diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..9741dd9a65 --- /dev/null +++ b/.gitignore @@ -0,0 +1,73 @@ + +antares-[0-9].[0-9]-* + +.*.sw[a-z] +*~ +CMakeCache.txt +Makefile +CMakeFiles +cmake_install.cmake +*.sln +*.rc +*.cbp +src/ipch +src/x64 +src/win32 +Debug +Release + +# Visual Studio +*.vcxproj +*.cproject +*.project +*.filters +*.user +*.suo +*.sdf +*.opensdf +*.dir +*.cbp +*.layout +src/.vs + +resources/examples* +resources/antares-open* +bin/debug +bin/release + +src/DartConfiguration.tcl +src/config.h + +# Yuni +src/ext/yuni/src/ProfileBuild.cmake +src/ext/yuni/src/yuni/config.h +src/ext/yuni/src/yuni/platform.h +src/ext/yuni/src/yuni/yuni.config.* +src/ext/yuni/src/yuni/yuni.version +src/ext/yuni/src/build +src/ext/yuni/src/samples +src/ext/yuni/docs/* +src/ext/yuni/nany/* +src/ext/yuni/src/compiler-flags-* + +src/ext/v8 + + +src/ui/simulator/resources/win32/manifest.antares-win32.manifest +src/ui/simulator/ProxyConnexionParameters.txt + +src/distrib/win32/version.nsh +src/distrib/win32/build.nsh +src/distrib/win32/rte-antares-*-installer-*.exe +src/distrib/win32/rte-antares-*-installer-*.zip +src/distrib/win32/readme.txt +src/distrib/win32/make-zip-from-installer.bat +src/distrib/unix/packages.sh +src/distrib/unix/rpm/pkginfo-* +src/distrib/unix/rpm/*.rpm +src/distrib/changelog.txt + +src/license/keys/rsakey2code +src/script/v8/libs/* +/src/antares.VC.VC.opendb +/src/antares.VC.db diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..a6ab4088d2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "src/ext/openssl"] + path = src/ext/openssl + url = https://github.com/openssl/openssl.git +[submodule "src/ext/wxwidgets"] + path = src/ext/wxwidgets + url = https://github.com/wxWidgets/wxWidgets.git +[submodule "src/ext/libcurl"] + path = src/ext/libcurl + url = https://github.com/curl/curl.git diff --git a/AUTHORS.txt b/AUTHORS.txt new file mode 100644 index 0000000000..9455919608 --- /dev/null +++ b/AUTHORS.txt @@ -0,0 +1,20 @@ +AUTHORS (from version/to version) +================================== + +Brahim Abbes V5 +Valentin Borozan V5 +Michael Boulade V4-V6 +Michel Doquet V1-V7 +Damien Gerard V2-V5 +Robert Gonzalez V2-V5 +Sylvain Marandon V6-V7 +Eric Momot V1-V2 +Papa Ndiaye V5-V7 +Guillaume Pierre V5-V7 +Frederique Verrier V1-V2 +Li Wu V5 + +Artwork +======= + +Damien Gérard \ No newline at end of file diff --git a/CERTIFICATE.txt b/CERTIFICATE.txt new file mode 100644 index 0000000000..0cdce0c397 --- /dev/null +++ b/CERTIFICATE.txt @@ -0,0 +1,37 @@ +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. \ No newline at end of file diff --git a/CONTRIBUTING.txt b/CONTRIBUTING.txt new file mode 100644 index 0000000000..877dded610 --- /dev/null +++ b/CONTRIBUTING.txt @@ -0,0 +1,30 @@ +Antares_Simulator is a project which, twelve years after its beginning, is still subject +to significant evolutions. + +To have an general idea of the progress that has been made so far, please read the NEWS file +at the root of this directory. + +To get of a wiew of the main directions in which further developments are currently oriented, +please read the ROADMAP file at the root of this directory. + +If you think about contributing to the Antares_Simulator project, your first move should be to get the source code. +There are two ways to achieve that: + +1) Clone the Antares_Simulator git repository available on GitHub : (link to be added) +2) Get an Antares_Simulator installer package available at https://antares-simulator@rte-france.com +and tick the box "copy source code" when installing the software. + +In the process followed to release the code of Antares_Simulator under Open Source, there are two important milestones: + +* In Summer 2018 , release of Antares_Simulator 6.0.0 : this first (ex-post) publication is meant to +provide a general access to the code, giving to everybody the ability to review as well as to (re)build the application. +At this stage, however, all will not be set yet regarding how to contribute (this file), conduct code, coding conventions, etc. + +* In Winter 2018/2019, release of Antares_Simulator 7.0.0 source. With this version will start the actual open +developement process, no more code being written in proprietary mode. This publication is meant to give the actual kick-off +for external contributions. + +* During the interim period (second half of 2018), developers who wish to join are welcome to examine +the code already published and to share their thoughts with the Antares_Simulator Team through one of +the email addresses that can be found at https://antares-simulator@rte-france.com + diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000000..a7adc9ffa5 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,725 @@ +Valid-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions + +License-Text: + +Copyright (C) 2007-2018 RTE +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3 of the License, or +(at your option) any later version. +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with this program; if not, see . + +In accordance with the terms of section 7 (7. Additional Terms.) of +the GNU GPL v3, the copyright holders of this Program add the +following Additional permissions: + +* If you modify this Program, or any covered work, by linking or +combining it with OpenSSL (or a modified version of that library), +containing parts covered by the terms of the OpenSSL license, the +copyright holders of this Program grant you additional permission to +convey the resulting work. Corresponding Source for a non-source form +of such a combination shall include the source code for the parts of +OpenSSL used as well as that of the covered work. + +* The terms "Sirius_Solver Substitution Exception" may be used to +refer to the permission defined in the next two paragraphs. + +In the following paragraph, the terms "Non-GPL code" mean code that is +covered neither by the GNU GPL v3 nor by a GPL-compatible license. +The terms "Eligible Interface" mean the interface definition files of +the Sirius_Solver library (version 6.0.0 or later). + +If you modify this Program, or any covered work, by linking it with +Non-GPL code through an Eligible Interface, the copyright holders of +this Program grant you additional conditional permission to convey the +resulting work. The condition to which the use of the permission is +subject to is that you replace the three characters between brackets +at the end of this line by the version identifiers of the Sirius_Solver +library whose eligible interface you make use of : [X.Y.Z] + +* As a special exception, the copyright holders of this Program give +you permission to link this software with libYuni library, licensed +under MPL-2.0, to produce an executable without applying the GNU GPL +v3 to the library itself providing that you meet the terms and +conditions of the MPL-2.0 on this library. + +### GNU GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +### Preamble + +The GNU General Public License is a free, copyleft license for +software and other kinds of works. + +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom +to share and change all versions of a program--to make sure it remains +free software for all its users. We, the Free Software Foundation, use +the GNU General Public License for most of our software; it applies +also to any other work released this way by its authors. You can apply +it to your programs, too. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + +To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you +have certain responsibilities if you distribute copies of the +software, or if you modify it: responsibilities to respect the freedom +of others. + +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + +Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + +For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + +Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the +manufacturer can do so. This is fundamentally incompatible with the +aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for +individuals to use, which is precisely where it is most unacceptable. +Therefore, we have designed this version of the GPL to prohibit the +practice for those products. If such problems arise substantially in +other domains, we stand ready to extend this provision to those +domains in future versions of the GPL, as needed to protect the +freedom of users. + +Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish +to avoid the special danger that patents applied to a free program +could make it effectively proprietary. To prevent this, the GPL +assures that patents cannot be used to render the program non-free. + +The precise terms and conditions for copying, distribution and +modification follow. + +### TERMS AND CONDITIONS + +#### 0. Definitions. + +"This License" refers to version 3 of the GNU General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds +of works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of +an exact copy. The resulting work is called a "modified version" of +the earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based +on the Program. + +To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user +through a computer network, with no transfer of a copy, is not +conveying. + +An interactive user interface displays "Appropriate Legal Notices" to +the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +#### 1. Source Code. + +The "source code" for a work means the preferred form of the work for +making modifications to it. "Object code" means any non-source form of +a work. + +A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can +regenerate automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same +work. + +#### 2. Basic Permissions. + +All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, +without conditions so long as your license otherwise remains in force. +You may convey covered works to others for the sole purpose of having +them make modifications exclusively for you, or provide you with +facilities for running those works, provided that you comply with the +terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for +you must do so exclusively on your behalf, under your direction and +control, on terms that prohibit them from making any copies of your +copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the +conditions stated below. Sublicensing is not allowed; section 10 makes +it unnecessary. + +#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such +circumvention is effected by exercising rights under this License with +respect to the covered work, and you disclaim any intention to limit +operation or modification of the work as a means of enforcing, against +the work's users, your or third parties' legal rights to forbid +circumvention of technological measures. + +#### 4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + +#### 5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these +conditions: + +- a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. +- b) The work must carry prominent notices stating that it is + released under this License and any conditions added under + section 7. This requirement modifies the requirement in section 4 + to "keep intact all notices". +- c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. +- d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + +A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + +#### 6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms of +sections 4 and 5, provided that you also convey the machine-readable +Corresponding Source under the terms of this License, in one of these +ways: + +- a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. +- b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the Corresponding + Source from a network server at no charge. +- c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. +- d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. +- e) Convey the object code using peer-to-peer transmission, + provided you inform other peers where the object code and + Corresponding Source of the work are being offered to the general + public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, +family, or household purposes, or (2) anything designed or sold for +incorporation into a dwelling. In determining whether a product is a +consumer product, doubtful cases shall be resolved in favor of +coverage. For a particular product received by a particular user, +"normally used" refers to a typical or common use of that class of +product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected +to use, the product. A product is a consumer product regardless of +whether the product has substantial commercial, industrial or +non-consumer uses, unless such uses represent the only significant +mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to +install and execute modified versions of a covered work in that User +Product from a modified version of its Corresponding Source. The +information must suffice to ensure that the continued functioning of +the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or +updates for a work that has been modified or installed by the +recipient, or for the User Product in which it has been modified or +installed. Access to a network may be denied when the modification +itself materially and adversely affects the operation of the network +or violates the rules and protocols for communication across the +network. + +Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + +#### 7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders +of that material) supplement the terms of this License with terms: + +- a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or +- b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or +- c) Prohibiting misrepresentation of the origin of that material, + or requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or +- d) Limiting the use for publicity purposes of names of licensors + or authors of the material; or +- e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or +- f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions + of it) with contractual assumptions of liability to the recipient, + for any liability that these contractual assumptions directly + impose on those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; the +above requirements apply either way. + +#### 8. Termination. + +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + +#### 9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run +a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + +#### 10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + +#### 11. Patents. + +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned +or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + +If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + +A patent license is "discriminatory" if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on +the non-exercise of one or more of the rights that are specifically +granted under this License. You may not convey a covered work if you +are a party to an arrangement with a third party that is in the +business of distributing software, under which you make payment to the +third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties +who would receive the covered work from you, a discriminatory patent +license (a) in connection with copies of the covered work conveyed by +you (or copies made from those copies), or (b) primarily for and in +connection with specific products or compilations that contain the +covered work, unless you entered into that arrangement, or that patent +license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + +#### 12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under +this License and any other pertinent obligations, then as a +consequence you may not convey it at all. For example, if you agree to +terms that obligate you to collect a royalty for further conveying +from those to whom you convey the Program, the only way you could +satisfy both those terms and this License would be to refrain entirely +from conveying the Program. + +#### 13. Use with the GNU Affero General Public License. + +Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + +#### 14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions +of the GNU General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in +detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies that a certain numbered version of the GNU General Public +License "or any later version" applies to it, you have the option of +following the terms and conditions either of that numbered version or +of any later version published by the Free Software Foundation. If the +Program does not specify a version number of the GNU General Public +License, you may choose any version ever published by the Free +Software Foundation. + +If the Program specifies that a proxy can decide which future versions +of the GNU General Public License can be used, that proxy's public +statement of acceptance of a version permanently authorizes you to +choose that version for the Program. + +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + +#### 15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + +#### 16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR +CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT +NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM +TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER +PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +#### 17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + +### How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively state +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper +mail. + +If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands \`show w' and \`show c' should show the +appropriate parts of the General Public License. Of course, your +program's commands might be different; for a GUI interface, you would +use an "about box". + +You should also get your employer (if you work as a programmer) or +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. For more information on this, and how to apply and follow +the GNU GPL, see . + +The GNU General Public License does not permit incorporating your +program into proprietary programs. If your program is a subroutine +library, you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +GNU Lesser General Public License instead of this License. But first, +please read . \ No newline at end of file diff --git a/INSTALL.txt b/INSTALL.txt new file mode 100644 index 0000000000..aad1aa8f4a --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1,336 @@ +THIS FILE CONTAINS DETAILED INSTRUCTIONS ON HOW TO BUILD BINARIES +----------------------------------------------------------------- +IDENTICAL TO THOSE DISTRIBUTED IN RTE'S PACKAGES +------------------------------------------------ + + +1. Environment +============== + +Antares_Simulator is a cross-platform project using components compatible +with many 32 bits and 64 bits OS (Windows, Linux, Unix) + +The source distribution accompanying this file has been tested for successful build on: + +Windows 7 +Windows 10 +Linux CentOS 6 +RHEL 7.3 + +with compilers MSVC 19.00 & GCC 4.8.1 + +Note on End-Of-Line convention +------------------------------ +If the origin of the source folder accompanying this file is a check-out +from a Git repository, end-of-line should be in the style of the local OS + +If the source folder was distributed along with the binary form of the code +within an Antares_Simulator installer package, the end-of-line style is that of +the OS the package is designed for + +To build on Windows system, please change end-of-line style to appropriate standard +Note that Visual Studio may carry out auto-reformating. + +1.1 OS-dependent resources +========================== + +Windows : Visual Studio 2015 (or later) +Linux : GCC >= 4.8.1 (required for C++11) + + +1.2 Tools +========= + +Git (source versioning) +Cmake (>=3.9.0) (Generation of Visual studio solutions, Linux and Unix Makefiles) +Perl strawberry (>=5.26) (Windows pre-compilation of OpenSSL) + + +1.3 External Dependencies +========================= + +This section describes compiling procedures for the third-part Open source libraries used by ANTARES +Hereafter the environment variable ${ANTARES} points at the Antares' repository root folder. + +To begin with , clone the whole Antares repository and checkout the branch bearing the tag +of the relevant distributed version ( >=6.0.0) + +Four external dependencies are integrated as Git submodules: + +* src/ext/openssl - OpenSSL 1.1.0 +* src/ext/libcurl - Curl 7.51.0 +* src/ext/wxwidgets - wxWidgets 3.0.2 +* src/ext/Sirius_Solver - Sirius_Solver 6.0.0 + +After a pull on Antares repository , submodules should be already properly initialized + + +1.3.1 Compiling OpenSSL with Visual Studio - 64 bits solution +============================================================= + +Requirements : +* Visual Studio - 2015 Update 2 +* Perl - Strawberry Perl + +Warning : make sure that the perl version available is Strawberry perl and not one shipped along with Git. +If needed, remove temporarily "...\Git\usr\bin" from the environment variables (and put it back afterwards) + +Notice: launching nmake requires the execution of "vcvars64.bat" (as described below), + which updates environment variables for the current session. + +Open a command line console and run: + + +"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" +cd ${ANTARES}\src\ext\openssl +perl Configure VC-WIN64A --prefix=vc-release-x86_64 no-shared +ms\do_win64a +nmake -f ms\nt.mak +nmake -f ms\nt.mak install + + +1.3.2 Compiling OpenSSL with Visual Studio - 32 bits solution +============================================================= + +Requirements : +* Visual Studio - 2015 Update 2 +* Perl - Strawberry Perl + +Warning : make sure that the perl version available is Strawberry perl and not one shipped along with Git. +If needed, remove temporarily "...\Git\usr\bin" from the environment variables (and put it back afterwards) + +Notice: launching nmake requires the execution of "vcvars64.bat" (as descibed below), +which updates environment variables for the current session. + +Open a command line console and run: + +"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat" +cd ${ANTARES}\src\ext\openssl +perl Configure VC-WIN32 no-asm --prefix=vc-release-x86 no-shared +ms\do_ms +nmake -f ms\nt.mak +nmake -f ms\nt.mak install + + + +1.3.3 Compiling OpenSSL for Linux +================================= + +* Set the compiler to use if the default one is not compatible with C++11 +* For instance, to use gcc-4.8, use : + + +export CC=/usr/local/gcc/4.8/bin/gcc-4.8 +export CXX=/usr/local/gcc/4.8/bin/g++-4.8 + +cd ${ANTARES} +cd src/ext +cd openssl +./config --prefix=$PWD/release-x86_64 no-asm no-mdc2 no-rc5 no-shared +make depend +make +make install + +1.4.1 Compiling Curl for Windows 64 bits +======================================== + +Open a command line console and run: + +"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" +cd ${ANTARES}\src\ext\libcurl\winbuild +nmake /f Makefile.vc mode=static VC=14 WITH_SSL=static WITH_DEVEL=../../openssl/vc-release-x86_64 ENABLE_SSPI=no ENABLE_IDN=no ENABLE_WINSSL=no GEN_PDB=no DEBUG=no MACHINE=x64 + + +1.4.2 Compiling Curl for Windows 32 bits +======================================== + +Open a command line console and run: + +"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat" +cd ${ANTARES}\src\ext\libcurl\winbuild +nmake /f Makefile.vc mode=static VC=14 WITH_SSL=static WITH_DEVEL=../../openssl/vc-release-x86 ENABLE_SSPI=no ENABLE_IDN=no ENABLE_WINSSL=no GEN_PDB=no DEBUG=no MACHINE=x86 + + +1.4.3 Compiling Curl for Linux +============================== + +* Set the compiler to use if the default one is not compatible with C++11 +* For instance, to use gcc-4.8, use : + + +export CC=/usr/local/gcc/4.8/bin/gcc-4.8 +export CXX=/usr/local/gcc/4.8/bin/g++-4.8 + +cd ${ANTARES}/src +ANTARES_SRC=`pwd` +cd ext/libcurl +./buildconf +LIBS="-ldl -lpthread" ./configure --disable-shared --with-ssl="$ANTARES_SRC/ext/openssl/release-x86_64" +make + + +1.5.1 Compiling WxWidget for Windows 32 or 64 bits +================================================== + +Copy file "setup0.h" from ${ANTARES}\src\ext\wxwidgets\include\wx\msw\ +to: ${ANTARES}\src\ext\wxwidgets\include\wx\msw\setup.h. + +In the file ${ANTARES}\src\ext\wxwidgets\src\tiff\libtiff\tif_config.h +Replace in line 367: #define snprintf _snprintf +by : + +#if (defined(_MSC_VER) && (_MSC_VER < 1900)) + #define snprintf _snprintf +#endif + +Locate the folder : ${ANTARES}\src\ext\wxwidgets\build\msw +open "wx_vc12.sln" (double-click to launch Visual Studio) + +* If needed,update compilation tools as suggested when opening Visual Studio + Explanation: in Visual Studio C++, the WxWidget solution is a VS 12.0 one. + With VS 2015 (version14.0), compilation tools must be upgraded. This is automatically suggested by VS 2015 +* Configure compilation parameters (Debug/Release/x64/Win32) + +* Compile + +1.5.2 Compiling WxWidget for Linux +================================== + + +* Set the compiler to use if the default one is not compatible with C++11 +* For instance, to use gcc-4.8, use : + + +export CC=/usr/local/gcc/4.8/bin/gcc-4.8 +export CXX=/usr/local/gcc/4.8/bin/g++-4.8 + +* run the compiler : + +cd ${ANTARES}/src +#wxWidgets +cd ext/wxwidgets +mkdir build_gtk +cd build_gtk +../configure --with-gtk --disable-shared +make + + +2. Building Antares Solution for Windows +======================================== + + +2.1 Preliminary step : get a clean environment +---------------------------------------------- + +If required, do not hesitate to clean up your local repository either: + +* before cloning the sources +* between successive 64 bits and 32 bits compilation + +Cleaning the Git repository can be achieved by runing the following command, which resets the local +repository to zero (no cached or temporary files remaining): + +git clean -xdf # + +If the version tag (X.Y.z) needs to be updated, this should be made in the file : + + @src/CMakeLists.txt@ : + + +# Version +set(ANTARES_VERSION_HI 5) # numero majeur X +set(ANTARES_VERSION_LO 0) # numero mineur Y +set(ANTARES_VERSION_REVISION 0) # numero de rĂ©vision z + + +2.2 Compiling for Windows : generation of Visual Studio solution +---------------------------------------------------------------- + +Note : generation should not be attempted before setting up the version tag defined in CMakeLists.txt + +cd ${ANTARES}/src + +2.2.1 32 bits version +--------------------- + +cmake -G "Visual Studio 10" -DCMAKE_BUILD_TYPE=release . + +or + +cmake -G "Visual Studio 14 2015" -DCMAKE_BUILD_TYPE=release . + + +2.2.2 64 bits version +--------------------- + +cmake -G "Visual Studio 10 Win64" -DCMAKE_BUILD_TYPE=release . + + +or + +cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_BUILD_TYPE=release . + +2.3 Compiling for Windows : Running the compiler +------------------------------------------------ + + +# Open the solution @src/antares.sln@ with Visual Studio 10 or Visual Studio 15 +# Choose the target "Release" +# Generate the solution + +3. Building Antares for Linux +============================= + +3.1 Preliminary step : get a clean environment +---------------------------------------------- + +Do not hesitate to clean up your local repository before cloning the sources + +Cleaning the Git repository can be achieved by runing the following command, which resets the local +repository to zero (no cached or temporary files remaining): + +git clean -xdf # + +If the version tag (X.Y.z) needs to be updated, this should be made in the file : + + @src/CMakeLists.txt@ : + + +# Version +set(ANTARES_VERSION_HI 5) # major index X +set(ANTARES_VERSION_LO 0) # minor index Y +set(ANTARES_VERSION_REVISION 0) # revision number z + +3.2 Compiling for Linux +----------------------- + +3.2.1 Set the path +------------------ + +$ cd ${ANTARES} + +* Set the compiler to use if the default one is not compatible with C++11 +* For instance, to use gcc-4.8, use : + +export CC=/usr/local/gcc/4.8/bin/gcc-4.8 +export CXX=/usr/local/gcc/4.8/bin/g++-4.8 + +3.2.2 Generate the makefiles +---------------------------- + +In debug mode: +$ cmake . + +Or in release mode: +$ cmake . -DCMAKE_BUILD_TYPE=release + +3.2.3 Compile Antares +--------------------- + +$ make + +Tips : If you have more than one processor/core, you can run more than one job : + $ make -j X + where X is the number of jobs to run simultaneously. + +Tips : `make VERBOSE=1` to see the real commands \ No newline at end of file diff --git a/NEWS.txt b/NEWS.txt new file mode 100644 index 0000000000..5a407d99e4 --- /dev/null +++ b/NEWS.txt @@ -0,0 +1,690 @@ + +Antares_Simulator Changelog +=========================== + + +v6.0.0 (04/2017) +---------------- + +### Features + + - GUI: A new interface makes it possible to define several views (maps) of + the Power System modelled in an Antares study. These maps are meant to give + the user the ability to set different layouts in which each Antares Area + or Link can be either shown or remain hidden. Accordingly, all input and + output data windows can now adapt the information displayed so as to match + exactly the content of any given map. Copy/Paste functions have been + extended so as to work between different maps of different studies opened + in multiple Antares sessions + + - Simulation: Introduction of a flexible multi-threaded mode for the processing + of heavy problems: Antares “Monte-Carlo years” can be be distributed on a + number of CPU cores freely set by the user. This parameter appears as a new + tunable item of the “advanced parameters” list attached to any Antares Study. + Five values are available in the [1, N] interval, N being the number of CPU + cores of the machine (virtual or physical) Antares is run on + + - License control through the internet: a new system has been developed for + accommodating situations where users wish to operate Antares on a large + fleet of machines among which a limited set of commercial license tokens + can float freely + + - Data organizer: Antares studies often include a great number of files of + all sizes, which may take long to process when multiple copies are needed. + Likewise, the management of the HDD space required for regular storage of + all of the studies involved in a complex study workflow may turn out to be + a demanding and heavy task. To save both time and hardware resources, the + Antares Data Organizer, now provided as a companion tool to the Antares + Simulator, brings the ability to schedule basic data management tasks + such as study archiving/expansion (use of a specific compressed format), + copy to backup folders, registering of studies and archives in catalogues. + + +v5.0.9-SE (04/2017) +---------------- + +### Bug fixes + + - Random noises on thermal clusters costs now include the zero-cost + "must-run" clusters (as a consequence, noises assumptions do not vary + with the cluster status) + + - Fixing an initialization issue that could sporadically affect the + minimum number of committed thermal units (+1 or -1 deviation, + "accurate" mode only) + +v5.0.7-SE (04/2017) +---------------- + +### Features + + - License control : management of SSL certificates encrypted through SHA-256 algorithm + + +v5.0.7 (12/2016) +---------------- + +### Bug fixes + + - Fixing a packaging error + + +v5.0.6 (12/2016) +---------------- + +### Bug fixes + + - Results processing: For full "must-run" thermal clusters, the NODU variable + could be wrongly assessed in the "accurate" unit commitment simulation mode + + - GUI: when the scenario builder feature is active, saving right after deleting + a thermal cluster could result in a partial dataset corruption (references to + the deleted object were kept alive in the scenario builder context) + + +### Features + + - Unsupplied energy control: if the actual economic optimization requires it, load + shedding is now allowed to occur in areas where the available thermal generation + is higher than the local demand (e.g. if local VOLL < local thermal costs) + + - Linear solver, hot starting of weekly problems: in the "fast" unit commitment + mode, optimal bases are flushed at the beginning of each Monte-Carlo year. This + comes as a pre-requirement for the next versions of Antares, which will be + fully multi-threaded + + - Simulation results: code segments processing all variables attached to spatial + aggregates, and the variable representing the number of running thermal units + on the first hour of the year, were re-written to be compatible with the next + versions of Antares, which will be fully multi-threaded + + + +v5.0.5 (08/2016) +---------------- + +### Bug fixes + + - No-Load Heat costs and Start-up costs: in the "fast" unit commitment options, + the result was slightly below the actual optimal possible cost for some + datasets (i.e. datasets in which the thermal cluster coming last in alphabetic + order had a minimum stable power equal to zero). + + - Spilled energy control: the three parameters defining how energy in excess should + be split between the different possible sources when there is a choice to make + can work properly again (feature inhibited in previous 5.0.x versions) + + +### Features + + - License control throughout the internet: all combinations of UTF8 characters can + now be used within proxy ids and passwords + + - Economic optimization: in an area where the amount of available thermal power + exceeds that of load, the fact that the demand should necessarily be served + is locally expressed as a constraint of the optimization problem (LOLE=0) + + +v5.0.4 (05/2016) +---------------- + +### Bug fixes + + - Errors occured on loading the "min gen modulation" time-series of thermal clusters + +### Features + + - Better estimate of the number of thermal units dispatched in "fast" unit commitment mode + - Nodal Marginal Prices and Marginal yield on interconnections are now available in + "accurate" unit commitment mode + - Binding constraints including offset parameters: unbounded positive or + negative values can be used for all classes of constraints (hourly, daily, weekly) + + +v5.0.3 (05/2016) +---------------- + +### Bug fixes + + - Crashes occured when the "full must-run status" parameter was set on + "true" for thermal clusters + + +v5.0.2 (04/2016) +---------------- + +### Bug fixes + + - Removed debug information that should not be displayed in release mode + +### Features + + - The optimization criterion used to assess the hydro energies to generate throughout + each month incorporates heavier penalization terms for the 12 deviations from the + theoretical monthly targets (formerly, only the largest deviation was penalized). + + +v5.0.1 (04/2016) +---------------- + +### Bug fixes + + - Adequacy mode: fixed a memory allocation bug that forced the post-simulation + output files processing to be interrupted + + - In the previous version, additional logs were added. That could lower the simulation + performances in some cases. This problem is now solved. + + +v5.0.0 (03/2016) +---------------- + +### Bug fixes + + - GUI, system map: copy /paste of binding constraints could alter the activity status or + the names of the duplicated binding constraints in some instances + + - GUI, system map: some conflicts in copy/paste actions were not always properly raised + (e.g. attempt to copy three nodes and paste them on two other nodes) + + - Thermal clusters: Improved checking of time-series generation parameters (improper use of a + nominal capacity modulation factor lower than the minimum stable power is no longer possible) + + - Thermal clusters: Improved checking of ready-made time-series. If the user-chosen time-series + are not consistent with the parameters set in the GUI, warnings are issued in log files + + - Output , LOLD variable: in some instances, the values assessed in "economic" simulation mode and in + "adequacy" simulation mode could slightly differ because of sporadic rounding side-effects. + rounding convention is now set uniformly to : 0 < X < 0.5 -> (X=0) + + - Output, MISC.NDG and PSP variable: values were not properly edited for the specific category + "geographic districts, "year-by-year results" + + - Output, OV. COST, OP. COST, NP. COST variables: values were not properly edited for the last + hour of the last day of the simulation + + - Output, File comparison functions: calendar marks were not properly displayed in some views + + - Output, File comparison functions: "Max" operator has been added + + +### Features + + - Optimization: introduction of a new unit-commitment mode based on a MILP approach slower but more + accurate than the former one. An option lets the user choose which mode should be used (fast/accurate) + + - Optimization: in "accurate" unit-commitment mode, incorporation of thermal start-up costs and + no-load heat costs within the global objective function to minimize. In "fast" unit-commitment + mode, start-up costs and no-load heat costs are minimized independently from the main objective + + - Optimization: in both unit-commitment modes, improvement of the inter-weekly start-up strategies + (seamless reformulation of the optimization results obtained beforehand) + + - Thermal clusters: definition of separate minimum up/down durations to be used for unit-commitment + + - Thermal clusters: definition of a minimum amount of power (hourly time-series) to be generated + by the units of the cluster, regardless of economic considerations (partial must-run commitment) + + - Thermal clusters: start-up cost can now be set from -5000000 to 5000000 (was from -50000 to 50000) + + - Binding constraints: introduction of new "offset" parameters which make it possible to define + constraints whose terms can refer to different times (e.g. 2 X(t) - 1.5 Y(t-4) + 3 Z(t+1) <10) + + - Benchmarking: so as to allow transparent comparisons with other software, the user may demand + that all optimization problems solved by Antares be printed in a standardized "mps" format + along with the values of the optimized criterion. + + - GUI, System map : new button available in the tool bar for centring the map on a (x,y) location + + - GUI, System map : new button available in the tool bar for map trimming around used space + + - Output: In synthetic Monte-Carlo results,year-by-year results and cluster-by-cluster results, + Addition of a field "Number of dispatched units" (NODU) + + + +v4.5.4 (03/2015) +---------------- + +### Bug fixes + + - License checking: internet proxys for which no login and/or password have been + defined can now be used + + - Upgrade to 4.5 format of datasets edited in 4.4 format or lower, in which the "scenario builder" + feature was activated: the conversion to 4.5 format could fail sometimes. + +v4.5.3 (02/2015) +---------------- + +### Features + + - Start-up and fixed thermal costs: the interpretation of the unit-commitment strategy + (starting-up and shutting-down times of each thermal unit) includes the explicit + minimization of the total sum of start-up costs and fixed costs (in previous versions, + units were called on as late as possible and called off as soon as possible) + + + - Various improvements in the linear solver yielding some speed increase in hard cases + + + - Control of license validity through the internet (setting up of a dedicated server) + + +### Bug fixes + + - Scenario builder: indices not subject to random draws could be mixed up in areas + including both "must-run" units and "regular" units (bug circumscribed to the thermal + time-series section) + + - Spillage management, when numerous binding constraints are active: an excessive leeway + could be observed regarding the level of hydro power allowed to be curtailed + +v4.5.2 (06/2014) +---------------- + +### Bug fixes + + - In the previous version, the average values of interconnection-related variables were multiplied by two + and this error was propagated to the standard deviation of the same variables + +v4.5.1 (06/2014) +---------------- + +### Features + + - Start-up and fixed thermal costs: the contribution of each thermal cluster to the operating + cost is now explicitly displayed in the results (field : "non proportional cost") + + + - Load time-series : negative values are now authorized + + + + +### Bug fixes + + - Creation of a thermal cluster : the default value of the NPOMAX parameter is set to 100 + + + - Hydro energy spatial allocation matrix : values are displayed more clearly in the GUI + + + - Copy/paste of nodes : the field "spread on unsupplied energy cost" was not pasted + + +v4.5.0 (04/2014) +---------------- + +### Features + + - Simplex solver: acceleration regarding the control of the admissibility of the solution + in the dual stages. This brings a significant improvement of the calculation time for + large problems in which the relative scale of system costs is very wide + + + - Identical upper and lower bounds have been set for the absolute values of all + non-zero system costs ( max = 5 10^4 €/MWh ; min = 5 10^-3 €/MWh) + + +### Bug fixes + + - Hydro Time-series generation : the GUI did not react properly when forbidden + values (negative) were seized for energy expectation and/or standard deviation + + + - Unit commitment of thermal plants: the time of the first activation of a plant + within a week was not fully optimized + + +v4.4.1 (05/2013) +---------------- + +### Bug fixes + + - Creation of a new binding constraint: the operation needed to be confirmed twice + (double click on "create button") and the study had to be "saved as" and reloaded before + proceeding further. + + - Time-series analyzer : due to round-off errors, spatial correlation of 100 % + (perfectly identical sets of time-series in different locations) could sometimes + be casted to 99%. Exact 100% correlations are now properly displayed. + + + + +v4.4.0 (04/2013) +---------------- + +### Features + + - Antares licenses can be either static or floating. Floating tokens are managed and + distributed by the Flexnet product, version 11.9. + + - Thermal plants time-series generator : availability parameters (outage rates and duration) + corresponding to a Mean Time Between Failure (MTBF) < 1 day are now allowed. Though unusual, + such sets of parameters may prove useful when it comes to modelling specific situations + + - Thermal plants time-series generator : it is possible to model the duration of each kind + of outages as 365-day random arrays instead of 365-day constant arrays. Two parameters + are available for the description of the probability distribution function of each component. + A first parameter allows to set the variable law to either "uniform" or "geometric". + A second parameter allows to set the ratio of the variable standard deviation to + its expectation to a particular value + + - Thermal plants time-series generator : The planned outage process is now committed to meet a + set of constraints defined by two 365-day arrays (PO Min Nb, PO Max Nb). For every day of + each Monte-Carlo year, the actual number of overhauls is kept within the [Min,Max] interval, + the exact value being determined by regular random draws based on outage rates and durations + + - As a consequence of the introduction of these new features, Monte-Carlo time-series + of available thermal power generated with Antares 4.4 may differ from those generated with + previous versions. Though differences may be observed draw by draw, the statistical + properties of the generated time-series are strictly preserved when datasets are identical. + + - Hydro storage optimization : when the maximum available power of a given day is not high + enough to allow the full use of the daily hydro storage energy credit, the energy in excess + is levelled on the other days of the month with a flatter pattern. + + +### Bug fixes + + - On creation of a new link, the transmission capacity status parameter is set + to `Use transmission capacities` instead of `Set to null`. + + + +v4.3.7 (02/2013) +---------------- + +### Features + + - Performance improvements for graphical display of large tables + + +### Bug fixes + + - The binding constraint data might not be written properly in some cases + when the constraint was renamed. + + + +V4.3.6 (12/2012) +---------------- + +### Bug fixes + + - Windows only: fixed potential crash which could happen when exiting + a simulation in adequacy mode with import of generated time-series + + - Windows only: improved free disk space assessment, which now takes into + consideration user- and folder-related quotas + + +V4.3.5 (10/2012) +---------------- + +### Features + + - The calendar field "year" is now available in the simulation main screen + (allows not only simulations from JAN to DEC but also from OCT to SEP, etc.) + + - The attribute "Leap year" is now available in the simulation main screen + + - The attribute "Week" is now available in the main simulation screen + (weekly results may be defined not only from MON to SUN but also from SAT to FRI,etc.) + + - Time-series screens: a new function is available for hourly and daily time-series + (shift rows until #date#) + + - Linear solver: new version slightly more accurate than the previous one. + Note that when a daily or weekly optimization has multiple equally optimal solutions, + the ultimate choice may differ from that of the previous version + + +### Bug fixes + + - Reference numbers of the time-series used in the course of a simulation: + When the simulation is based on a user-defined scenario (building mode: custom) + and when a printout of the reference numbers of the time-series used in the simulation + is asked for (MC scenarios: true), the numbers printed for thermal clusters running + under the "must-run" status were wrong + + - Interconnection results, marginal costs: + For a congested interconnection whose transmission capacities are not symmetric, + and in presence of hurdle costs, a zero could sometimes be delivered instead of + the actually expected value + + - Districts: when the Monte-Carlo synthesis edition is skipped, the results regarding + districts were not accessible via the output viewer. + + + +V4.2.6 (07/2012) +---------------- + +### Features + + - The field "MAX MRG" (last of the nodal results) is now available in the output files + + - The Monte-Carlo synthesis edition can be skipped when year-by-year results are asked for + + +### Bug fixes + + - Binding constraints: in the filter available for the weight matrix, removal of + redundant options + + - Copy/Paste nodes on the general map: "print status" parameters can now be copied like + any other data + + - Upgrade of studies in 3.8 format: negative hurdle costs were not correctly transposed + + - Thermal plants time-series generator: outages lasting N days, starting on day D, were + considered as outages lasting N days starting on D+1 (corrected by removal of the + one-day shift) + + - Advanced parameters, option "shave peaks" used along with the "weekly" simplex range: + the maximum intra-daily hydro storage limit on power could occasionally be overcome during + the unsupplied energy levelling process (corrected by a slight lessening of the authorized + levelling) + + + + +v4.1.0 (06/2012) +---------------- + +### Features + + - Hydro storage energy management : each nodal policy of use can be tuned so as to + accommodate simultaneously the net load of several nodes + + - Hydro storage energy modelling : monthly time-series of inflows and reference trajectories + for reservoir levels can be used instead of monthly time-series of generated energies. + + - Load shedding strategies : when unsupplied energy is unavoidable, a choice is now possible + between two policies : minimize the duration of sheddings or "shave" the load curve. + + - When multiple mathematically equivalent solutions exist a the first order for the + economic optimization problem, a choice can be made at the second order between three + ramping strategies + + + + +v3.8.0 (12/2011) +---------------- + +### Features + + - The simulation mode `Adequacy` is renamed `Draft`. + + - A new simulation mode `Adequacy` is available. In this mode, all thermal plants are + considered as must-run zero-cost units. + + - New possibilities are given regarding the filtering of simulation results (selection + of nodes, of interconnections, etc.) + + - Automatic spatial aggregation of results is possible through the use of the new + "district" object (a district is a sort of macro-node gathering several regions) + + - Nodal costs of unsupplied energy and of spilled energy : a small additive stochastic + noise around the reference values can be introduced to help discriminate between + theoretically equivalent solutions + + + +V3.7.4 (08/2011) +---------------- + +### Features + + - New version of the dual simplex engine (speed is about twice that of 3.6 version) + + - Economic optimizations now encompass a full week (168 hours) span. Traditional + day-long optimizations can still be carried out (ad hoc "preference" parameter) + + - Binding constraints can be defined at the weekly scale in addition to the + daily and hourly scales + + - Several other "optimization preferences" are made available to allow the quick examination + of variants used in sensitivity analyses + + - A new graphic interface is available for the consultation of all simulation results + (except those obtained in draft mode) + + - Extraction of data regarding any given variable from the whole Monte-Carlo year-by-year + set of results is now possible + + - New variables are introduced in the economic output files : the overall available dispatchable + thermal generation (AVL DTG) and the thermal margin (DTG MRG = AVL DTG - dispatched power) + + + + +V3.6.4 (04/2011) +---------------- + +### Features + + - The "scenario builder" is now available. With this builder it is possible to define + precisely the simulation context (for any given year, random numbers drawn for each + kind of time-series can be replaced by user-defined numbers). This feature allows + simulations to be carried out in a versatile "What If" mode. + + + + + +V3.5.3 (03/2011) +---------------- + +### Features + + - Addition of the fuel category "lignite" to the regular options available + for the description of thermal plants. + + - Improvement of the presentation of the 365-day arrays "market bid modulation" + and "marginal cost modulation". + + - Automatic processing of the inter-monthly & inter-regional hydro correlation hydro + energy matrix to meet the feasibility constraints (the matrix has to be positive + semi-definite). User should check in the simulation log file that no warning such as : + "info : hydro correlation not positive semi-definite : shrink by factor x " appears. + + + + +V3.4.4 (02/2011) +---------------- + +### Features + + - The names of nodes, thermal clusters and binding constraints can be extended to + 128 characters. Authorized characters are : `a-z, A-Z,0-9,-,_, space` + + + + +v3.4.3 (10/2010) +---------------- + +### Features + + - Two calculations modes are now available (in the "run" window): + + "regular": the software tries to hold all simulation data in RAM + this mode is faster than the second one when datasets are small but + can get dramatically slow when RAM limits are close + + "swap" : a dedicated memory management module loads in RAM amounts + of data as small as possible. This mode should be prefered to the + other when datasets are large. + + Note that in "regular" mode, the maximum amount of data loaded is + limited by the OS to 2 Go on 32-bit machines, regardless of the + memory installed. The integrality of installed memory can be used + on 64-bit machines. + + - A new module (time-series analyzer) is available to help set the + parameters of the stochastic time-series generators for wind power, + solar power and load. The analyzer determines, on sets of historical + 8760-hour time-series the relevant parameters for different kinds of + random laws (uniform, normal,Weibull, Beta, Gamma), along with a + description of the auto-correlation dynamic (two parameters) + and a full spatial correlation matrix + + + + + +v3.3.2 (07/2010) +---------------- + +### Features + + - Improvement of the wind power time-series generator (faster calculations) + + - Introduction of new stochastic time-series generators for + solar power and load + + - Introduction of an explicit modelling of wind-to-power curves. + As a consequence, wind power time-series can now be generated + either through a direct approach (by analysis of historical + time-series of power) or through an indirect (more physical) + approach, based on the analysis of historical time-series of + wind speed + + - Introduction of a new 8760-hour power array for each node, + representing the day-ahead reserve that should be made available + (either on-site or at distance) to face last-minute incidents + and/or forecasts errors. + + - Introduction of so-called hurdles costs on interconnection. + + + + +v3.1.0 (01/2010) +---------------- + +### Features + + - Breakdown of monthly hydro storage energy credits in daily credits: + The pilot curve is now the net load (i.e. load - all must-run generation) + instead of the gross load + + - New functionalities available for datasets management (stucy cleaner, + Log file wiewer) + + - New info is given for simulation context (available & required amounts + of RAM & HDD space) + + + +From V1 to V2 (all versions) +---------------------------- + + - Refer to project development archives (TRAC thread) + diff --git a/README.txt b/README.txt new file mode 100644 index 0000000000..e402783339 --- /dev/null +++ b/README.txt @@ -0,0 +1,55 @@ +README for Antares_Simulator +=========================== + +Antares_Simulator is an open source power system simulator meant to be +used by anybody placing value in quantifying the adequacy or the +economic performance of interconnected power systems, at short or +remote time horizons: + +Transmission system Operators, Power Producers, Regulators, Academics, +Consultants, NGO and all others actors concerned by energy policy issues +are welcome to use the software. + +The Antares_Simulator project was initiated by RTE (French Electricity +Transmission system Operator) in 2007. It was developed from the start +as a cross-platform application (Windows, GNU/Linux ,Unix). + +Until 2018 it was distributed under the terms of a proprietary license. + +In May 2018 RTE decided to relicense the project under the GPLv3 license. + +Links: +====== + +The Antares web site. . . . https://antares.rte-france.com/ +Support . . . . . . . . . . To do +Forums . . . . . . . . . . To do +Wiki . . . . . . . . . . . To do +Bugtracker . . . . . . . . To do +The RTE web site . . . . . http://www.rte-france.com/ + + +Source Code Content: +=================== + +AUTHORS - Antares_Simulator authors. +CERTIFICATE - A standard DCO that has to be signed by every contributor +CONTRIBUTING - How to submit patches and discuss about code evolutions +COPYING - The GPL v3 license. +INSTALL - Installation and building instructions. +NEWS - Important modifications between the releases. +README - This file. +ROADMAP - Main orientations for further developements +THANKS - Attribution notices for external libraries and contributors. +bin/ - Antares_Simulator binaries. +doc/ - Miscellaneous documentation. +resources/ - Free sample data sets. +src/analyzer/ - source code for the statistical analysis of historical time-series. +src/cmake/ - files for initializing a solution ready for compilation. +src/distrib/ - system redistributable libraries Win(x64,x86),unix. +src/ext/ - third party libraries used by Antares_Simulator: libCurl, OpenSSL,Wxwidgets,libYuni, Sirius_Solver. +src/libs/ - miscellaneous Antares_Simulator libraries. +src/internet/ - web access (check for updates, usage metrics, data exchange). +src/simulator/ - Time-series generation, Monte-Carlo simulation and weekly optimization modelling. +src/tools/ - miscellaneous tools for dataset management. +src/ui/ - Graphic user interface. \ No newline at end of file diff --git a/ROADMAP.txt b/ROADMAP.txt new file mode 100644 index 0000000000..fb1c57a391 --- /dev/null +++ b/ROADMAP.txt @@ -0,0 +1,45 @@ +This file describes the development roadmap leading from Antares_Simulator 6.0.0 +(released: Summer 2018) to Antares_Simulator 7.0.0 (expected: winter 2018/2019). + +a) Enhancement of the perimeter of binding constraints: + +Since from their first apparition in Antares_Simulator, so-called +binding constraints have been defined as arbitrary linear constraints +on flow variables. Since Antares_Simulator makes it possible to define +completely artificial flow variables, the binding constraint editor is +quite versatile and this property has for long been intensively and +successfully used to build up handy auxiliary sub-problems +(e.g reservoir level equations of PSP) + +However, a significant improvement will be brought by extending the +binding constraint domain to the output from dispatchable plants. +Alike flow variables, generation variables will include physical +ones as well as completely artificial ones, should the need for +them arise in the course of setting up a specific power system model. + +b) Automation of the definition of "DC approximation" load flow +constraints: + +Using conventional binding constraints defined on a cycle basis of the +graph formed by the AC components of the power system is, in +Antares_Simulator, a well established practice for enforcing Kirchhoff's +second law on power flows in the classical "DC approximation". A +suitable tuning of the RHS of these constraints already gives, in +addition, the ability to model the operation of PSTs or to reproduce +the "natural" loop flows that may be have to be taken into account on +a grid whose geography has been simplified. + +However, the manual edition of all of these constraints may represent +a heavy task, even with the assistance of partially automated scripts. +For this reason the roadmap to Antares_Simulator 7.0.0 includes the +development of a new integrated "binding constraints generator" that +will automatically set up the desired constraints, on the basis of the +impedances and PST settings provided by the user in the +Antares_Simulator dataset. + +c) Extension of the hydro storage model + +As compared to Antares 6.0.0, the next Open Source version shall +introduce much more flexibility in the way hydro resources (or any +other storable forms of energy) can be managed at the different stages +of the optimization problems definition and resolution. diff --git a/THANKS.txt b/THANKS.txt new file mode 100644 index 0000000000..d451d3cfd7 --- /dev/null +++ b/THANKS.txt @@ -0,0 +1,40 @@ +ATTRIBUTION NOTICES +=================== + +Antares_Simulator uses external libraries and makes extensive use of the +following persons' or companies code. Source and binary forms of these programs +are distributed along with Antares_Simulator with NO WARRANTY: + +Wxwidgets 3.0.2 Copyright (c) 1998-2017 The wxWidget Team +license: wxWindows Library License,V3.1 https://spdx.org/licenses/wxWindows.html + +libCurl 7.51.0 Copyright (c) 1996-2017 Daniel Stenberg et al +license: curl license https://spdx.org/licenses/curl.html + +OpenSSL 1.1.0 Copyright (c) 1998-2016 The OpenSSL Project +"This product includes software developed by the OpenSSL Project +for use in the OpenSSL Toolkit (http://www.openssl.org/)" +"This product includes software written by Tim Hudson (tjh@cryptsoft.com)" +license: OpenSSL license and SSLeay license https://spdx.org/licenses/OpenSSL.html + +libYuni 1.1.0 https://github.com/libyuni +license: Mozilla Public License 2.0 https://spdx.org/licenses/MPL-2.0.html + +Mersenne Twister Copyright (c) 1997-2002 M.Matsumoto and T.Nishimura +license: 3-clause BSD https://spdx.org/licenses/BSD-3-Clause.html + +strtod library Copyright (c) 1988-1993 The Regents of the University of California + Copyright (c) 1994 Sun Microsystems, Inc +license: ISC license https://spdx.org/licenses/ISC.html + +Sirius_Solver 6.0.0 Copyright (c) 2007-2018 RTE +license: EPL 2.0 https://spdx.org/licenses/EPL-2.0.html + + +SPECIAL THANKS +============== + +Special thanks are due to two Authors without whom Antares_Simulator would not be what it is: + + Damien Gerard (also developer of the libYuni library) + Robert Gonzalez (also author of the Sirius_Solver library) \ No newline at end of file diff --git a/docs/ref_guides/Antares-general-reference-guide.pdf b/docs/ref_guides/Antares-general-reference-guide.pdf new file mode 100644 index 0000000000..088f951e56 Binary files /dev/null and b/docs/ref_guides/Antares-general-reference-guide.pdf differ diff --git a/docs/ref_guides/Antares-map-editor-reference-guide.pdf b/docs/ref_guides/Antares-map-editor-reference-guide.pdf new file mode 100644 index 0000000000..34e68ba1e2 Binary files /dev/null and b/docs/ref_guides/Antares-map-editor-reference-guide.pdf differ diff --git a/docs/ref_guides/Antares_v6_General_brochure.pdf b/docs/ref_guides/Antares_v6_General_brochure.pdf new file mode 100644 index 0000000000..8c8241de08 Binary files /dev/null and b/docs/ref_guides/Antares_v6_General_brochure.pdf differ diff --git a/docs/ref_guides/Antares_v6_Optimization_Problems_Formulation.pdf b/docs/ref_guides/Antares_v6_Optimization_Problems_Formulation.pdf new file mode 100644 index 0000000000..3438df706d Binary files /dev/null and b/docs/ref_guides/Antares_v6_Optimization_Problems_Formulation.pdf differ diff --git a/resources/examples.7z b/resources/examples.7z new file mode 100644 index 0000000000..b19ac391b3 Binary files /dev/null and b/resources/examples.7z differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000..4e474b7d4e --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,225 @@ +project(antares) +cmake_minimum_required(VERSION 2.8) + +# Version +set(ANTARES_VERSION_HI 6) +set(ANTARES_VERSION_LO 0) +set(ANTARES_VERSION_REVISION 0) +set(ANTARES_VERSION_YEAR 2018) + +set(ANTARES_PUBLISHER "RTE France") +set(ANTARES_WEBSITE "https://antares.rte-france.com") + +# Beta release +set(ANTARES_BETA 0) +#set(ANTARES_RC 1) + + + + + + + + + + + + + + + + +# +# ---------------------------------------------------------------------------------------------- +# + + +# CMAKE - Suppress useless features +set(CMAKE_SKIP_PREPROCESSED_SOURCE_RULES true) +set(CMAKE_SKIP_ASSEMBLY_SOURCE_RULES true) + +include(CheckCXXSourceCompiles) +include(CheckIncludeFiles) +include(CheckIncludeFileCXX) +include(CheckCXXCompilerFlag) + +include("cmake/messages.cmake") + +if(${ANTARES_BETA}) + set(ANTARES_VERSION_TAG "-beta${ANTARES_BETA}") +else() + set(ANTARES_VERSION_TAG "") +endif() + +if(${ANTARES_RC}) + set (ANTARES_VERSION_TAG "${ANTARES_VERSION_TAG}-rc${ANTARES_RC}") +else() + set (ANTARES_RC 0) +endif() + +# Build Configuration +if("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + set(ANTARES_TARGET "${CMAKE_BUILD_TYPE}") +else() + set(CMAKE_BUILD_TYPE "debug") + set(ANTARES_TARGET "debug") +endif() + +OMESSAGE("") +OMESSAGE_TITLE("Antares " "v${ANTARES_VERSION_HI}.${ANTARES_VERSION_LO}.${ANTARES_VERSION_REVISION}${ANTARES_VERSION_TAG}-${ANTARES_TARGET}") +OMESSAGE("A New Tool for Adequacy Reporting of Electric Systems (RTE France)") +OMESSAGE_BOLD("Configuring...") +OMESSAGE("") + +include("cmake/changelog.cmake") +include("cmake/checks.cmake") + + + +if (ANTARES_LICENSE) + OMESSAGE("{antares} License : ${ANTARES_LICENSE}") +endif() + +set(ANTARES_PRG_VERSION "${ANTARES_VERSION_HI}.${ANTARES_VERSION_LO}") + +if ((WIN32 OR WIN64) AND (NOT MINGW AND NOT MSVC AND NOT CYGWIN AND NOT MSYS)) + set(MSVC 1) + set(ICC 1) +endif() + +if (CMAKE_SIZEOF_VOID_P EQUAL 8) + OMESSAGE(" Enabled 64bits instructions sets") + set(ANTARES_x86_64 true) + set(ANTARES_INSTALLER_ARCH "64bits") + set(ANTARES_INSTALLER_REDIST_ARCH "x64") + set(ANTARES_MANIFEST_ARCH "ia64") +else() + set(ANTARES_INSTALLER_ARCH "32bits") + set(ANTARES_INSTALLER_REDIST_ARCH "x86") + set(ANTARES_MANIFEST_ARCH "x86") +endif() + +if (WIN32) + if(MSVC) + set(COMPILER_NAME "vc14") + set(COMPILER_LIB_INCLUDE "vc") + else(MSVC) + set(COMPILER_NAME "gcc4.x") + set(COMPILER_LIB_INCLUDE "gcc") + endif(MSVC) +endif(WIN32) + +# +# Beta +# +if(NOT ANTARES_BETA EQUAL 0) + set(ANTARES_INSTALLER_BETA "-beta${ANTARES_BETA}") +else() + set(ANTARES_INSTALLER_BETA "") +endif() + +if(${ANTARES_RC}) + set(ANTARES_INSTALLER_RC "rc${ANTARES_RC}") +else() + set(ANTARES_INSTALLER_RC "") +endif() + +OMESSAGE("") +OMESSAGE("") + +set(ROOT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") + + +# +# Build Configuration +# +if("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + OMESSAGE("{antares} Build Configuration: RELEASE") +else() + OMESSAGE("{antares} Build Configuration: DEBUG") +endif() + + + + +# +# Yuni Framework +# +if("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + set(YUNI_TARGET_MODE "release") + set(ANTARES_VERSION_TARGET "release") +else() + set(YUNI_TARGET_MODE "debug") + set(ANTARES_VERSION_TARGET "debug") +endif() + +# All libraries will be stored in /bin directory +set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../bin/${YUNI_TARGET_MODE}) + + + +# +# SQLite +# +# SQLite is compiled from the repository +#add_subdirectory("ext/sqlite/src") + + + +# Standard Settings +include(cmake/common-settings.cmake) + + +# Licence stuff +include(cmake/libcurl_openssl.cmake) + +# Yuni Framework +configure_file("cmake/ProfileBuild.template.cmake" "ext/yuni/src/ProfileBuild.cmake") +add_subdirectory("ext/yuni/src") + +# +# The Global Config.h +# +configure_file("config.h.cmake" "config.h") + +OMESSAGE("") # empty line + +# Sub Directories +add_subdirectory(libs) +add_subdirectory(internet) +add_subdirectory(ui) +add_subdirectory(solver) +add_subdirectory(analyzer) + +#if (NOT WIN32 AND NOT WIN64) +# add_subdirectory(script) +#endif() + + +# Tools +add_subdirectory(tools) + +OMESSAGE("") + +# Informations for NSIS +if(WIN32 OR WIN64) + if(MSVC) + if("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + set(NSIS_TARGET "Release") + else("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + set(NSIS_TARGET "Debug") + endif("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + set(COMPILER_MARK "v") + #set(COMPILER_INCLUDE "vs9") + else(MSVC) + set(NSIS_TARGET "") + set(COMPILER_MARK "m") + set(COMPILER_INCLUDE "mingw") + endif(MSVC) + configure_file("distrib/win32/version.cmake" "distrib/win32/version.nsh") + configure_file("distrib/win32/build.template.cmake" "distrib/win32/build.nsh") + configure_file("distrib/win32/make-zip-from-installer.cmake" "distrib/win32/make-zip-from-installer.bat") +else() + configure_file("distrib/unix/packages.cmake" "distrib/unix/packages.sh") +endif() + diff --git a/src/FindCURL.cmake b/src/FindCURL.cmake new file mode 100644 index 0000000000..066ae21fd2 --- /dev/null +++ b/src/FindCURL.cmake @@ -0,0 +1,36 @@ +# Look for the header file. +set (CURL_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/ext/libcurl/include) + + +# Look for the library +set(LIB_CURL_NAME libcurl.a ) +set (CURL_LIBRARY ${PROJECT_SOURCE_DIR}/ext/libcurl/lib/.libs/${LIB_CURL_NAME}) + + +mark_as_advanced(CURL_LIBRARY) + +if(CURL_INCLUDE_DIR) + foreach(_curl_version_header curlver.h curl.h) + if(EXISTS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}") + file(STRINGS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}" curl_version_str REGEX "^#define[\t ]+LIBCURL_VERSION[\t ]+\".*\"") + string(REGEX REPLACE "^#define[\t ]+LIBCURL_VERSION[\t ]+\"([^\"]*)\".*" "\\1" CURL_VERSION_STRING "${curl_version_str}") + unset(curl_version_str) + break() + endif() + endforeach() +endif() + + + +# handle the QUIETLY and REQUIRED arguments and set CURL_FOUND to TRUE if +# all listed variables are TRUE +FIND_PACKAGE_HANDLE_STANDARD_ARGS(CURL + REQUIRED_VARS CURL_LIBRARY CURL_INCLUDE_DIR + VERSION_VAR CURL_VERSION_STRING) + + + +if(CURL_FOUND) + set(CURL_LIBRARIES ${CURL_LIBRARY}) + set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR}) +endif() diff --git a/src/FindOpenSSL.cmake b/src/FindOpenSSL.cmake new file mode 100644 index 0000000000..1bef7cbf08 --- /dev/null +++ b/src/FindOpenSSL.cmake @@ -0,0 +1,85 @@ +# Look for the header file. +set (OPENSSL_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/ext/openssl/include) + + +# Look for the library +set(LIB_EAY_NAMES libcrypto.a ) +set(SSL_EAY_NAMES libssl.a ) + +set(LIB_EAY ${PROJECT_SOURCE_DIR}/ext/openssl/${LIB_EAY_NAMES}) + +set(SSL_EAY ${PROJECT_SOURCE_DIR}/ext/openssl/${SSL_EAY_NAMES}) + + +set(OPENSSL_SSL_LIBRARY ${SSL_EAY} ) +set(OPENSSL_CRYPTO_LIBRARY ${LIB_EAY} ) +set(OPENSSL_LIBRARIES ${SSL_EAY} ${LIB_EAY} ) + +unset(LIB_EAY_NAMES) +unset(SSL_EAY_NAMES) + +function(from_hex HEX DEC) + string(TOUPPER "${HEX}" HEX) + set(_res 0) + string(LENGTH "${HEX}" _strlen) + while (_strlen GREATER 0) + math(EXPR _res "${_res} * 16") + string(SUBSTRING "${HEX}" 0 1 NIBBLE) + string(SUBSTRING "${HEX}" 1 -1 HEX) + if (NIBBLE STREQUAL "A") + math(EXPR _res "${_res} + 10") + elseif (NIBBLE STREQUAL "B") + math(EXPR _res "${_res} + 11") + elseif (NIBBLE STREQUAL "C") + math(EXPR _res "${_res} + 12") + elseif (NIBBLE STREQUAL "D") + math(EXPR _res "${_res} + 13") + elseif (NIBBLE STREQUAL "E") + math(EXPR _res "${_res} + 14") + elseif (NIBBLE STREQUAL "F") + math(EXPR _res "${_res} + 15") + else() + math(EXPR _res "${_res} + ${NIBBLE}") + endif() + string(LENGTH "${HEX}" _strlen) + endwhile() + set(${DEC} ${_res} PARENT_SCOPE) +endfunction() + +if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h") + file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str + REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*") + if(openssl_version_str) + # The version number is encoded as 0xMNNFFPPS: major minor fix patch status + # The status gives if this is a developer or prerelease and is ignored here. + # Major, minor, and fix directly translate into the version numbers shown in + # the string. The patch field translates to the single character suffix that + # indicates the bug fix state, which 00 -> nothing, 01 -> a, 02 -> b and so + # on. + string(REGEX REPLACE "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F]).*$" + "\\1;\\2;\\3;\\4;\\5" OPENSSL_VERSION_LIST "${openssl_version_str}") + list(GET OPENSSL_VERSION_LIST 0 OPENSSL_VERSION_MAJOR) + list(GET OPENSSL_VERSION_LIST 1 OPENSSL_VERSION_MINOR) + from_hex("${OPENSSL_VERSION_MINOR}" OPENSSL_VERSION_MINOR) + list(GET OPENSSL_VERSION_LIST 2 OPENSSL_VERSION_FIX) + from_hex("${OPENSSL_VERSION_FIX}" OPENSSL_VERSION_FIX) + list(GET OPENSSL_VERSION_LIST 3 OPENSSL_VERSION_PATCH) + if (NOT OPENSSL_VERSION_PATCH STREQUAL "00") + from_hex("${OPENSSL_VERSION_PATCH}" _tmp) + # 96 is the ASCII code of 'a' minus 1 + math(EXPR OPENSSL_VERSION_PATCH_ASCII "${_tmp} + 96") + unset(_tmp) + # Once anyone knows how OpenSSL would call the patch versions beyond 'z' + # this should be updated to handle that, too. This has not happened yet + # so it is simply ignored here for now. + string(ASCII "${OPENSSL_VERSION_PATCH_ASCII}" OPENSSL_VERSION_PATCH_STRING) + endif () + set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}") + endif () +endif () + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenSSL + REQUIRED_VARS OPENSSL_LIBRARIES OPENSSL_INCLUDE_DIR + VERSION_VAR OPENSSL_VERSION ) + +mark_as_advanced(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES) diff --git a/src/FindWXWidgets.cmake b/src/FindWXWidgets.cmake new file mode 100644 index 0000000000..794612ab6b --- /dev/null +++ b/src/FindWXWidgets.cmake @@ -0,0 +1,178 @@ + + + +# +# wxWidgets +# +if(WIN32) + # + # Specific setup + # + + if("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + set(WX_BUILD_STRING "release") + else() + set(WX_BUILD_STRING "debug") + set(WX_BUILD_TYPE "d") + endif() + if(NOT "${ANTARES_x86_64}" STREQUAL "") + set(WX_ARCH_TYPE "_x64") + #set(WX_ARCH_TYPE "_x64") + else() + set(WX_ARCH_TYPE "") + endif() + + #set(WX_ROOT_PATH "C:/projects/wxwidgets/3.1/${COMPILER_LIB_INCLUDE}-${WX_BUILD_TYPE}-${WX_ARCH_TYPE}") + set(WX_ROOT_PATH "${ANTARES_WX_ROOT_PATH}") + set(WX_VERSION ${ANTARES_WX_VERSION}) + + # + # Generic setup + # + + set(wxWidgets_BASEDIR "${WX_ROOT_PATH}") + set(wxWidgets_LIBRARIES_DIRS "${wxWidgets_BASEDIR}/lib/${COMPILER_LIB_INCLUDE}${WX_ARCH_TYPE}_lib") + + set(wxWidgets_INCLUDE_DIRS "${wxWidgets_BASEDIR}/include" + "${wxWidgets_LIBRARIES_DIRS}/mswu${WX_BUILD_TYPE}") + + OMESSAGE("${wxWidgets_BASEDIR}") + OMESSAGE("${wxWidgets_LIBRARIES_DIRS}") + OMESSAGE("${wxWidgets_INCLUDE_DIRS}") + + set(wxWidgets_LIBRARIES + "wxbase${WX_VERSION}u${WX_BUILD_TYPE}" + "wxmsw${WX_VERSION}u${WX_BUILD_TYPE}_core" + "wxmsw${WX_VERSION}u${WX_BUILD_TYPE}_aui" + "wxmsw${WX_VERSION}u${WX_BUILD_TYPE}_adv" + "wxmsw${WX_VERSION}u${WX_BUILD_TYPE}_richtext" + "wxmsw${WX_VERSION}u${WX_BUILD_TYPE}_html" + "wxbase${WX_VERSION}u${WX_BUILD_TYPE}_xml" + "wxmsw${WX_VERSION}u${WX_BUILD_TYPE}_propgrid" + wxjpeg${WX_BUILD_TYPE} + wxpng${WX_BUILD_TYPE} + wxregexu${WX_BUILD_TYPE} + wxtiff${WX_BUILD_TYPE} + wxzlib${WX_BUILD_TYPE} + wxexpat${WX_BUILD_TYPE} + # Windows related libraries + kernel32 user32 gdi32 comdlg32 winspool winmm shell32 + comctl32 ole32 oleaut32 uuid rpcrt4 advapi32 + wsock32 odbc32) + + if("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + #set(wxWidgets_INCLUDE_DIRS "${wxWidgets_BASEDIR}/include" + # "${wxWidgets_BASEDIR}/lib/vc_lib/mswu") + set(wxWidgets_DEFINITIONS "-D_UNICODE" + "-DHAVE_WIN32API_H" + "-D__WXMSW__" "-D_WINDOWS" + "-DwxUSE_GUI" + "-DwxUSE_THREADS" + "-DwxUSE_BASE=1") + # set(wxWidgets_LIBRARIES + # wxbase30u + # wxmsw30u_core + # wxmsw30u_aui + # wxmsw30u_adv + # wxmsw30u_richtext + # wxmsw30u_html + # wxbase30u_xml + # wxmsw30u_propgrid + # wxjpeg + # wxpng + # wxregexu + # wxtiff + # wxzlib + # wxexpat + # # Windows related libraries + # kernel32 user32 gdi32 comdlg32 winspool winmm shell32 + # comctl32 ole32 oleaut32 uuid rpcrt4 advapi32 + # wsock32 odbc32) + + else() + + #set(wxWidgets_INCLUDE_DIRS "${wxWidgets_BASEDIR}/include" + # "${wxWidgets_BASEDIR}/lib/vc_lib/mswud") + Set(wxWidgets_DEFINITIONS "-D_UNICODE" + "-DHAVE_WIN32API_H" + "-D__WXMSW__" "-D_WINDOWS" "-D_DEBUG" + "-DwxUSE_GUI" + "-DwxUSE_BASE=1" + "-DwxUSE_THREADS" + "-D__WXDEBUG__") + # set(wxWidgets_LIBRARIES + # wxbase30ud + # wxmsw30ud_core + # wxmsw30ud_aui + # wxmsw30ud_adv + # wxmsw30ud_richtext + # wxmsw30ud_html + # wxbase30ud_xml + # wxmsw30ud_propgrid + # wxjpegd + # wxpngd + # wxregexud + # wxtiffd + # wxzlibd + # wxexpatd + # # Windows related libraries + # kernel32 user32 gdi32 comdlg32 winspool winmm shell32 + # comctl32 ole32 oleaut32 uuid rpcrt4 advapi32 + # wsock32 odbc32) + + endif() + + if(NOT "${IS_64BITS}" STREQUAL "") + set(wxWidgets_DEFINITIONS ${wxWidgets_DEFINITIONS} "-DWIN64" "-D_M_X64") + else() + set(wxWidgets_DEFINITIONS ${wxWidgets_DEFINITIONS} "-DWIN32") + endif() + link_directories("${wxWidgets_LIBRARIES_DIRS}") + + # wxWidgets include directory + include_directories(${wxWidgets_INCLUDE_DIRS}) + + foreach(d ${wxWidgets_DEFINITIONS}) + string(STRIP "${d}" d) + string(SUBSTRING "${d}" 0 2 p) + if(NOT "${p}" STREQUAL "-D") + add_definitions("-D${d}") + else() + add_definitions("${d}") + endif() + endforeach() + + #message(STATUS "wxWidgets: Incl: ${wxWidgets_INCLUDE_DIRS}") + #message(STATUS "wxWidgets: Libs: ${wxWidgets_LIBRARIES_DIRS}") + #message(STATUS "wxWidgets: Defs: ${wxWidgets_DEFINITIONS}") + #message(STATUS "wxWidgets: Root path: ${WX_ROOT_PATH}") + +else() + set(wxWidgets_USE_UNICODE true) + execute_process(COMMAND ${PROJECT_SOURCE_DIR}/ext/wxwidgets/build_gtk/wx-config --unicode=yes --cxxflags OUTPUT_VARIABLE WX_CXXFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${PROJECT_SOURCE_DIR}/ext/wxwidgets/build_gtk/wx-config --unicode=yes --libs std,richtext,propgrid,aui OUTPUT_VARIABLE WX_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) + + # Fixed some strange result from wx-config + #string(REPLACE "-lwxregexu-3.1" "/local/partage/opt/lib/libwxregexu-3.1.a" WX_LIBS_FIX "${WX_LIBS}") + #string(REGEX REPLACE "[^ ]+\\.a" "" WX_LIBS_CLEAN "${WX_LIBS_FIX}") + #string(REGEX MATCHALL "[^ ]+\\.a" wxWidgets_LIBRARIES "${WX_LIBS_FIX}") + + #set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${WX_LIBS_CLEAN}") + #set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${WX_LIBS_CLEAN}") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${WX_CXXFLAGS}") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${WX_CXXFLAGS}") + + set(wxWidgets_LIBRARIES "${WX_LIBS}") + +endif() + + + +# add wxWidgets definitions +add_definitions(-DXTHREADS -D_REENTRANT -DXUSE_MTSAFE_API) + + +if(ANTARES_GUI) + add_definitions("-DWX_SUPPORT") +endif(ANTARES_GUI) + diff --git a/src/analyzer/CMakeLists.txt b/src/analyzer/CMakeLists.txt new file mode 100644 index 0000000000..be4f98c411 --- /dev/null +++ b/src/analyzer/CMakeLists.txt @@ -0,0 +1,64 @@ +project(AntaresAnalyzer) + +cmake_minimum_required(VERSION 2.8) + +include(../cmake/messages.cmake) +OMESSAGE("antares-analyzer") + +include(../cmake/common-settings.cmake) + + + + +# Le main +Set(SRCS main.cpp + atsp/atsp.h + atsp/atsp.hxx + atsp/atsp.cpp + atsp/load.cpp + atsp/misc.cpp + atsp/preflight.cpp + atsp/correlations.cpp + atsp/cache.cpp + ) + + +# The new ant library +include_directories("..") + + + +if(WIN32) + file(REMOVE "${CMAKE_CURRENT_SOURCE_DIR}/win32/analyzer.o") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/win32/analyzer.rc.cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/win32/analyzer.rc") + + if(MINGW) + # resource compilation for mingw + ADD_CUSTOM_COMMAND(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/win32/analyzer.o" + COMMAND windres.exe "-I${CMAKE_CURRENT_SOURCE_DIR}" + "-i${CMAKE_CURRENT_SOURCE_DIR}/win32/analyzer.rc" + -o "${CMAKE_CURRENT_BINARY_DIR}/win32/analyzer.o") + SET(SRCS ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/win32/analyzer.o") + else(MINGW) + SET(SRCS ${SRCS} "win32/analyzer.rc") + endif(MINGW) +endif(WIN32) + + +add_executable(antares-${ANTARES_PRG_VERSION}-analyzer ${SRCS}) + +target_link_libraries(antares-${ANTARES_PRG_VERSION}-analyzer + libantares-license + libantares-core + libantares-core-calendar + yuni-static-core + ${wxWidgets_LIBRARIES} ${CMAKE_THREADS_LIBS_INIT}) +if(NOT WIN32) + target_link_libraries(antares-${ANTARES_PRG_VERSION}-analyzer dl ssh2 idn rt) +endif(NOT WIN32) + + +import_std_libs(antares-${ANTARES_PRG_VERSION}-analyzer) +executable_strip(antares-${ANTARES_PRG_VERSION}-analyzer) + diff --git a/src/analyzer/atsp/atsp.cpp b/src/analyzer/atsp/atsp.cpp new file mode 100644 index 0000000000..1c27cdd678 --- /dev/null +++ b/src/analyzer/atsp/atsp.cpp @@ -0,0 +1,203 @@ +/* +** Copyright 2007-2018 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include "atsp.h" + + +using namespace Yuni; + +#define SEP Yuni::IO::Separator + + +namespace Antares +{ + + // constants + const uint ATSP::lonmois[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; + const uint ATSP::durmois[12] = {744,672,744,720,744,720,744,744,720,744,720,744}; + const uint ATSP::posmois[12] = {0,744,1416,2160,2880,3624,4344,5088,5832,6552,7296,8016}; + + + + ATSP::ATSP() : + pRoundingCount(), + pRounding80percentCount(), + pRoundingCountTotal(), + HOR(0.92), + pLimitMemory(200 * 1024 * 1024), + pCacheMemoryUsed(), + pAutoClean(false) + { + } + + + ATSP::~ATSP() + { + for (uint i = 0; i != pArea.size(); ++i) + delete pArea[i]; + + if (pAutoClean) + { + logs.info() << "Cleaning..."; + pStr.clear(); + # ifdef YUNI_OS_WINDOWS + pStr << "del /S /F /Q "; + pStr << '"' << pTemp << SEP << tsName << '"'; + system(pStr.c_str()); + pStr.clear(); + pStr << "rmdir /S /Q "; + pStr << '"' << pTemp << SEP << tsName << '"'; + system(pStr.c_str()); + pStr.clear(); + pStr << "rmdir /Q "; + pStr << '"' << pTemp << '"'; + system(pStr.c_str()); + # else + pStr << "rm -rf "; + pStr << '"' << pTemp << SEP << tsName << '"'; + system(pStr.c_str()); + # endif + } + } + + + void ATSP::printSummary() const + { + logs.info(); + logs.info() << " Summary :"; + logs.info() << " number of timeseries : " << pTimeseriesCount; + logs.info() << " short-term autocorr adjustment : " << pShortTermAutoCorrAdjustment; + logs.info() << " medium-term autocorr. adjustment : " << pMediumTermAutoCorrAdjustment; + logs.info() << " trimming threshold : " << pRoundOff; + + if (pUseUpperBound) + logs.info() << " upper bound : " << pUpperBound; + else + logs.info() << " upper bound : (none)"; + + if (pUseLowerBound) + logs.info() << " lower bound : " << pLowerBound; + else + logs.info() << " lower bound : (none)"; + + logs.info() << " memory cache size : " << (pLimitMemory / 1024 / 1024) << "Mo"; + logs.info() << " auto-clean : " << (pAutoClean ? "yes" : "no"); + + logs.info(); + if (pArea.size() > 1) + logs.info() << " " << pArea.size() << " areas to analyze"; + else + logs.info() << " 1 area to analyze"; + + for (uint i = 0; i != pArea.size(); ++i) + { + const AreaInfo& info = *pArea[i]; + if (info.rawData) + { + logs.info() << " " << info.name << ": law '" << Data::XCast::DistributionToCString(info.distribution) + << "' will be fitted on raw data"; + } + else + { + logs.info() << " " << info.name << ": law '" << Data::XCast::DistributionToCString(info.distribution) + << "' will be fitted on deviation from average data"; + } + } + } + + + + bool ATSP::writeMoments() const + { + IO::File::Stream f; + { + String filename; + filename.clear() << pTemp << SEP << tsName << SEP << "moments-table.txt"; + if (!f.openRW(filename)) + { + logs.error() << "Impossible to create " << filename; + return false; + } + } + + f << '\t'; + for (uint j = 0; j < 12; ++j) + { + for (uint k = 0; k < 4; ++k) + f << "MONTH " << (j+1) << '\t'; + } + f << "\n\t"; + + for (uint j = 0; j < 12; ++j) + f << " EXPEC\t STAND\t SKEWN\t KURTO\t"; + f << '\n'; + + for (uint i = 0; i < pArea.size(); ++i) + { + const AreaInfo& info = *(pArea[i]); + if (!info.enabled) + continue; + + f << info.name << '\t'; + const MomentCentrSingle& moment = moments_centr[i]; + + for (uint j = 0; j < 12; ++j) + { + const double* m = moment.data[j]; + + for (uint k = 0; k < 4; ++k) + f << m[k] << '\t'; + } + f << '\n'; + } + + return true; + } + + + bool ATSP::cachePreload(unsigned index, const AnyString& filename, + uint height, Matrix<>::BufferType& buffer) + { + enum + { + options = Matrix<>::optImmediate | Matrix<>::optFixedSize, + }; + if (pCacheMatrix[index].loadFromCSVFile(filename, NBS, height, options, &buffer)) + { + pCacheLastValidIndex = index + 1; + return true; + } + else + pCacheMatrix[index].clear(); + + return false; + } + + + + +} // namespace Antares diff --git a/src/analyzer/atsp/atsp.h b/src/analyzer/atsp/atsp.h new file mode 100644 index 0000000000..0663f6dcb6 --- /dev/null +++ b/src/analyzer/atsp/atsp.h @@ -0,0 +1,270 @@ +/* +** Copyright 2007-2018 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ +#ifndef __PREPROCESSOR_ATSP_H__ +# define __PREPROCESSOR_ATSP_H__ + +# include +# include +# include +# include + + + +namespace Antares +{ + + + class ATSP final + { + public: + //! The most suitable smart pointer for the class + typedef Yuni::SmartPtr Ptr; + + public: + //! \name Constructor & Destructor + //@{ + /*! + ** \brief Default constructor + */ + ATSP(); + //! Destructor + ~ATSP(); + //@} + + /*! + ** \brief Load settings from an INI file + */ + bool loadFromINIFile(const Yuni::String& filename); + + /*! + ** \brief Print a summary + */ + void printSummary() const; + + bool preflight(); + + bool computeMonthlyCorrelations(); + + + private: + class AreaInfo final + { + public: + //! Vector + typedef std::vector Vector; + + public: + bool enabled; + Data::AreaName name; + Yuni::String filename; + bool rawData; + Data::XCast::Distribution distribution; + }; + + struct MomentCentrSingle + { + double data[12][4]; + }; + typedef std::vector MomentCentr; + + + private: + // range dans les nblig première lignes et nbcol premières colonnes de OUT + // le bloc d'Ă©lements de MTRX de taille nblig x nbcol commençant aux indices indlig et indcol + static void Extrait_bloc(Matrix<>& out, uint indlig, uint indcol, + const Matrix<>& MTRX, uint nblig, uint nbcol); + + // range dans OUT la moyenne des colonnes de MTRX + static void Colonne_moyenne(double* out, const Matrix<>& MTRX, uint nblig, uint nbcol); + + // retourne le maximum ou le minimum de MTRX selon le code + static void Mtrx_bound(double& rmin, double& rmax, const Matrix<>& MTRX, + uint nblig, uint nbcol); + + // met dans OUT la valeur absolue de MTRX + static void Mtrx_abs(Matrix<>& out, const Matrix<>& MTRX, uint nblig, uint nbcol); + + // retourne la moyenne des elements de A + static double Moyenne_generale(double* A, uint nblig); + + // retranche de MTRX le vecteur A + static void Retranche_mtrx(Matrix<>& MTRX, const double* A, uint nblig, uint nbcol); + + // range dans OUT les nblig première lignes de la colonne de MTRX d'indice indcol + static void Extrait_col(double* out, const Matrix<>& MTRX, uint nblig, uint indcol); + + // met dans A le carre de B + static void Square(double* A, const double* B, uint nblig); + + // met (B- le scalaire x) dans A + static void Retranche_scalaire(Matrix<>& A, const Matrix<>& B, double x, uint nblig, uint nbcol); + + // met (B /scalaire x) dans A + static void Divise_scalaire(Matrix<>& A, const Matrix<>& B, double x, uint nblig, uint nbcol); + + // met dans A le cube de B + static void Cube(double* A, const double* B, uint nblig); + + // met dans A B^4 + static void Dsquare(double* A, const double* B, uint nblig); + + // range dans OUT nblig elements de MTRX pris a partir de l'indice indlig + static void Extrait_seg(double* out, const double* src, uint nblig, uint indlig); + + // retourne le coefficient de corrĂ©lation entre A et B (retourne 999 si paramètre "code" aberrant) + // si code = 0 : les espĂ©rances et Ă©carts-types des variables reprĂ©sentĂ©es par A et B sont Ă  calculer + // si code = 1 : des estimations des espĂ©rances et Ă©carts-types sont fournis dans EA,EB,SA,SB + static double Correlation(double* A, double* B, uint nblig, double EA, double EB, double SA, double SB, int code); + + static double GammaEuler(double z); + + static double Ecart(double T1, double P1, double T2, double P2 , int M, double T); + + static double autocorr_average(int H, int M, double R); + + static double Standard_shrinkage(int M, double R); + + + private: + //! Check the study version + bool checkStudyVersion() const; + + bool preflight(const uint areaIndex); + + void Analyse_auto(double* A, int nblig, double auc, double aum, double hor, double& theta, double& mu); + + // ajustement de la densitĂ© de probabilitĂ© en fonction des bornes L, U, de l'espĂ©rance E + // et de l'Ă©cart-type S + // selon une loi "type" : calcule alpha=A, beta = B, gamma = C, delta = D + // retourne 0 si le calage est possible et 1 sinon + bool Probab_density_funct(double L, double U, double E, double S, Data::XCast::Distribution law, + double& A, double& B, double& C, double& D); + + void roundMatrixValues(Matrix<>& m); + + bool writeMoments() const; + + void cacheCreate(); + void cacheDestroy(); + void cacheClear(); + bool cacheFetch(uint index, Matrix<>& out) const; + + bool cachePreload(uint index, const AnyString& filename, + uint height, Matrix<>::BufferType& buffer); + + + private: + AreaInfo::Vector pArea; + YString pStudyFolder; + YString pTemp; + uint pTimeseriesCount; + uint pMHeight; + uint pTimeseries; + double pMediumTermAutoCorrAdjustment; + double pShortTermAutoCorrAdjustment; + double pRoundOff; + double pUpperBound; + double pUpperBound80percent; + double pLowerBound; + bool pUseUpperBound; + bool pUseLowerBound; + yuint64 pRoundingCount; + yuint64 pRounding80percentCount; + yuint64 pRoundingCountTotal; + Yuni::ShortString16 tsName; + + uint pEnabledAreaCount; + + //! The total number of zareas + uint NBZ; + //! The total number of timeseries to analyze + uint NBS; + + //! The target timeseries (1: wind, 2: solar, 3: load) + char TDS; + //! The target timeseries (W: wind, S: solar, L: load) + char code; + + double RTZ; + //! Short-term auto-correlation adjustment + double AUC; + //! Medium-term auto-correlation adjustment + double AUM; + + /*! + ** \brief Horizon degenere + ** + ** Autocorrelation minimale requise entre X(0) et X(0+mu), ou mu est la periode des + ** moyennes glissantes de X(t) + ** + ** valeur >= 0.92 pour eviter la degenerescence de X en loi normale + ** Ce seuil n'est pas utilise quand l'analyse porte sur une loi normale + */ + const double HOR; // 0.92 by default + enum + { + //! nombre de valeurs d'autocorrelation calculees (de X0-X0 Ă  X0-X119) + PRA = 120, + }; + + MomentCentr moments_centr; + + Matrix<> SERIE_N; + Matrix<> SERIE_P; + Matrix<> SERIE_Q; + + double buffer_n[744]; + double buffer_p[744]; + double buffer_q[744]; + + static const uint lonmois[12]; + static const uint durmois[12]; + static const uint posmois[12]; + enum { durjour = 24 }; + + yuint64 pLimitMemory; + yuint64 pCacheMemoryUsed; + uint pCacheLastValidIndex; + Matrix<>* pCacheMatrix; + + Yuni::String::Vector folderPerArea; + //! Temporary string mainly used for filename manipulation + Yuni::CString<512> pStr; + + bool pAutoClean; + + }; // class ATSP + + + + + +} // namespace Antares + +# include "atsp.hxx" + +#endif // __PREPROCESSOR_ATSP_H__ diff --git a/src/analyzer/atsp/atsp.hxx b/src/analyzer/atsp/atsp.hxx new file mode 100644 index 0000000000..84719fbdd1 --- /dev/null +++ b/src/analyzer/atsp/atsp.hxx @@ -0,0 +1,51 @@ +/* +** Copyright 2007-2018 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ +#ifndef __PREPROCESSOR_ATSP_HXX__ +# define __PREPROCESSOR_ATSP_HXX__ + + + +namespace Antares +{ + + + inline bool ATSP::cacheFetch(uint index, Matrix<>& out) const + { + if (pCacheMatrix[index].width > 0) + { + out = pCacheMatrix[index]; + return true; + } + return false; + } + + + + +} // namespace Antares + +#endif // __PREPROCESSOR_ATSP_HXX__ diff --git a/src/analyzer/atsp/cache.cpp b/src/analyzer/atsp/cache.cpp new file mode 100644 index 0000000000..402cbd6030 --- /dev/null +++ b/src/analyzer/atsp/cache.cpp @@ -0,0 +1,67 @@ +/* +** Copyright 2007-2018 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include "atsp.h" + + +using namespace Yuni; + + +#define SEP Yuni::Core::IO::Separator + + +namespace Antares +{ + + void ATSP::cacheCreate() + { + pCacheMatrix = new Matrix<>[pArea.size()]; + pCacheMemoryUsed = sizeof(Matrix<>) * pArea.size(); + pCacheLastValidIndex = 0; + } + + + void ATSP::cacheDestroy() + { + delete[] pCacheMatrix; + pCacheMatrix = NULL; + } + + + void ATSP::cacheClear() + { + for (uint i = 0; i != pCacheLastValidIndex; ++i) + pCacheMatrix[i].clear(); + pCacheMemoryUsed = sizeof(Matrix<>) * pArea.size(); + pCacheLastValidIndex = 0; + } + + + + + +} // namespace Antares diff --git a/src/analyzer/atsp/correlations.cpp b/src/analyzer/atsp/correlations.cpp new file mode 100644 index 0000000000..e5f3a95b22 --- /dev/null +++ b/src/analyzer/atsp/correlations.cpp @@ -0,0 +1,413 @@ +/* +** Copyright 2007-2018 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include "atsp.h" +#include +#include "../solver/misc/matrix-dp-make.h" + + +using namespace Yuni; + + +#define SEP Yuni::IO::Separator + + +namespace Antares +{ + + + bool ATSP::computeMonthlyCorrelations() + { + logs.checkpoint() << "Monthly correlation values"; + + // Prepare the cache + cacheCreate(); + + // pre-cleaning, just in case + SERIE_N.clear(); + SERIE_P.clear(); + SERIE_Q.clear(); + + // The real number of areas + const uint realAreaCount = pEnabledAreaCount; + + // stockage d'une matrice mensuelle de correlations inter-zones + Matrix<> CORR_MNP; + CORR_MNP.reset(realAreaCount, realAreaCount); + // stockage de la matrice annuelle obtenue par moyenne des correlations mensuelles + Matrix<> CORR_YNP; + CORR_YNP.reset(realAreaCount, realAreaCount); + + Matrix<> ID; + ID.reset(realAreaCount, realAreaCount); + ID.fillUnit(); + + Matrix<> resultNDP; + resultNDP.reset(realAreaCount, realAreaCount); + Matrix<> tmpNDP; + tmpNDP.reset(realAreaCount, realAreaCount); + + double* tmpArray = new double[realAreaCount + 1]; + + // Initialize mapping, to skip areas which has been disabled + // the real number of items is `realAreaCount` + uint* mapping = new uint [pArea.size()]; + { + uint z = 0; + for (uint i = 0; i != pArea.size(); ++i) + { + mapping[i] = (uint) -1; + if (pArea[i]->enabled) + { + mapping[z] = i; + ++z; + } + } + } + + // Buffer for reading matrices + Matrix<>::BufferType buffer; + + // + size_t sizePerMatrix = 744 * pTimeseriesCount * sizeof(double); + + for (uint m = 0; m < 12; ++m) + { + logs.info() << "Correlation: Precaching data for " << Antares::Date::MonthToString(m); + cacheClear(); + + { + uint iZ = realAreaCount; + do + { + if (pCacheMemoryUsed + sizePerMatrix > pLimitMemory) + break; + --iZ; + const uint i = mapping[iZ]; + const String& folder = folderPerArea[i]; + pStr.clear() << folder << SEP << "userfile-m"; + if (m < 10) + pStr << '0'; + pStr << m << ".txt"; + + if (!cachePreload(i, pStr, durmois[m], buffer)) + break; + } + while (iZ); + } + + for (uint iZ = 0; iZ < realAreaCount; ++iZ) + { + const uint i = mapping[iZ]; + + // The folder for the area + const String& folder = folderPerArea[i]; + + + if (!cacheFetch(i, SERIE_N)) + { + pStr.clear() << folder << SEP << "userfile-m"; + if (m < 10) + pStr << '0'; + pStr << m << ".txt"; + if (!SERIE_N.loadFromCSVFile(pStr, NBS, durmois[m], Matrix<>::optImmediate|Matrix<>::optFixedSize, &buffer)) + { + logs.error() << "impossible to open " << pStr; + continue; + } + } + + CORR_MNP.entry[iZ][iZ] = 1.; + for (uint jZ = iZ + 1; jZ < realAreaCount; ++jZ) + { + const uint j = mapping[jZ]; + // The folder for the area + const String& folderJ = folderPerArea[j]; + + logs.info() << "Correlation: month: " << Antares::Date::MonthToString(m) + << ", area " << (1+iZ) << '/' << realAreaCount << ": " << pArea[i]->name + << " with area " << (1+jZ) << '/' << realAreaCount << ": " << pArea[j]->name; + + if (!cacheFetch(j, SERIE_P)) + { + pStr.clear() << folderJ << SEP << "userfile-m"; + if (m < 10) + pStr << '0'; + pStr << m << ".txt"; + if (!SERIE_P.loadFromCSVFile(pStr, NBS, durmois[m], Matrix<>::optImmediate|Matrix<>::optFixedSize, &buffer)) + continue; + } + + + double coeff = 0.; + for (uint q = 0; q < NBS; ++q) + { + Extrait_col(buffer_n, SERIE_N, durmois[m], q); + Extrait_col(buffer_p, SERIE_P, durmois[m], q); + const double xx = Correlation(buffer_n, buffer_p, durmois[m], + moments_centr[i].data[m][0], moments_centr[j].data[m][0], + moments_centr[i].data[m][1], moments_centr[j].data[m][1], 0); + + coeff += xx / NBS; + } + + // The rounding must be done later, otherwise CORR_YNP will + // be rounding as well + CORR_MNP.entry[iZ][jZ] = coeff; + CORR_MNP.entry[jZ][iZ] = coeff; + } + } + + for (uint i = 0; i < realAreaCount; ++i) + { + Matrix<>::ColumnType& outcol = CORR_YNP.entry[i]; + const Matrix<>::ColumnType& col = CORR_MNP.entry[i]; + for (uint j = 0; j < realAreaCount; ++j) + outcol[j] += col[j] / 12.; + } + + // Rounding monthly correlation coefficients (matrix trimming) + for (uint i = 1; i < CORR_MNP.width; ++i) + { + auto& column = CORR_MNP[i]; + for (uint j = 0; j < i; ++j) + { + if (Math::Abs(column[j]) < RTZ) + { + column[j] = 0.; + CORR_MNP[j][i] = 0.; + } + else if (column[j] > 1.) + { + column[j] = 1.; + CORR_MNP[j][i] = 1.; + } + else if (column[j] < -1.) + { + column[j] = -1.; + CORR_MNP[j][i] = -1.; + } + } + } + + // Writing the monthly correlation coefficients + resultNDP.zero(); + + pStr.clear() << pTemp << SEP << tsName << SEP << "origin-correlation-m"; + if (m < 10) + pStr << '0'; + pStr << m << ".txt"; + CORR_MNP.saveToCSVFile(pStr); + + + // Converting into an admissible matrix + double ret = Solver::MatrixDPMake(tmpNDP.entry, CORR_MNP.entry, resultNDP.entry, ID.entry, ID.width, tmpArray); + if (ret < 1.) + { + if (ret <= -1.) + { + logs.error() << "invalid data, can not be processed"; + } + else + { + logs.warning() << "TS-Analyzer: " << Date::MonthToString(m) << ": correlation matrix was shrinked by " << ret + << ". Trimming threshold may be too high"; + } + } + + // copying results + for (uint y = 1; y < resultNDP.height; ++y) + { + for (uint x = 0; x < y; ++x) + resultNDP[x][y] = resultNDP[y][x]; + } + + pStr.clear() << pTemp << SEP << tsName << SEP << "correlation-m"; + if (m < 10) + pStr << '0'; + pStr << m << ".txt"; + resultNDP.saveToCSVFile(pStr); + } + + // Memory cleaning + buffer.clear().shrink(); + SERIE_N.clear(); + SERIE_P.clear(); + SERIE_Q.clear(); + CORR_MNP.clear(); + moments_centr.clear(); + cacheDestroy(); + + + // Rounding annual correlation coefficients + for (uint i = 1; i < CORR_YNP.width; ++i) + { + auto& column = CORR_YNP[i]; + for (uint j = 0; j < i; ++j) + { + if (Math::Abs(column[j]) < RTZ) + { + column[j] = 0.; + CORR_YNP[j][i] = 0.; + } + else if (column[j] > 1.) + { + column[j] = 1.; + CORR_YNP[j][i] = 1.; + } + else if (column[j] < -1.) + { + column[j] = -1.; + CORR_YNP[j][i] = -1.; + } + } + } + + // Annual correlation coefficients + pStr.clear() << pTemp << SEP << tsName << SEP << "origin-correlation-year.txt"; + CORR_YNP.saveToCSVFile(pStr); + + // Converting into an admissible matrix + double ret = Solver::MatrixDPMake(tmpNDP.entry, CORR_YNP.entry, resultNDP.entry, ID.entry, ID.width, tmpArray); + if (ret < 1.) + { + if (ret <= -1.) + { + logs.error() << "invalid data, can not be processed"; + } + else + { + logs.warning() << "TS-Analyzer: annual: correlation matrix was shrinked by " + << ret << ". Trimming threshold may be too high"; + } + } + for (uint y = 1; y < resultNDP.height; ++y) + { + for (uint x = 0; x < y; ++x) + resultNDP[x][y] = resultNDP[y][x]; + } + + // Annual correlation coefficients + pStr.clear() << pTemp << SEP << tsName << SEP << "correlation-year.txt"; + resultNDP.saveToCSVFile(pStr); + + + { + // We won't use the class `Correlation` here + // because it would be memory hungry + CString key; + + pStr.clear() << pStudyFolder << SEP << "input" << SEP << tsName + << SEP << "prepro" << SEP << "correlation.ini"; + IO::File::Stream f; + if (not f.open(pStr, IO::OpenMode::write | IO::OpenMode::truncate)) + { + logs.error() << "Impossible to create " << pStr; + } + else + { + f << "[general]\n"; + f << "mode = monthly\n\n"; + + f << "[annual]\n"; + for (uint iZ = 0; iZ != realAreaCount; ++iZ) + { + const uint i = mapping[iZ]; + //const auto& col = CORR_YNP.entry[iZ]; + const auto& col = resultNDP[iZ]; + for (uint jZ = iZ + 1; jZ < realAreaCount; ++jZ) + { + if (not Math::Zero(col[jZ])) + { + const uint j = mapping[jZ]; + f << pArea[i]->name << '%' << pArea[j]->name << " = " << col[jZ] << '\n'; + } + } + } + f << '\n'; + CORR_YNP.clear(); + + for (uint m = 0; m != 12; ++m) + { + pStr.clear() << pTemp << SEP << tsName << SEP << "correlation-m"; + if (m < 10) + pStr << '0'; + pStr << m << ".txt"; + + if (not CORR_MNP.loadFromCSVFile(pStr, realAreaCount, realAreaCount, Matrix<>::optImmediate|Matrix<>::optFixedSize)) + { + logs.error() << "Impossible to reload " << pStr; + continue; + } + + f << '[' << m << "]\n"; + for (uint iZ = 0; iZ < realAreaCount; ++iZ) + { + const uint i = mapping[iZ]; + const auto& col = CORR_MNP.entry[iZ]; + for (uint jZ = iZ + 1; jZ < realAreaCount; ++jZ) + { + if (not Math::Zero(col[jZ])) + { + const uint j = mapping[jZ]; + f << pArea[i]->name << '%' << pArea[j]->name << " = " << col[jZ] << '\n'; + } + } + } + f << '\n'; + } + } + } + + // Writing the index + { + IO::File::Stream f; + pStr.clear() << pTemp << SEP << tsName << SEP << "arealist.txt"; + if (f.openRW(pStr)) + { + for (uint iZ = 0; iZ != realAreaCount; ++iZ) + { + const uint i = mapping[iZ]; + f << pArea[i]->name << '\n'; + } + } + else + logs.error() << "Impossible to create " << pStr; + } + + // removing the mapping list + delete mapping; + + return true; + } + + + + + + +} // namespace Antares diff --git a/src/analyzer/atsp/load.cpp b/src/analyzer/atsp/load.cpp new file mode 100644 index 0000000000..deb1833ea5 --- /dev/null +++ b/src/analyzer/atsp/load.cpp @@ -0,0 +1,327 @@ +/* +** Copyright 2007-2018 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ +#include "atsp.h" +#include +#include "../../config.h" +#include "../../internet/limits.h" + +using namespace Yuni; + +#define SEP Yuni::IO::Separator + + + +namespace Antares +{ + + + bool ATSP::loadFromINIFile(const String& filename) + { + pArea.clear(); + pStudyFolder.clear(); + pTemp.clear(); + pTimeseriesCount = 0; + pMHeight = 0; + pTimeseries = 0; + pUseUpperBound = false; + pUseLowerBound = false; + pUpperBound = 100.; + pLowerBound = 0.; + pUpperBound80percent = 0.; + pLimitMemory = 200 * 1024 * 1024; + pAutoClean = false; + + IniFile ini; + if (ini.open(filename)) + { + logs.info() << "Reading " << filename; + + IniFile::Section* section; + CString<50, false> key; + CString<50, false> value; + + for (section = ini.firstSection; section != NULL; section = section->next) + { + if (section->name == ".general") + { + IniFile::Property* p = section->firstProperty; + for (; p != NULL; p = p->next) + { + key = p->key; + key.toLower(); + + if (key == "study") + { + pStudyFolder = p->value; + continue; + } + if (key == "temporary") + { + pTemp = p->value; + continue; + } + + value = p->value; + value.trim(" \t\r\n"); + value.toLower(); + + if (key == "target") + { + if (value == "load") + pTimeseries = Data::timeSeriesLoad; + else if (value == "solar") + pTimeseries = Data::timeSeriesSolar; + else if (value == "wind") + pTimeseries = Data::timeSeriesWind; + continue; + } + if (key == "width") + { + if (not value.to(pTimeseriesCount)) + logs.error() << "impossible to read the number of timeseries"; + continue; + } + if (key == "height") + { + if (not value.to(pMHeight)) + logs.error() << "impossible to read the height"; + continue; + } + if (key == "medium-term-autocorrelation") + { + pMediumTermAutoCorrAdjustment = value.to() / 100.; + continue; + } + if (key == "short-term-autocorrelation") + { + pShortTermAutoCorrAdjustment = value.to() / 100.; + continue; + } + if (key == "trimming") + { + pRoundOff = value.to() / 100.; + continue; + } + if (key == "upperbound-enable") + { + pUseUpperBound = value.to(); + continue; + } + if (key == "lowerbound-enable") + { + pUseLowerBound = value.to(); + continue; + } + if (key == "upperbound-value") + { + pUpperBound = value.to(); + pUpperBound80percent = pUpperBound * 0.8; + continue; + } + if (key == "lowerbound-value") + { + pLowerBound = value.to(); + continue; + } + if (key == "memory-cache") + { + pLimitMemory = value.to(); + if (pLimitMemory > 16384) + { + logs.warning() << "The limit of the memory cache size has been shrinked to 16Go"; + pLimitMemory = 16384u; // splitted into 2 parts to avoid constant out of range on Visual Studio + pLimitMemory *= 1024u * 1024u; + } + else + pLimitMemory *= 1024u * 1024u; + continue; + } + if (key == "clean") + { + pAutoClean = value.to(); + continue; + } + } + } + else + { + AreaInfo* info = new AreaInfo(); + info->name = section->name; + info->name.toLower(); + info->enabled = true; + info->distribution = Data::XCast::dtBeta; + + IniFile::Property* p = section->firstProperty; + for (; p != NULL; p = p->next) + { + key = p->key; + key.toLower(); + + if (key == "file") + { + info->filename = p->value; + continue; + } + if (key == "data") + { + key = p->value; + key.toLower(); + info->rawData = (key == "raw"); + continue; + } + if (key == "distribution") + { + info->distribution = Data::XCast::StringToDistribution(p->value); + if (info->distribution == Data::XCast::dtNone) + { + logs.error() << "invalid distribution for " << section->name << " ('beta' will be used)"; + info->distribution = Data::XCast::dtBeta; + } + continue; + } + } + + pArea.push_back(info); + if (License::Limits::areaCount and pArea.size() > License::Limits::areaCount) + return false; + } + } + + if (pMHeight < 8760 or pMHeight > 9000) + { + logs.error() << "invalid height"; + return false; + } + if (pArea.empty()) + { + logs.error() << "no area found."; + return false; + } + if (License::Limits::areaCount and pArea.size() > License::Limits::areaCount) + return false; + + + if (!checkStudyVersion()) + return false; + + logs.info() << "Target study: " << pStudyFolder; + + NBZ = (uint) pArea.size(); + NBS = pTimeseriesCount; + TDS = 1; + RTZ = pRoundOff; + code = 'W'; + switch (pTimeseries) + { + case Data::timeSeriesLoad: + TDS = 3; code = 'L'; tsName = "load"; + break; + case Data::timeSeriesSolar: + TDS = 2; code = 'S'; tsName = "solar"; + break; + case Data::timeSeriesWind: + TDS = 1; code = 'W'; tsName = "wind"; + break; + default: + TDS = -1; code = '_'; tsName = '_'; + logs.error() << "invalid timeseries type. Expected load, solar, or wind"; + return false; + } + + AUC = pShortTermAutoCorrAdjustment; + AUM = pMediumTermAutoCorrAdjustment; + + SERIE_N.resize(pTimeseriesCount, 744); + SERIE_P.resize(pTimeseriesCount, 744); + SERIE_Q.resize(pTimeseriesCount, 744); + + folderPerArea.resize(pArea.size()); + moments_centr.resize(pArea.size()); + + // Copying the INI file + pStr.clear() << pTemp << SEP << tsName << SEP << "settings.ini"; + logs.info() << " Exporting settings to " << pStr; + IO::File::Copy(filename, pStr); + + // Checking 0 < AUM < AUC < 1 + if (AUC <= 0. or AUC >= 1.) + { + logs.error() << "The short-term auto-correlation adjustment must be strictly between 0 and 1"; + return false; + } + if (AUM <= 0. or AUM >= 1.) + { + logs.error() << "The medium-term auto-correlation adjustment must be strictly between 0 and 1"; + return false; + } + if (AUC < AUM) + { + logs.error() << "The medium-term auto-correlation adjustment must be strictly less than the short-term"; + return false; + } + + return not (License::Limits::areaCount and pArea.size() > License::Limits::areaCount); + } + return false; + } + + + + bool ATSP::checkStudyVersion() const + { + auto v = Data::StudyTryToFindTheVersion(pStudyFolder, false); + switch (v) + { + case Data::versionUnknown: + { + logs.error() << "The folder is not a study"; + return false; + } + case Data::versionFutur: + { + logs.error() << "The format of the study folder requires a more recent version of Antares"; + return false; + } + default: + { + if ((uint) v != (uint) Data::versionLatest) + { + logs.error() << "The study folder must be upgraded from v" + << Data::VersionToCStr(v) << " to v" + << Data::VersionToCStr(static_cast(Data::versionLatest)); + return false; + } + } + } + return true; + } + + + + +} // namespace Antares + diff --git a/src/analyzer/atsp/misc.cpp b/src/analyzer/atsp/misc.cpp new file mode 100644 index 0000000000..cec6b871ef --- /dev/null +++ b/src/analyzer/atsp/misc.cpp @@ -0,0 +1,706 @@ +/* +** Copyright 2007-2018 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include "atsp.h" +#include +#include + + +using namespace Yuni; + + +//! Our value of PI +#define PI 3.141592653589793 + + + +namespace Antares +{ + + void ATSP::roundMatrixValues(Matrix<>& m) + { + if (pUseUpperBound) + { + for (uint x = 0; x < m.width; ++x) + { + auto& src = m.entry[x]; + for (uint y = 0; y < m.height; ++y) + { + if (src[y] > pUpperBound) + { + src[y] = pUpperBound; + ++pRoundingCount; + } + if (src[y] > pUpperBound80percent) + ++pRounding80percentCount; + } + } + pRoundingCountTotal += m.width * m.height; + } + if (pUseLowerBound) + { + for (uint x = 0; x < m.width; ++x) + { + auto& src = m.entry[x]; + for (uint y = 0; y < m.height; ++y) + { + if (src[y] < pLowerBound) + { + src[y] = pLowerBound; + ++pRoundingCount; + } + } + } + pRoundingCountTotal += m.width * m.height; + } + } + + + void ATSP::Extrait_bloc(Matrix<>& out, uint indlig, uint indcol, const Matrix<>& MTRX, + uint nblig, uint nbcol) + { + for (uint j = 0; j < nbcol; ++j) + { + auto& outcol = out.entry[j]; + const auto& srccol = MTRX.entry[j + indcol]; + for (uint i = 0; i < nblig; ++i) + outcol[i] = srccol[i + indlig]; + } + } + + + void ATSP::Colonne_moyenne(double* out, const Matrix<>& MTRX, uint nblig, uint nbcol) + { + assert(nbcol > 0 && "Invalid column count, it will produce a division by 0"); + + double d; + for (uint i = 0; i < nblig; ++i) + { + d = 0.; + for (uint j = 0; j < nbcol; ++j) + d += MTRX[j][i]; + out[i] = d / nbcol; + } + } + + + /* retourne le maximum ou le minimum de MTRX selon le code */ + void ATSP::Mtrx_bound(double& rmin, double& rmax, const Matrix<>& MTRX, uint nblig, uint nbcol) + { + rmax = -1e+30; + rmin = +1e+30; + + for (uint j = 0; j < nbcol; ++j) + { + auto& col = MTRX.entry[j]; + for (uint i = 0; i < nblig; ++i) + { + if (col[i] > rmax) + rmax = col[i]; + if (col[i] < rmin) + rmin = col[i]; + } + } + } + + + // met dans OUT la valeur absolue de MTRX + void ATSP::Mtrx_abs(Matrix<>& out, const Matrix<>& MTRX, uint nblig, uint nbcol) + { + for (uint j = 0; j < nbcol; ++j) + { + for (uint i = 0; i < nblig; ++i) + out[j][i] = Math::Abs(MTRX[j][i]); + } + } + + + // retourne la moyenne des Ă©lĂ©ments de A + double ATSP::Moyenne_generale(double* A, uint nblig) + { + double x = 0.; + for (uint i=0; i < nblig; ++i) + x += A[i]; + return x / nblig; + } + + + + // retranche de MTRX le vecteur A + void ATSP::Retranche_mtrx(Matrix<>& MTRX, const double* A, uint nblig, uint nbcol) + { + for (uint j = 0; j < nbcol; ++j) + { + Matrix<>::ColumnType& col = MTRX.entry[j]; + for (uint i = 0; i < nblig; ++i) + { + col[i] -= A[i]; + } + } + } + + + // range dans OUT les nblig première lignes de la colonne de MTRX d'indice indcol + void ATSP::Extrait_col(double* out, const Matrix<>& MTRX, uint nblig, uint indcol) + { + const Matrix<>::ColumnType& col = MTRX.entry[indcol]; + for (uint i = 0; i < nblig; ++i) + out[i] = col[i]; + } + + + // met dans A le carre de B + void ATSP::Square(double* A, const double* B, uint nblig) + { + for (uint i = 0; i < nblig; ++i) + A[i] = B[i] * B[i]; + } + + + // met (B- le scalaire x) dans A + void ATSP::Retranche_scalaire(Matrix<>& A, const Matrix<>& B, double x, uint nblig, uint nbcol) + { + for (uint j = 0; j < nbcol; ++j) + { + const Matrix<>::ColumnType& src = B.entry[j]; + auto& out = A.entry[j]; + for (uint i = 0; i < nblig; ++i) + out[i] = src[i] - x; + } + } + + + + // met (B /scalaire x) dans A + void ATSP::Divise_scalaire(Matrix<>& A, const Matrix<>& B, double x, uint nblig, uint nbcol) + { + for (uint j = 0; j < nbcol; ++j) + { + const auto& src = B.entry[j]; + auto& out = A.entry[j]; + + for (uint i = 0; i < nblig; ++i) + out[i] = src[i] / x; + } + } + + + // met dans A le cube de B + void ATSP::Cube(double* A, const double* B, uint nblig) + { + for (uint i = 0; i < nblig; ++i) + A[i] = B[i] * B[i] * B[i]; + } + + + // met dans A B^4 + void ATSP::Dsquare(double* A, const double* B, uint nblig) + { + for (uint i = 0; i < nblig; ++i) + A[i] = B[i] * B[i] * B[i] * B[i]; + } + + + // range dans OUT nblig elements de MTRX pris a partir de l'indice indlig + void ATSP::Extrait_seg(double* out, const double* src, uint nblig, uint indlig) + { + for (uint i = 0; i < nblig; ++i) + out[i] = src[i + indlig]; + } + + + + // retourne le coefficient de corrĂ©lation entre A et B (retourne 999 si paramètre "code" aberrant) + // si code = 0 : les espĂ©rances et Ă©carts-types des variables reprĂ©sentĂ©es par A et B sont Ă  calculer + // si code = 1 : des estimations des espĂ©rances et Ă©carts-types sont fournis dans EA,EB,SA,SB + double ATSP::Correlation(double* A, double* B, uint nblig, double EA, double EB, double SA, double SB, int code) + { + double sigma_A = 0.; + double sigma_B = 0.; + double expec_A = 0.; + double expec_B = 0.; + double buffer[744]; + + switch (code) + { + case 0: + { + expec_A = Moyenne_generale(A, nblig); + expec_B = Moyenne_generale(B, nblig); + + // sigma A + { + Square(buffer, A, nblig); + double x = Moyenne_generale(buffer, nblig) - expec_A * expec_A; + sigma_A = (x > 1e-9) ? sqrt(x) : 0.; + } + // sigma B + { + Square(buffer, B, nblig); + double x = Moyenne_generale(buffer, nblig) - expec_B * expec_B; + sigma_B = (x > 1e-9) ? sqrt(x) : 0.; + } + break; + } + case 1: + { + expec_A = EA; + expec_B = EB; + sigma_A = SA; + sigma_B = SB; + break; + } + default: + assert("ATSP::Correlation: invalid code"); + return 999.; // should never happen + } + + if (Math::Abs(sigma_A) < 1e-4 || Math::Abs(sigma_B) < 1e-4) + return 0.; + + double rho = 0.; + + if (code == 1) + { + for (uint i = 0; i < nblig; ++i) + rho += (A[i] - expec_A) * (B[i] - expec_B); + + rho /= nblig; + rho /= sigma_A; + rho /= sigma_B; + } + else + { + // if (code == 0) + + for (uint i = 0; i < nblig; ++i) + rho += A[i] * B[i]; + + rho /= nblig; + rho -= expec_A * expec_B; + rho /= sigma_A; + rho /= sigma_B; + } + + if (rho > 1) + rho = 1; + if (rho < -1) + rho = -1; + + return rho; + } + + + double ATSP::Ecart(double T1, double P1, double T2, double P2 , int M, double T) + { + const double R = exp(-T); + const double PP1 = autocorr_average((int)T1, M, R); + const double PP2 = autocorr_average((int)T2, M, R); + + double y = (P2 - PP2); + double x = y * y; + + y = (P1 - PP1); + x += y * y; + + return x; + } + + + double ATSP::autocorr_average(int H, int M, double R) + { + if (R < 0.) // ceci ne doit jamais se produire + { + R = 0.; + } + + double x = 0.; + for (int i = 1; i < M + 1; ++i) + { + for (int j = 1 + H; j < M + 1 + H; ++j) + x += pow(R, abs(j - i)); + } + + double y = 0.; + for (int i = 1; i < M + 1; ++i) + { + for (int j = i + 1; j < M + 1; ++j) + y += pow(R,j-i); + } + + y *= 2.; + y += M; + + return x / y; + } + + + void ATSP::Analyse_auto(double* A, int nblig, double auc, double aum, double hor, double& theta, double& mu) + { + // calcul des heures TC et TM + + // initialisation necessaire au cas ou la fonction experimentale serait aberrante + // heure pour laquelle A[TM] >= aum & A[TM+1] < aum + int TM = ((int)nblig) - 1; + // heure pour laquelle A[TC] >= auc & A[TC+1] < auc + int TC = TM / 2; + + int max_mu = 24; + + enum { dicho = 20 }; + + // cas standard ou de bonnes valeurs peuvent etre trouvees + for (int l = nblig - 2; l > -1; --l) + { + // on trouve une bonne estimation pour TM + if (A[l] >= aum && A[l+1] < aum) + TM = l; + // on trouve une bonne estimation pour TC + if (A[l] >= auc && A[l+1] < auc) + TC = l; + // on cherchera ensuite une valeur de mu comprise entre 1 et max_mu + if (A[l] >= hor && A[l+1] < hor) + max_mu = l + 1; + } + + if (max_mu > 24) max_mu = 24; + if (max_mu == 0) max_mu = 1; + + // cas ou l'autocorrelation experimentale ne decroĂ®t pas suffisamment en PRA heures + // il faut alors rectifier auc et aum puis TC et TM + if (A[nblig - 1] >= aum) + { + TM = nblig - 1; + aum = A[TM]; + TC = int(TM / 2); + auc = A[TC]; + } + + // cas ou les valeurs de auc et aum ont ete mal choisies + if (TC == TM) TC = TM - 1; + if (TC <= 0) TC = 1; + if (TM <= 1) TM = 2; + + // cas particulier ou l'autocorrelation est constante : on retourne + // directement theta =0 mu=1 + if (A[TC] == A[TM]) + { + theta = 0.; + mu = 1.; + return; + } + + // cas general : recherche des valeurs ad hoc pour T= theta et M= int(mu) + // initialisation standard + int M = 1; + double T = -log(aum) / TM; + mu = 1.; // M + theta = T; + double R = 0.; + + + // on mesure l'ecart Ă  la cible au moyen d'une fonction admissible + double delta = Ecart(double(TC), A[TC], double(TM), A[TM], M, T); + double refer = delta; + if (delta == 0) + { + // calage parfait qui ne se produira jamais en pratique + theta = T; + mu = (double) M; + return; + } + else + { + // sinon on cherche le meilleur couple (T,M )possible en testant les valeurs de + // M comprises entre 1 et max_mu et en cherchant Ă  chaque fois la valeur critique de + // R=exp(-T) pour laquelle on a : autocorr_average(int(TM),M,R) = autocorr experimentale(TM) + // on calcule ensuite la fonction d'Ă©cart et si elle est meilleure que la + // precedente, -log(R) et M deviennent + // les meilleures estimations courantes de THE et MUL + + for (int M = 1; M < max_mu + 1; ++M) + { + double top = 1; + double bot = 0; + for (int i = 1; i < dicho + 1; ++i) + { + R = (top + bot) / 2; + if (autocorr_average(TM,M,R) >= A[TM]) + top = R; + else + bot = R; + } + + // on a converge vers R tq autocorr_average(TM,M,R) = A[TM] + delta = Ecart(double(TC), A[TC], double(TM), A[TM], M, -log(R)); + if (delta < refer) + { + mu = M; + theta = -log(R); + refer = delta; + } + } + } + } + + + + double ATSP::GammaEuler(double z) + { + // checking for parameter validity + if (Yuni::Logs::Verbosity::Debug::enabled) // static check + { + // in Debug mode, it would be easier to assert the condition + // (gdb) + assert((z > 0. && z <= 100.) && "error in the Gamma function (invalid parameter)"); + } + else + { + if (z <= 0. || z > 100.) + { + logs.error() << "Internal error in the Gamma function (invalid parameter)"; + return 0.; + } + } + + enum + { + g = 6, + }; + double x; + const double t = z + double(g) + 0.5; + double rho; + static const double p[9] = + { + 0.99999999999980993, 676.5203681218851, -1259.1392167224028, + 771.32342877765313, -176.61502916214059, 12.507343278686905, + -0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7 + }; + + if (z < 0.5) + { + z = 1. - z; + rho = PI / sin(PI * z); + z -= 1.; + x = p[0]; + + for (int i = 1; i < g + 3; ++i) + { + x += p[i] / (z + double(i)); + } + //x = 1. / (sqrt(2. * PI) * pow(t, z + 0.5) * exp(-t) * x); + x = 1. / (2.506628275 * pow(t, z + 0.5) * exp(-t) * x); + } + else + { + rho = 1.; + z -= 1.; + x = p[0]; + + for (int i = 1; i < g + 3; ++i) + { + x += p[i] / (z + double(i)); + } + //x = sqrt(2. * PI) * pow(t, z + 0.5) * exp(-t) * x; + x = 2.506628275 * pow(t, z + 0.5) * exp(-t) * x; + } + + return (rho * x); + } + + + + // ajustement de la densitĂ© de probabilitĂ© en fonction des bornes L, U, de l'espĂ©rance E et de l'Ă©cart-type S + // selon une loi "type" : calcule alpha=A, beta = B, gamma = C, delta = D + // retourne 0 si le calage est possible et 1 sinon */ + bool ATSP::Probab_density_funct(double L, double U, double E, double S, + Data::XCast::Distribution law, double& A, double& B, double& C, double& D) + { + enum { dicho = 20 }; + + A = 1.; + B = 1.; + C = 0.; + D = 1.; + + if (Math::Abs(S) < 1e-40) + { + double fe = Math::Abs(E); + S = (fe < 1e-40) ? (1e-4) : (1e-4 / fe); + } + + switch (law) + { + case Data::XCast::dtUniform: + { + if (S < 0.) + return false; + // au lieu de prendre simplement C=L et D=U, on procede + // par la methode des moments + C = (2. * E - 3.4641 * S) / 2.; + D = (2. * E + 3.4641 * S) / 2.; + A = L; + B = U; + + // (note : si le calage est plausible on doit avoir A proche de + // C et B proche de D ... ) + return true; + } + + case Data::XCast::dtBeta: + { + if (U <= L) + return false; + C = L; + D = U; + double V = E - C; + double W = D - C; + if (S == W) + return false; + + A = ( V / W) * (V / W * (1. - (V / W)) / ((S * S) / (W * W)) - 1.); + B = (1. - V / W) * (V / W * (1. - (V / W)) / ((S * S) / (W * W)) - 1.); + return (A > 0. && B > 0.); + } + + case Data::XCast::dtNormal: + { + if (S < 0.) + return false; + C = 0.; + D = 0.; + A = E; + B = S; + return true; + } + + case Data::XCast::dtWeibullShapeA: + { + if (S < 0.) + return false; + + // Since 3.5: No translation + // E = E - L; + + if (E == 0 || S == 0) + return false; + // pour une loi de weibull de paramètre a>=1, le calage n'est possible que si + // S/E < 1 + if (S / E > 1.) + return false; + + double bot = 1.; + double top = 50.; + + double cible = S/E; + cible *= cible; + + // Since 3.5, C = 0 + // C = L; + C = 0; + + D = 0; // D n'est pas utilise par le generateur stochastique + double a; + double g; + for (uint i = 1; i < dicho + 1; ++i) + { + a = (top + bot) / 2.; + g = GammaEuler(1. + 1. / a); + g = g * g; + double niveau = GammaEuler(1. + 2. / a) - g; + niveau /= g; + if (niveau >= cible) + bot = a; + else + top = a; + } + A = a; + B = E / GammaEuler(1. + 1. / a); + + // calage mathematiquement possible mais hors des limites antares + return ! (A < 1. || A > 50.); + } + + case Data::XCast::dtGammaShapeA: + { + if (S <= 0.) + return false; + + // Since 3.5, no translation + // E = E - L; + + if (E == 0.) + return false; + + // Since 3.5, C = 0 + // C = L; + C = 0; + + D = 0; // D n'est pas utilise par le generateur stochastique + A = (E / S); + A *= A; + // Since 3.5, B' = 1/B, it was B = A / E + // Now : + B = E / A; + + return ! (A < 1. || A > 50.); + } + + case Data::XCast::dtNone: + case Data::XCast::dtMax: + break; + } + + return false; + } + + + double ATSP::Standard_shrinkage(int M, double R) + { + if (R < 0.) // ceci ne doit jamais se produire + R = 0.; + + double x = 0.; + for (int i = 1; i < M + 1; ++i) + { + for (int j = i + 1; j < M + 1; ++j) + x += pow(R, j - i); + } + + x *= 2; + x += M; + x /= (M * M); + x = sqrt(x); + + return x; + } + + + + + +} // anonymous namespace diff --git a/src/analyzer/atsp/preflight.cpp b/src/analyzer/atsp/preflight.cpp new file mode 100644 index 0000000000..e116f1c0c3 --- /dev/null +++ b/src/analyzer/atsp/preflight.cpp @@ -0,0 +1,463 @@ +/* +** Copyright 2007-2018 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include "atsp.h" +#include +#include + + +using namespace Yuni; + + +#define SEP Yuni::IO::Separator + + +namespace Antares +{ + + + bool ATSP::preflight() + { + logs.info(); + logs.checkpoint() << "Extracting coefficients"; + + // Preparing folders + logs.info() << "Preparing folders..."; + { + uint error = 0; + for (uint i = 0; i != pArea.size(); ++i) + { + String& folder = folderPerArea[i]; + folder.clear() << pTemp << SEP << tsName << SEP << (i / 256) << SEP << pArea[i]->name; + if (!IO::Directory::Create(folder)) + { + logs.error() << "impossible to create the directory " << folder; + if (++error > 10) // try all folders before aborting + { + logs.info() << "Too many errors. Aborting now."; + return false; + } + } + } + if (error) + return false; + } + + logs.info(); // empty line + + pEnabledAreaCount = 0; + for (uint i = 0; i != pArea.size(); ++i) + { + if (!preflight(i)) + { + pArea[i]->enabled = false; + logs.info() << " The area '" << pArea[i]->name << "' has been removed"; + } + else + ++pEnabledAreaCount; + } + + // moments + writeMoments(); + + // Statistics + logs.info(); // empty line + if (pUseUpperBound || pUseLowerBound) + { + logs.info() << " Summary:"; + logs.info() << ' ' << pTimeseriesCount << " timeseries"; + logs.info() << ' ' << pRoundingCount << " values / " << pRoundingCountTotal << " out of bounds (" + << (100. * pRoundingCount / pRoundingCountTotal) << "%)"; + if (pUseUpperBound) + { + logs.info() << " " << pRounding80percentCount << " values above 80% of the upper bound (" + << (100. * pRounding80percentCount / pRoundingCountTotal) << "%)"; + } + logs.info(); // empty line + } + + return (pEnabledAreaCount > 0); + } + + + + bool ATSP::preflight(const uint areaIndex) + { + // Alias to the current area info + const AreaInfo& info = *(pArea[areaIndex]); + // The folder for the current area + const String& folder = folderPerArea[areaIndex]; + + // log + logs.info() << "Coefficients: area " << (1+areaIndex) << '/' << pArea.size() + << ": " << info.name; + + + // Reading the matrix file for the current area + Matrix<> MTRX; + if (!MTRX.loadFromCSVFile(info.filename, 1, pMHeight, Matrix<>::optImmediate)) + return false; + // Shrinking the matrix if required + if (MTRX.width > pTimeseriesCount) + MTRX.resizeWithoutDataLost(pTimeseriesCount, MTRX.height); + else + { + if (MTRX.width < pTimeseriesCount) + { + logs.error() << "not enough timeseries for the area '" << info.name << "'"; + return false; + } + } + + // Round values + roundMatrixValues(MTRX); + + // Matrix used for writing data + Matrix<> mtrxWriter; + // Modulation + Matrix<> modulation(12, 24); + + // Initializing non standardized bounds + double minimu_brut[12]; + double maximu_brut[12]; + for (uint j = 0; j != 12; ++j) + { + minimu_brut[j] = +1e+30; + maximu_brut[j] = -1e+30; + } + + // Series de coefficients d'autocorrelation, en pratique seuls + // les PRA premières valeurs sont utilisĂ©es + double AUTO_ESTIM1[744]; + // les deux estimations convergent pour des series infinies + double AUTO_ESTIM2[744]; + + // col 1=alpha 2= beta 3=gamma 4=delta 5=theta 6=mu + double stocha_values[12][6]; + + // traitement des donnees brutes avec decoupage mensuel, normalisation + // et copie locale (ces copies sont a ranger dans user/ wind,solar,load/ "areaname.txt") + for (uint j = 0; j != 12; ++j) + { + // Alias to the stochastics values of the month + double* stocha = stocha_values[j]; + double* moments_centr_mois = moments_centr[areaIndex].data[j]; + + Extrait_bloc(SERIE_N, posmois[j], 0, MTRX, durmois[j], NBS); + + // si on travaille avec les donnees brutes on les recopie et la serie de + // translation vaut zero, sinon on calcule la moyenne pluis les ecarts + if (!info.rawData) + { + // buffer_n will be reseted. No need to initialize it with memset. + Colonne_moyenne(buffer_n, SERIE_N, durmois[j], NBS); + Retranche_mtrx(SERIE_N, buffer_n, durmois[j], NBS); + } + else + (void)::memset(buffer_n, 0, sizeof(buffer_n)); + + + // buffer_n contient la serie de translation et SERIE_N les donnees Ă  normaliser + pStr.clear() << folder << SEP << "translation-m"; + if (j < 10) + pStr << '0'; + pStr << j << ".txt"; + // To reduce the size of each file, and consequently speed-up their loading + // we will use the standard matrix of Antares, which perform a lot of + // optimization when writing to a file. + mtrxWriter.resize(1, durmois[j]); + mtrxWriter.pasteToColumn(0, buffer_n); + if (!mtrxWriter.saveToCSVFile(pStr, 3)) + return false; + + // On calcule les valeurs extrĂŞmes du processus brut + Mtrx_bound(minimu_brut[j], maximu_brut[j], SERIE_N, durmois[j], NBS); + + // On calcule ensuite les coefficients horaires de modulation pour le mois courant + { + Mtrx_abs(SERIE_P, SERIE_N, durmois[j], NBS); + Colonne_moyenne(buffer_p, SERIE_P, durmois[j], NBS); + const double expect = Moyenne_generale(buffer_p, durmois[j]); + double ratios[24]; + + for (uint n = 0; n < 24; ++n) + { + double d = 0; + for (uint m = 0; m < lonmois[j]; ++m) + d += (buffer_p[24 * m + n] / lonmois[j]); + ratios[n] = d / expect; + } + modulation.pasteToColumn(j, ratios); + + // il faut normaliser les series avant de les reecrire + for (uint n = 0; n < durmois[j]; ++n) + { + const uint mod = n % 24; + for (uint m = 0; m < NBS; ++m) + { + if (ratios[mod] != 0) + SERIE_N.entry[m][n] /= ratios[mod]; + } + } + } + + // copie locale des donnees mormalisees dans study/user/wind,solar,load/ ... + { + pStr.clear() << folder << SEP << "userfile-m"; + if (j < 10) + pStr << '0'; + pStr << j << ".txt"; + SERIE_N.height = durmois[j]; + if (!SERIE_N.saveToCSVFile(pStr, 3)) + return false; + + SERIE_N.height = 744; // restore the previous value + } + + + // calcul de l'esperance, de la variance et des valeurs extremes pour la + // zone et le mois + double expect_global = 0.; + double varian_global = 0.; + // premiere boucle sur les sĂ©ries pour calcul des esperances et variances + for (uint m = 0; m < NBS; ++m) + { + Extrait_col(buffer_n, SERIE_N, durmois[j], m); + expect_global += Moyenne_generale(buffer_n,durmois[j]) / NBS; + + Square(buffer_p, buffer_n, durmois[j]); + varian_global += Moyenne_generale(buffer_p,durmois[j]) / NBS; + } + + double variance = varian_global - expect_global*expect_global; + if (variance < 0.) + variance = 0.; // si bruit numerique + const double standard = sqrt(variance); + + + // calcul des moments d'ordre 3 et 4 + double skewne_global = 0.; + double kurtos_global = 0.; + + // passage aux valeurs centrees reduites si l'ecart-type n'est pas nul + if (standard > 0.) + { + Retranche_scalaire(SERIE_P,SERIE_N,expect_global,744,NBS); + Divise_scalaire(SERIE_Q,SERIE_P, standard, 744, NBS); + + // seconde boucle sur les series pour calcul des skewness et kurtosis + for (uint m = 0; m < NBS; ++m) + { + Extrait_col(buffer_n,SERIE_Q,durmois[j],m); + Cube(buffer_p,buffer_n,durmois[j]); + skewne_global += Moyenne_generale(buffer_p, durmois[j]) / NBS; + + Dsquare(buffer_p, buffer_n, durmois[j]); + kurtos_global += Moyenne_generale(buffer_p, durmois[j]) / NBS; + } + } + + // mise a jour du tableau general des moments (NBZ X 12 X 4) + moments_centr_mois[0] = expect_global; + moments_centr_mois[1] = standard; + moments_centr_mois[2] = skewne_global; + moments_centr_mois[3] = kurtos_global - 3; + + // Calcul des autocorrelations a l'aide de deux estimateurs AUTO_ESTIM1 + // (pour theta) et AUTO_ESTIM2 (pour mu). + // + // AUTO_ESTIM1 et AUTO_ESTIM2 convergent vers des valeurs identiques pour + // des series longues et nombreuses + (void)::memset(AUTO_ESTIM1, 0, sizeof(AUTO_ESTIM1)); + (void)::memset(AUTO_ESTIM2, 0, sizeof(AUTO_ESTIM2)); + + AUTO_ESTIM1[0] = 1.; // autocorrelation (Xt, Xt + 0) = 100% + AUTO_ESTIM2[0] = 1.; // autocorrelation (Xt, Xt + 0) = 100% + + for (uint m = 0; m < NBS; ++m) + { + Extrait_col(buffer_n, SERIE_N, durmois[j], m); + Extrait_seg(buffer_p, buffer_n, durmois[j], 0); + + // commence a 1 car AUTOCOR[0] deja calcule + for (uint n = 1; n < PRA; ++n) + { + Extrait_seg(buffer_q,buffer_n,durmois[j]-(n+1),n); + + // les correlations de chaque paire (buffer_n, buffer_q) + // pour chacune des NBS sĂ©ries contribuent Ă  la corrĂ©lation (X0,X0+n)*/ + // + // 20/07/2010 : on inhibe le calcul de AUTO_ESTIM1 car toujours moins bon + // que ESTIM2 dans sa formulation actuelle + + // xx = Correlation(buffer_p,buffer_q,durmois[j]-(n+1),moments_centr[i][j][0],moments_centr[i][j][0],moments_centr[i][j][1],moments_centr[i][j][1],1); + double yy = Correlation(buffer_p, buffer_q, durmois[j] - (n + 1), 0, 0, 0, 0, 0); + // AUTO_ESTIM1[n] += xx/NBS; + AUTO_ESTIM2[n] += yy / NBS; + } + } + + + // identification de theta et mu. + // On tient compte de HOR si on n'analyse pas une loi normale + if (info.distribution != Data::XCast::dtNormal) + Analyse_auto(AUTO_ESTIM2, PRA, AUC, AUM, (double)HOR, stocha[4], stocha[5]); + else + Analyse_auto(AUTO_ESTIM2, PRA, AUC, AUM, 0, stocha[4], stocha[5]); + + // On constate que ESTIM2 conduit Ă  surĂ©valuer theta, on corrige le biais + // avec une fonction empirique + if (stocha[4] > 0.002) + stocha[4] -= 0.04 * sqrt(stocha[4]); + + // si mu>1 il faut majorer l'ecart-type observe sur les valeurs lissees + // pour remonter a l'ecart-type des valeurs des series non-lissees + double standard_majore = (Math::Abs(stocha[5] - 1.) < 1e-6) + ? standard + : standard / Standard_shrinkage((int)stocha[5], exp(-stocha[4])); + + // identification des alpha, beta, gamma, delta + if (!Probab_density_funct(minimu_brut[j], maximu_brut[j], expect_global, standard_majore, + info.distribution, stocha[0], stocha[1], stocha[2], stocha[3])) + { + logs.error() << "Area " << info.name << ", month " << (j + 1) + << ": fitting impossible for the chosen type of law"; + return false; + } + + } // each month + + + // Monthly Modulation coefficients + { + logs.info() << " Exporting daily profile"; + pStr.clear() << folder << SEP << "diurmodulation.txt"; + modulation.saveToCSVFile(pStr); + pStr.clear() << pStudyFolder << SEP << "input" << SEP << tsName + << SEP << "prepro" << SEP << info.name << SEP << "k.txt"; + // pStr.clear() << folder << SEP << "diurmodulation.txt"; + modulation.saveToCSVFile(pStr); + } + + // Coefficients + { + // ecriture du bloc des parametres des lois marginales + MTRX.resize(6, 12); + for (uint x = 0; x != 6; ++x) + { + auto& out = MTRX[x]; + for (uint y = 0; y != 12; ++y) + out[y] = stocha_values[y][x]; + } + + // Override MU coefficients, to have mu [1..23], and not 24 + auto& mu = MTRX[Data::XCast::dataCoeffMu]; + for (uint y = 0; y != 12 /*MTRX.height*/; ++y) + { + if (mu[y] > 23.f) + mu[y] = 23.f; + } + + logs.info() << " Exporting coefficients"; + pStr.clear() << folder << SEP << "stochpara.txt"; + MTRX.saveToCSVFile(pStr); + + pStr.clear() << pStudyFolder << SEP << "input" << SEP << tsName + << SEP << "prepro" << SEP << info.name << SEP << "data.txt"; + MTRX.saveToCSVFile(pStr); + } + + // Conversion + logs.info() << " The conversion will be disabled but the data will remain untouched."; + + // Translation + { + logs.info() << " Exporting translation data"; + mtrxWriter.reset(1, 8760); + + uint y = 0; + for (uint m = 0; m != 12; ++m) + { + pStr.clear() << folder << SEP << "translation-m"; + if (m < 10) + pStr << '0'; + pStr << m << ".txt"; + + if (!MTRX.loadFromCSVFile(pStr, 1, durmois[m], Matrix<>::optImmediate|Matrix<>::optFixedSize)) + { + logs.error() << "Impossible to reload " << pStr; + continue; + } + + auto& src = MTRX[0]; + auto& dst = mtrxWriter[0]; + for (uint j = 0; j != MTRX.height; ++j) + { + dst[y] = src[j]; + ++y; + } + } + + pStr.clear() << pStudyFolder << SEP << "input" << SEP << tsName + << SEP << "prepro" << SEP << info.name << SEP << "translation.txt"; + if (!mtrxWriter.saveToCSVFile(pStr)) + logs.error() << "Impossible to write " << pStr; + } + + // Settings for the TS generator (XCast) + { + logs.info() << " Updating the TS-Generator settings"; + pStr.clear() << pStudyFolder << SEP << "input" << SEP << tsName + << SEP << "prepro" << SEP << info.name << SEP << "settings.ini"; + IO::File::Stream f; + if (!f.open(pStr, IO::OpenMode::write | IO::OpenMode::truncate)) + logs.error() << "Impossible to create " << pStr; + else + { + // Example : [general] + // distribution = Beta + // capacity = 0.000000 + // conversion = false + // translation = never + // + f << "[general]" + << "\ndistribution = " << Data::XCast::DistributionToNameID(info.distribution) + << "\ncapacity = 1" + << "\nconversion = false"; + if (info.rawData) + f << "\ntranslation = never\n"; + else + f << "\ntranslation = before-conversion\n"; + } + } + + return true; + } + + + +} // namespace Antares diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp new file mode 100644 index 0000000000..494b4bf60d --- /dev/null +++ b/src/analyzer/main.cpp @@ -0,0 +1,208 @@ +/* +** Copyright 2007-2018 RTE +** Authors: Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ + +#include +#include +#include +#include "../ui/common/winmain.hxx" +#include +#include +#include +#include "atsp/atsp.h" +#include +#include +#include +#include +#include "../config.h" +#include "../internet/license.h" + +using namespace Yuni; +using namespace Antares; + + +# define SEP Yuni::IO::Separator + + + + + +static bool OpenLogFilename(const String& optSettings) +{ + IniFile ini; + if (not ini.open(optSettings)) + { + logs.fatal() << "impossible to open " << optSettings; + return false; + } + auto* section = ini.find(".general"); + if (!section) + { + logs.fatal() << "invalid map structure (section not found): " << optSettings; + return false; + } + auto* property = section->find("study"); + if (!property || !property->value) + { + logs.fatal() << "invalid map structure (no study specified): " << optSettings; + return false; + } + String filename; + filename << property->value << SEP << "logs"; + + // Date/time + char nowstr[128]; + time_t nowbin; + struct tm nowstruct; + + time(&nowbin); + # ifdef YUNI_OS_MSVC + localtime_s(&nowstruct, &nowbin); + # else + nowstruct = *localtime(&nowbin); + # endif + size_t result = strftime(nowstr, sizeof(nowstr), "%Y%m%d-%H%M%S", &nowstruct); + if (result == 0) + { + logs.error() << "[output] Could not get string from strftime()"; + nowstr[0] = '\0'; + } + else + nowstr[result] = '\0'; + + filename << SEP << "analyzer-" << (const char*) nowstr << ".log"; + + // Assigning the log filename + logs.logfile(filename); + + if (not logs.logfileIsOpened()) + { + logs.error() << "Impossible to open " << filename; + return false; + } + return true; +} + + + + +static void NotEnoughMemory() +{ + logs.fatal() << "Not enough memory. aborting."; + exit(42); +} + + + + +int main(int argc, char* argv[]) +{ + // Dealing with the lack of memory + std::set_new_handler(&NotEnoughMemory); + + // Swap memory + if (not memory.initialize()) + return EXIT_FAILURE; + + // locale + InitializeDefaultLocale(); + + logs.applicationName("analyzer"); + argv = AntaresGetUTF8Arguments(argc, argv); + + String optSettings; + + // Command Line options + { + // Parser + GetOpt::Parser options; + // + options.addParagraph(Yuni::String() + << "Antares Study Analyzer v" << Antares::VersionToCString() << "\n"); + // Input + options.remainingArguments(optSettings); + // Output + options.add(optSettings, 'i', "input", "INI file which contains the settings"); + + // Version + bool optVersion = false; + options.addFlag(optVersion, 'v', "version", "Print the version and exit"); + + if (!options(argc, argv)) + return options.errors() ? 1 : 0; + + if (optVersion) + { + Antares::PrintVersionToStdCout(); + return 0; + } + } + + + if (optSettings.empty()) + { + logs.fatal() << "No settings file. Aborting."; + return 1; + } + + if (!OpenLogFilename(optSettings)) + return 1; + + // Starting ! + logs.checkpoint() << "Antares Analyzer v" << Antares::VersionToCString(); + WriteHostInfoIntoLogs(); + # ifdef ANTARES_BENCHMARK + logs.info() << " :: Built with benchmark support"; + # endif + logs.info(); + logs.info() << "Log filename: " << logs.logfile(); + + + // Load the local policy settings + LocalPolicy::Open(); + LocalPolicy::CheckRootPrefix(argv[0]); + + // ASTP + // note : ASTP must be destroyed before the variable logs + { + ATSP atsp; + // Load global settings + per area + if (atsp.loadFromINIFile(optSettings)) + { + // Print a summary of the global settings + atsp.printSummary(); + // Prepare data + if (atsp.preflight()) + atsp.computeMonthlyCorrelations(); // monthly correlations + } + } + + logs.info(); + logs.info() << "Done."; + + return 0; +} + diff --git a/src/analyzer/win32/analyzer.ico b/src/analyzer/win32/analyzer.ico new file mode 100644 index 0000000000..def2df809b Binary files /dev/null and b/src/analyzer/win32/analyzer.ico differ diff --git a/src/analyzer/win32/analyzer.rc.cmake b/src/analyzer/win32/analyzer.rc.cmake new file mode 100644 index 0000000000..4037b3f09f --- /dev/null +++ b/src/analyzer/win32/analyzer.rc.cmake @@ -0,0 +1,32 @@ +// note that the icon used by the Explorer (i.e. the programs icon) is the +// first icon in the executable and the icons are sorted both by their order +// (Win9x) and by alphabetically (!) (NT), so put this icon first and give it +// a name starting with "a" +aaaaa ICON "win32/analyzer.ico" + +1 VERSIONINFO +FILEVERSION @ANTARES_VERSION_HI@,@ANTARES_VERSION_LO@,@ANTARES_VERSION_REVISION@,0 +PRODUCTVERSION @ANTARES_VERSION_HI@,@ANTARES_VERSION_LO@,@ANTARES_VERSION_REVISION@,0 + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "@ANTARES_PUBLISHER@" + VALUE "FileDescription", "Antares Study Analyzer v@ANTARES_VERSION_HI@.@ANTARES_VERSION_LO@.@ANTARES_VERSION_REVISION@" + VALUE "FileVersion", "@ANTARES_VERSION_HI@.@ANTARES_VERSION_LO@.@ANTARES_VERSION_REVISION@" + VALUE "InternalName", "Antares Study Analyzer" + VALUE "LegalCopyright", "@ANTARES_PUBLISHER@" + VALUE "OriginalFilename", "antares-analyzer-@ANTARES_VERSION_HI@.@ANTARES_VERSION_LO@.exe" + VALUE "ProductName", "Antares Study Analyzer" + VALUE "ProductVersion", "@ANTARES_VERSION_HI@.@ANTARES_VERSION_LO@.@ANTARES_VERSION_REVISION@" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + diff --git a/src/changelog.mdown b/src/changelog.mdown new file mode 100644 index 0000000000..6228f4408e --- /dev/null +++ b/src/changelog.mdown @@ -0,0 +1,690 @@ + +Antares Changelog +================= + + +v6.0.0 (04/2017) +---------------- + +### Features + + - GUI: A new interface makes it possible to define several views (maps) of + the Power System modelled in an Antares study. These maps are meant to give + the user the ability to set different layouts in which each Antares Area + or Link can be either shown or remain hidden. Accordingly, all input and + output data windows can now adapt the information displayed so as to match + exactly the content of any given map. Copy/Paste functions have been + extended so as to work between different maps of different studies opened + in multiple Antares sessions + + - Simulation: Introduction of a flexible multi-threaded mode for the processing + of heavy problems: Antares “Monte-Carlo years” can be be distributed on a + number of CPU cores freely set by the user. This parameter appears as a new + tunable item of the “advanced parameters” list attached to any Antares Study. + Five values are available in the [1, N] interval, N being the number of CPU + cores of the machine (virtual or physical) Antares is run on + + - License control through the internet: a new system has been developed for + accommodating situations where users wish to operate Antares on a large + fleet of machines among which a limited set of commercial license tokens + can float freely + + - Data organizer: Antares studies often include a great number of files of + all sizes, which may take long to process when multiple copies are needed. + Likewise, the management of the HDD space required for regular storage of + all of the studies involved in a complex study workflow may turn out to be + a demanding and heavy task. To save both time and hardware resources, the + Antares Data Organizer, now provided as a companion tool to the Antares + Simulator, brings the ability to schedule basic data management tasks + such as study archiving/expansion (use of a specific compressed format), + copy to backup folders, registering of studies and archives in catalogues. + + +v5.0.9-SE (04/2017) +---------------- + +### Bug fixes + + - Random noises on thermal clusters costs now include the zero-cost + "must-run" clusters (as a consequence, noises assumptions do not vary + with the cluster status) + + - Fixing an initialization issue that could sporadically affect the + minimum number of committed thermal units (+1 or -1 deviation, + "accurate" mode only) + +v5.0.7-SE (04/2017) +---------------- + +### Features + + - License control : management of SSL certificates encrypted through SHA-256 algorithm + + +v5.0.7 (12/2016) +---------------- + +### Bug fixes + + - Fixing a packaging error + + +v5.0.6 (12/2016) +---------------- + +### Bug fixes + + - Results processing: For full "must-run" thermal clusters, the NODU variable + could be wrongly assessed in the "accurate" unit commitment simulation mode + + - GUI: when the scenario builder feature is active, saving right after deleting + a thermal cluster could result in a partial dataset corruption (references to + the deleted object were kept alive in the scenario builder context) + + +### Features + + - Unsupplied energy control: if the actual economic optimization requires it, load + shedding is now allowed to occur in areas where the available thermal generation + is higher than the local demand (e.g. if local VOLL < local thermal costs) + + - Linear solver, hot starting of weekly problems: in the "fast" unit commitment + mode, optimal bases are flushed at the beginning of each Monte-Carlo year. This + comes as a pre-requirement for the next versions of Antares, which will be + fully multi-threaded + + - Simulation results: code segments processing all variables attached to spatial + aggregates, and the variable representing the number of running thermal units + on the first hour of the year, were re-written to be compatible with the next + versions of Antares, which will be fully multi-threaded + + + +v5.0.5 (08/2016) +---------------- + +### Bug fixes + + - No-Load Heat costs and Start-up costs: in the "fast" unit commitment options, + the result was slightly below the actual optimal possible cost for some + datasets (i.e. datasets in which the thermal cluster coming last in alphabetic + order had a minimum stable power equal to zero). + + - Spilled energy control: the three parameters defining how energy in excess should + be split between the different possible sources when there is a choice to make + can work properly again (feature inhibited in previous 5.0.x versions) + + +### Features + + - License control throughout the internet: all combinations of UTF8 characters can + now be used within proxy ids and passwords + + - Economic optimization: in an area where the amount of available thermal power + exceeds that of load, the fact that the demand should necessarily be served + is locally expressed as a constraint of the optimization problem (LOLE=0) + + +v5.0.4 (05/2016) +---------------- + +### Bug fixes + + - Errors occured on loading the "min gen modulation" time-series of thermal clusters + +### Features + + - Better estimate of the number of thermal units dispatched in "fast" unit commitment mode + - Nodal Marginal Prices and Marginal yield on interconnections are now available in + "accurate" unit commitment mode + - Binding constraints including offset parameters: unbounded positive or + negative values can be used for all classes of constraints (hourly, daily, weekly) + + +v5.0.3 (05/2016) +---------------- + +### Bug fixes + + - Crashes occured when the "full must-run status" parameter was set on + "true" for thermal clusters + + +v5.0.2 (04/2016) +---------------- + +### Bug fixes + + - Removed debug information that should not be displayed in release mode + +### Features + + - The optimization criterion used to assess the hydro energies to generate throughout + each month incorporates heavier penalization terms for the 12 deviations from the + theoretical monthly targets (formerly, only the largest deviation was penalized). + + +v5.0.1 (04/2016) +---------------- + +### Bug fixes + + - Adequacy mode: fixed a memory allocation bug that forced the post-simulation + output files processing to be interrupted + + - In the previous version, additional logs were added. That could lower the simulation + performances in some cases. This problem is now solved. + + +v5.0.0 (03/2016) +---------------- + +### Bug fixes + + - GUI, system map: copy /paste of binding constraints could alter the activity status or + the names of the duplicated binding constraints in some instances + + - GUI, system map: some conflicts in copy/paste actions were not always properly raised + (e.g. attempt to copy three nodes and paste them on two other nodes) + + - Thermal clusters: Improved checking of time-series generation parameters (improper use of a + nominal capacity modulation factor lower than the minimum stable power is no longer possible) + + - Thermal clusters: Improved checking of ready-made time-series. If the user-chosen time-series + are not consistent with the parameters set in the GUI, warnings are issued in log files + + - Output , LOLD variable: in some instances, the values assessed in "economic" simulation mode and in + "adequacy" simulation mode could slightly differ because of sporadic rounding side-effects. + rounding convention is now set uniformly to : 0 < X < 0.5 -> (X=0) + + - Output, MISC.NDG and PSP variable: values were not properly edited for the specific category + "geographic districts, "year-by-year results" + + - Output, OV. COST, OP. COST, NP. COST variables: values were not properly edited for the last + hour of the last day of the simulation + + - Output, File comparison functions: calendar marks were not properly displayed in some views + + - Output, File comparison functions: "Max" operator has been added + + +### Features + + - Optimization: introduction of a new unit-commitment mode based on a MILP approach slower but more + accurate than the former one. An option lets the user choose which mode should be used (fast/accurate) + + - Optimization: in "accurate" unit-commitment mode, incorporation of thermal start-up costs and + no-load heat costs within the global objective function to minimize. In "fast" unit-commitment + mode, start-up costs and no-load heat costs are minimized independently from the main objective + + - Optimization: in both unit-commitment modes, improvement of the inter-weekly start-up strategies + (seamless reformulation of the optimization results obtained beforehand) + + - Thermal clusters: definition of separate minimum up/down durations to be used for unit-commitment + + - Thermal clusters: definition of a minimum amount of power (hourly time-series) to be generated + by the units of the cluster, regardless of economic considerations (partial must-run commitment) + + - Thermal clusters: start-up cost can now be set from -5000000 to 5000000 (was from -50000 to 50000) + + - Binding constraints: introduction of new "offset" parameters which make it possible to define + constraints whose terms can refer to different times (e.g. 2 X(t) - 1.5 Y(t-4) + 3 Z(t+1) <10) + + - Benchmarking: so as to allow transparent comparisons with other software, the user may demand + that all optimization problems solved by Antares be printed in a standardized "mps" format + along with the values of the optimized criterion. + + - GUI, System map : new button available in the tool bar for centring the map on a (x,y) location + + - GUI, System map : new button available in the tool bar for map trimming around used space + + - Output: In synthetic Monte-Carlo results,year-by-year results and cluster-by-cluster results, + Addition of a field "Number of dispatched units" (NODU) + + + +v4.5.4 (03/2015) +---------------- + +### Bug fixes + + - License checking: internet proxys for which no login and/or password have been + defined can now be used + + - Upgrade to 4.5 format of datasets edited in 4.4 format or lower, in which the "scenario builder" + feature was activated: the conversion to 4.5 format could fail sometimes. + +v4.5.3 (02/2015) +---------------- + +### Features + + - Start-up and fixed thermal costs: the interpretation of the unit-commitment strategy + (starting-up and shutting-down times of each thermal unit) includes the explicit + minimization of the total sum of start-up costs and fixed costs (in previous versions, + units were called on as late as possible and called off as soon as possible) + + + - Various improvements in the linear solver yielding some speed increase in hard cases + + + - Control of license validity through the internet (setting up of a dedicated server) + + +### Bug fixes + + - Scenario builder: indices not subject to random draws could be mixed up in areas + including both "must-run" units and "regular" units (bug circumscribed to the thermal + time-series section) + + - Spillage management, when numerous binding constraints are active: an excessive leeway + could be observed regarding the level of hydro power allowed to be curtailed + +v4.5.2 (06/2014) +---------------- + +### Bug fixes + + - In the previous version, the average values of interconnection-related variables were multiplied by two + and this error was propagated to the standard deviation of the same variables + +v4.5.1 (06/2014) +---------------- + +### Features + + - Start-up and fixed thermal costs: the contribution of each thermal cluster to the operating + cost is now explicitly displayed in the results (field : "non proportional cost") + + + - Load time-series : negative values are now authorized + + + + +### Bug fixes + + - Creation of a thermal cluster : the default value of the NPOMAX parameter is set to 100 + + + - Hydro energy spatial allocation matrix : values are displayed more clearly in the GUI + + + - Copy/paste of nodes : the field "spread on unsupplied energy cost" was not pasted + + +v4.5.0 (04/2014) +---------------- + +### Features + + - Simplex solver: acceleration regarding the control of the admissibility of the solution + in the dual stages. This brings a significant improvement of the calculation time for + large problems in which the relative scale of system costs is very wide + + + - Identical upper and lower bounds have been set for the absolute values of all + non-zero system costs ( max = 5 10^4 €/MWh ; min = 5 10^-3 €/MWh) + + +### Bug fixes + + - Hydro Time-series generation : the GUI did not react properly when forbidden + values (negative) were seized for energy expectation and/or standard deviation + + + - Unit commitment of thermal plants: the time of the first activation of a plant + within a week was not fully optimized + + +v4.4.1 (05/2013) +---------------- + +### Bug fixes + + - Creation of a new binding constraint: the operation needed to be confirmed twice + (double click on "create button") and the study had to be "saved as" and reloaded before + proceeding further. + + - Time-series analyzer : due to round-off errors, spatial correlation of 100 % + (perfectly identical sets of time-series in different locations) could sometimes + be casted to 99%. Exact 100% correlations are now properly displayed. + + + + +v4.4.0 (04/2013) +---------------- + +### Features + + - Antares licenses can be either static or floating. Floating tokens are managed and + distributed by the Flexnet product, version 11.9. + + - Thermal plants time-series generator : availability parameters (outage rates and duration) + corresponding to a Mean Time Between Failure (MTBF) < 1 day are now allowed. Though unusual, + such sets of parameters may prove useful when it comes to modelling specific situations + + - Thermal plants time-series generator : it is possible to model the duration of each kind + of outages as 365-day random arrays instead of 365-day constant arrays. Two parameters + are available for the description of the probability distribution function of each component. + A first parameter allows to set the variable law to either "uniform" or "geometric". + A second parameter allows to set the ratio of the variable standard deviation to + its expectation to a particular value + + - Thermal plants time-series generator : The planned outage process is now committed to meet a + set of constraints defined by two 365-day arrays (PO Min Nb, PO Max Nb). For every day of + each Monte-Carlo year, the actual number of overhauls is kept within the [Min,Max] interval, + the exact value being determined by regular random draws based on outage rates and durations + + - As a consequence of the introduction of these new features, Monte-Carlo time-series + of available thermal power generated with Antares 4.4 may differ from those generated with + previous versions. Though differences may be observed draw by draw, the statistical + properties of the generated time-series are strictly preserved when datasets are identical. + + - Hydro storage optimization : when the maximum available power of a given day is not high + enough to allow the full use of the daily hydro storage energy credit, the energy in excess + is levelled on the other days of the month with a flatter pattern. + + +### Bug fixes + + - On creation of a new link, the transmission capacity status parameter is set + to `Use transmission capacities` instead of `Set to null`. + + + +v4.3.7 (02/2013) +---------------- + +### Features + + - Performance improvements for graphical display of large tables + + +### Bug fixes + + - The binding constraint data might not be written properly in some cases + when the constraint was renamed. + + + +V4.3.6 (12/2012) +---------------- + +### Bug fixes + + - Windows only: fixed potential crash which could happen when exiting + a simulation in adequacy mode with import of generated time-series + + - Windows only: improved free disk space assessment, which now takes into + consideration user- and folder-related quotas + + +V4.3.5 (10/2012) +---------------- + +### Features + + - The calendar field "year" is now available in the simulation main screen + (allows not only simulations from JAN to DEC but also from OCT to SEP, etc.) + + - The attribute "Leap year" is now available in the simulation main screen + + - The attribute "Week" is now available in the main simulation screen + (weekly results may be defined not only from MON to SUN but also from SAT to FRI,etc.) + + - Time-series screens: a new function is available for hourly and daily time-series + (shift rows until #date#) + + - Linear solver: new version slightly more accurate than the previous one. + Note that when a daily or weekly optimization has multiple equally optimal solutions, + the ultimate choice may differ from that of the previous version + + +### Bug fixes + + - Reference numbers of the time-series used in the course of a simulation: + When the simulation is based on a user-defined scenario (building mode: custom) + and when a printout of the reference numbers of the time-series used in the simulation + is asked for (MC scenarios: true), the numbers printed for thermal clusters running + under the "must-run" status were wrong + + - Interconnection results, marginal costs: + For a congested interconnection whose transmission capacities are not symmetric, + and in presence of hurdle costs, a zero could sometimes be delivered instead of + the actually expected value + + - Districts: when the Monte-Carlo synthesis edition is skipped, the results regarding + districts were not accessible via the output viewer. + + + +V4.2.6 (07/2012) +---------------- + +### Features + + - The field "MAX MRG" (last of the nodal results) is now available in the output files + + - The Monte-Carlo synthesis edition can be skipped when year-by-year results are asked for + + +### Bug fixes + + - Binding constraints: in the filter available for the weight matrix, removal of + redundant options + + - Copy/Paste nodes on the general map: "print status" parameters can now be copied like + any other data + + - Upgrade of studies in 3.8 format: negative hurdle costs were not correctly transposed + + - Thermal plants time-series generator: outages lasting N days, starting on day D, were + considered as outages lasting N days starting on D+1 (corrected by removal of the + one-day shift) + + - Advanced parameters, option "shave peaks" used along with the "weekly" simplex range: + the maximum intra-daily hydro storage limit on power could occasionally be overcome during + the unsupplied energy levelling process (corrected by a slight lessening of the authorized + levelling) + + + + +v4.1.0 (06/2012) +---------------- + +### Features + + - Hydro storage energy management : each nodal policy of use can be tuned so as to + accommodate simultaneously the net load of several nodes + + - Hydro storage energy modelling : monthly time-series of inflows and reference trajectories + for reservoir levels can be used instead of monthly time-series of generated energies. + + - Load shedding strategies : when unsupplied energy is unavoidable, a choice is now possible + between two policies : minimize the duration of sheddings or "shave" the load curve. + + - When multiple mathematically equivalent solutions exist a the first order for the + economic optimization problem, a choice can be made at the second order between three + ramping strategies + + + + +v3.8.0 (12/2011) +---------------- + +### Features + + - The simulation mode `Adequacy` is renamed `Draft`. + + - A new simulation mode `Adequacy` is available. In this mode, all thermal plants are + considered as must-run zero-cost units. + + - New possibilities are given regarding the filtering of simulation results (selection + of nodes, of interconnections, etc.) + + - Automatic spatial aggregation of results is possible through the use of the new + "district" object (a district is a sort of macro-node gathering several regions) + + - Nodal costs of unsupplied energy and of spilled energy : a small additive stochastic + noise around the reference values can be introduced to help discriminate between + theoretically equivalent solutions + + + +V3.7.4 (08/2011) +---------------- + +### Features + + - New version of the dual simplex engine (speed is about twice that of 3.6 version) + + - Economic optimizations now encompass a full week (168 hours) span. Traditional + day-long optimizations can still be carried out (ad hoc "preference" parameter) + + - Binding constraints can be defined at the weekly scale in addition to the + daily and hourly scales + + - Several other "optimization preferences" are made available to allow the quick examination + of variants used in sensitivity analyses + + - A new graphic interface is available for the consultation of all simulation results + (except those obtained in draft mode) + + - Extraction of data regarding any given variable from the whole Monte-Carlo year-by-year + set of results is now possible + + - New variables are introduced in the economic output files : the overall available dispatchable + thermal generation (AVL DTG) and the thermal margin (DTG MRG = AVL DTG - dispatched power) + + + + +V3.6.4 (04/2011) +---------------- + +### Features + + - The "scenario builder" is now available. With this builder it is possible to define + precisely the simulation context (for any given year, random numbers drawn for each + kind of time-series can be replaced by user-defined numbers). This feature allows + simulations to be carried out in a versatile "What If" mode. + + + + + +V3.5.3 (03/2011) +---------------- + +### Features + + - Addition of the fuel category "lignite" to the regular options available + for the description of thermal plants. + + - Improvement of the presentation of the 365-day arrays "market bid modulation" + and "marginal cost modulation". + + - Automatic processing of the inter-monthly & inter-regional hydro correlation hydro + energy matrix to meet the feasibility constraints (the matrix has to be positive + semi-definite). User should check in the simulation log file that no warning such as : + "info : hydro correlation not positive semi-definite : shrink by factor x " appears. + + + + +V3.4.4 (02/2011) +---------------- + +### Features + + - The names of nodes, thermal clusters and binding constraints can be extended to + 128 characters. Authorized characters are : `a-z, A-Z,0-9,-,_, space` + + + + +v3.4.3 (10/2010) +---------------- + +### Features + + - Two calculations modes are now available (in the "run" window): + + "regular": the software tries to hold all simulation data in RAM + this mode is faster than the second one when datasets are small but + can get dramatically slow when RAM limits are close + + "swap" : a dedicated memory management module loads in RAM amounts + of data as small as possible. This mode should be prefered to the + other when datasets are large. + + Note that in "regular" mode, the maximum amount of data loaded is + limited by the OS to 2 Go on 32-bit machines, regardless of the + memory installed. The integrality of installed memory can be used + on 64-bit machines. + + - A new module (time-series analyzer) is available to help set the + parameters of the stochastic time-series generators for wind power, + solar power and load. The analyzer determines, on sets of historical + 8760-hour time-series the relevant parameters for different kinds of + random laws (uniform, normal,Weibull, Beta, Gamma), along with a + description of the auto-correlation dynamic (two parameters) + and a full spatial correlation matrix + + + + + +v3.3.2 (07/2010) +---------------- + +### Features + + - Improvement of the wind power time-series generator (faster calculations) + + - Introduction of new stochastic time-series generators for + solar power and load + + - Introduction of an explicit modelling of wind-to-power curves. + As a consequence, wind power time-series can now be generated + either through a direct approach (by analysis of historical + time-series of power) or through an indirect (more physical) + approach, based on the analysis of historical time-series of + wind speed + + - Introduction of a new 8760-hour power array for each node, + representing the day-ahead reserve that should be made available + (either on-site or at distance) to face last-minute incidents + and/or forecasts errors. + + - Introduction of so-called hurdles costs on interconnection. + + + + +v3.1.0 (01/2010) +---------------- + +### Features + + - Breakdown of monthly hydro storage energy credits in daily credits: + The pilot curve is now the net load (i.e. load - all must-run generation) + instead of the gross load + + - New functionalities available for datasets management (stucy cleaner, + Log file wiewer) + + - New info is given for simulation context (available & required amounts + of RAM & HDD space) + + + +From V1 to V2 (all versions) +---------------------------- + + - Refer to project development archives (TRAC thread) + diff --git a/src/cmake/ProfileBuild.template.cmake b/src/cmake/ProfileBuild.template.cmake new file mode 100644 index 0000000000..3b6c1c03c5 --- /dev/null +++ b/src/cmake/ProfileBuild.template.cmake @@ -0,0 +1,195 @@ + +############################################################################### +# Profile +# Everything related to this particular profile +############################################################################### + +# Profile name +# FIXME: Document usage. +set(YUNI_PROFILE_NAME "RTE-ANTARES") + + + + +############################################################################### +# Environment +# Compilers, program search paths, everything about your system. +############################################################################### + +# YUNI_MACPORTS_PREFIX +# Mac-specific: MacPorts path. When you specify "macports" in a package search, +# this prefix is used. +# +# Default: Prefix of the first «port» program found in PATH. +# Should be /opt/local in the most common case. +# +#set(YUNI_MACPORTS_PREFIX "/my/twisted/macports/prefix") +set(YUNI_MACPORTS_PREFIX "/opt/local/") + + + +############################################################################### +# Target +# What is produced, and everything related to it. +############################################################################### + +# YUNI_TARGET +# Specifies the compilation profile. Accepted values are: +# - debug: No optimization, debug info, very slow. +# - release: O3 optimization level, no debug, production code. +# +# Default: debug +# +set(YUNI_TARGET "${ANTARES_VERSION_TARGET}") + + +# MODULES +# Specifies which Yuni components should be build. +# Uncomment the following line to override the module list +# Example : `ui,scripts,-net` +# Note : `cmake -DMODULES=help` to have a list of all available modules +set(MODULES "core,uuid") + + + +############################################################################### +# External packages +# +# A module often requires one or more external packages (`lua` for example). +# Most of the time the system has its own package management utility, which +# will provide all needed and up-to-date packages (`lua`, `libxml`...). +# It is not always the case (Windows for example), so some pre-built packages +# (DevPacks) are available on http://devpacks.libyuni.org and can be +# automatically downloaded. +# +# Several modes can be given in the preferred order to find and use the +# appropriate package. If nothing suits your needs, it is possible to use the +# `custom` mode and to set the prefix path where the package can be found. +# This is useful if you have special needs or wish to integrate Yuni in an +# software that already uses the package. +# +# Generic modes : +# +# disabled: Do as if the particular package could not be found. +# Implemented only for certain packages providing optional support. +# +# system : Try to use the standard way to find the package provided by the system +# Standard paths, System Frameworks (OS X) +# +# custom : Try to find the package from a custom prefix path +# The variable `YUNI_DvP__PREFIX` must be set. +# Other variables may need to be set, on a per-package +# basis +# +# macport : Try to find the package from a macport installation (Mac OS X) +# (http://www.macports.org) +# +# devpack : Download and use the pre-build package from `devpacks.libyuni.org` +# This is the recommended way on Windows, and when you want to have +# a known-working build. +# +# NOTE: Each package is not required to support every mode. Available modes are speci +# +# Example : +# Use `lua` compiled by hand, installed in `/opt/lua` (/opt/lua/include and `/opt/lua/lib`) : +# Set(YUNI_DvP_LUA_MODE custom) +# Set(YUNI_DvP_LUA_PREFIX "/opt/lua") +# +############################################################################### + +## Core + +# PThread [FIXME: NOT IMPLEMENTED] +# Provides: Threads, locking, synchronisation +# Modes: system +# Required for Core module. +#set(YUNI_DvP_PTHREAD_MODE system) + +## Audio + +# ZLIB [FIXME: NOT IMPLEMENTED] +# Provides: GZip compression support +# Modes: system, custom +# Required for Audio module. + +# OpenAL +# Provides: Audio abstraction layer. +# Modes: system, devpack, custom +# Required for Audio module. +set(YUNI_DvP_OPENAL_MODE system) + + +## Scripts + +# Lua (+script,+lua) +# Provides: Lua scripting support +# Modes: devpack, system, macports, custom +# Optional. +set(YUNI_DvP_LUA_MODE system) + + + +############################################################################### +# Platform-specific options +############################################################################### + +# For building universal binaries on OS X +# Value by default : i686;x86_64 +#set(YUNI_MACOX_UNIVERSAL_BINARIES "ppc;ppc64;i386;x86_64") + + +############################################################################### +# Miscellaneous build options +# Options that concern small features, tweaks or optimisations +############################################################################### + +# Auto-Compile yuni-config from CMake +# Enable this option to automatically compile yuni-config from CMake +# FIXME: Describe when this could be useful. +#set(YUNI_AUTO_COMPILE_YUNI_CONFIG false) + + +# Special instructions sets +# The following options enable or disable certain CPU optimisations. +# If you have to run on platforms that do not support certain options, +# we recommend to disable them. +# Options: +# auto : Auto detect if these sets can be used (based on build host) +# no : Completely disable it +# yes : Try to use it anyways (it may not even compile, though) +# +set(YUNI_PROFILE_MMX "auto") # MMX +set(YUNI_PROFILE_3DNOW "auto") # 3DNow! +set(YUNI_PROFILE_SSE "auto") # SSE +set(YUNI_PROFILE_SSE2 "auto") # SSE2 (depends on SSE) +set(YUNI_PROFILE_SSE3 "auto") # SSE3 (depends on SSE2) +set(YUNI_PROFILE_SSE4 "auto") # SSE4 (depends on SSE3) +set(YUNI_PROFILE_SSE4a "auto") # SSE4a (depends on SSE3) +set(YUNI_PROFILE_SSE4_1 "auto") # SSE 4.1 (depends on SSE3) +set(YUNI_PROFILE_SSE4_2 "auto") # SSE 4.2 (depends on SSE3) + + +# yuni-config +# Enable this option to skip the build of yuni-config +set(YUNI_SKIP_YUNI_CONFIG true) + + +# Custom C/C++ Flags +# +# Advanced users only : it may not a good idea to use your own CFlags +# for compiling the Yuni library. Do not file any bug reports before re-testing +# with standard build-flags. + +# Uncomment the following line to ADD some C++ compiler flags +#set(YUNI_CXX_FLAGS_OVERRIDE_ADD_DEBUG "-Wextra") +#set(YUNI_CXX_FLAGS_OVERRIDE_ADD_RELEASE "-Wextra") +#set(YUNI_CXX_FLAGS_OVERRIDE_ADD_RELWITHDEBINFO "-Wextra") + +# Uncomment the following line to OVERRIDE the C++ compiler flags +# This is not recommended. +set(YUNI_CXX_FLAGS_OVERRIDE_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") +set(YUNI_CXX_FLAGS_OVERRIDE_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") +set(YUNI_CXX_FLAGS_OVERRIDE_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE}") + + +# That's all, folks ! ######################################################### diff --git a/src/cmake/changelog.cmake b/src/cmake/changelog.cmake new file mode 100644 index 0000000000..b937b58f05 --- /dev/null +++ b/src/cmake/changelog.cmake @@ -0,0 +1,4 @@ + +# Copy the changelog +file(READ "changelog.mdown" changelog_content) +file(WRITE "distrib/changelog.txt" "${changelog_content}") diff --git a/src/cmake/checks.cmake b/src/cmake/checks.cmake new file mode 100644 index 0000000000..c149eb87ea --- /dev/null +++ b/src/cmake/checks.cmake @@ -0,0 +1,24 @@ + +if (CMAKE_COMPILER_IS_GNUCXX) + # Check for valid version of GCC + check_cxx_source_compiles(" + #ifdef __GNUC__ + # define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) + # if GCC_VERSION < 40500 + # error \"GCC >=4.5 required\" + # endif + #endif + int main() {return 0;}" OPTIMATE_HAS_GCC_GREATER_THAN_45) + + if (NOT OPTIMATE_HAS_GCC_GREATER_THAN_45) + message(FATAL_ERROR "\n\nGCC >= 4.5 is required\n") + endif() + +else() + if(MSVC) + if (MSVC60 OR MSVC70 OR MSVC71 OR MSVC80 OR CMAKE_COMPILER_2005 OR MSVC90) + message(FATAL_ERROR "\n\nVisual Studio >=10 is required\n") + endif() + endif() +endif() + diff --git a/src/cmake/common-settings.cmake b/src/cmake/common-settings.cmake new file mode 100644 index 0000000000..14defc15fb --- /dev/null +++ b/src/cmake/common-settings.cmake @@ -0,0 +1,275 @@ + +# no RPATH at all +#set(CMAKE_SKIP_RPATH true) +#set(CMAKE_SKIP_BUILD_RPATH true) +#set(CMAKE_BUILD_WITH_INSTALL_RPATH 0) + + +# +# Common FLAGS for all compilers +# +set(COMMON_GCC_FLAGS "-Wall -W -Wextra -Wfatal-errors") +if (NOT WIN32) + set(COMMON_GCC_FLAGS "${COMMON_GCC_FLAGS} -pipe -msse -msse2 -Wunused-but-set-variable -Wunused-but-set-parameter") + set(COMMON_GCC_FLAGS "${COMMON_GCC_FLAGS} -Werror=return-type") +endif() +set(COMMON_MSVC_FLAGS "/W3 /MP4 /Zi ") +set(COMMON_MSVC_FLAGS "${COMMON_MSVC_FLAGS} /we4715 /we4716") #adding no return or no return for all code paths as errors +set(ADDITIONAL_C_FLAGS " -Wconversion -Wmissing-prototypes -Wstrict-prototypes") +set(ADDITIONAL_C_FLAGS "${ADDITIONAL_C_FLAGS} -Wmissing-noreturn -Wpacked -Wredundant-decls -Wbad-function-cast -W -Wcast-align -Wcast-qual -Wsign-compare -fno-exceptions -Wdeclaration-after-statement") + + +Set(ANTARES_VERSION_TARGET "unknown") +Set(ANTARES_INSTALLER_EXTENSION "") + + +macro(EMBED_MANIFEST manifestfile target) + if(MSVC AND NOT MSVC9) + message(STATUS "{antares} :: adding rule for manifest ${manifestfile}") + set(ANTARES_UI_BIN_TARGET "Debug\\") + if("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + set(ANTARES_UI_BIN_TARGET "Release\\") + endif() + + add_custom_command(TARGET ${target} POST_BUILD COMMAND + "${PROJECT_SOURCE_DIR}/../bin/mt.exe" + "-nologo" "-manifest" + "\"${CMAKE_CURRENT_SOURCE_DIR}/${manifestfile}\"" + "-outputresource:${CMAKE_CURRENT_SOURCE_DIR}\\${ANTARES_UI_BIN_TARGET}\\${target};1" + COMMENT "Embedding the manifest into the executable '${CMAKE_CURRENT_SOURCE_DIR}\\${ANTARES_UI_BIN_TARGET}\\${target}'") + endif() +endmacro() + +# +# Command line options for G++ (Debug) +# +# Ex: cmake . -DCMAKE_BUILD_TYPE=release +# +if("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + + # + # Build Configuration: Release + # + set(ANTARES_VERSION_TARGET "release") + + if(NOT WIN32) + set(CMAKE_CXX_FLAGS_RELEASE "${COMMON_GCC_FLAGS} -flto -O3 -funroll-loops -frerun-cse-after-loop -frerun-loop-opt -finline-functions") + set(CMAKE_C_FLAGS_RELEASE "${COMMON_GCC_FLAGS} -flto -O3 -funroll-loops -frerun-cse-after-loop -frerun-loop-opt -finline-functions ${ADDITIONAL_C_FLAGS}") + endif(NOT WIN32) + add_definitions("-DNDEBUG") # Remove asserts + + if (NOT MINGW AND NOT MSVC) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -ansi") + endif() + if (NOT MSVC) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -std=c99") + endif() + + if("${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -pg --no-inline") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pg --no-inline") + endif("${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + +else() + + # + # Build Configuration: Debug + # + set(ANTARES_VERSION_TARGET "debug") + set(ANTARES_INSTALLER_EXTENSION "-debug") + + + if(NOT WIN32) + + set(CMAKE_CXX_FLAGS_DEBUG "${COMMON_GCC_FLAGS} -g3 -ggdb3 -feliminate-unused-debug-symbols") + + set(CMAKE_C_FLAGS_DEBUG "${COMMON_GCC_FLAGS} -g3 -ggdb3 -feliminate-unused-debug-symbols ${ADDITIONAL_C_FLAGS}") + + endif() + add_definitions("-DANTDEBUG") # More debug ! + + if (NOT MINGW AND NOT MSVC) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ansi") + endif() + if (NOT MSVC) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -std=c99") + endif() + +endif() + + + + +# UNICODE +if(WIN32 OR WIN64) + add_definitions("-DUNICODE") + add_definitions("-D_UNICODE") + add_definitions("-D__UNICODE") +endif() + + +if(MSVC) + set(CMAKE_C_FLAGS_DEBUG "${COMMON_MSVC_FLAGS} /MDd /GR /Ot /Od /EHsc /RTC1") + set(CMAKE_CXX_FLAGS_DEBUG "${COMMON_MSVC_FLAGS} /MDd /GR /Ot /Od /EHsc /RTC1 /fp:except") + + # RELEASE + set(CMAKE_EXE_LINKER_FLAGS_RELEASE) + set(MSVC_RELEASE_FLAGS) + # O2x: optimization + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /O2") + # Prefer speed instead of size + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /Ot") + # Omit frame pointer + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /Oy") + # Any suitable inlining + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /Ob2") + # Fiber-safe optimizations + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /GT") + # whole program / requires "Link time code generation" + #set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /GL") + # No buffer security check + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /GS-") + # Intrinsic functions + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /Oi") + # Multithreaded DLL + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /MD") + + + # linker: Link time code generation + #set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + if(NOT "${ANTARES_x86_64}" STREQUAL "") + #message(STATUS "{antares} using 64bits architecture") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /MACHINE:X64") + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /MACHINE:X64") + else() + # SSE2 + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /arch:SSE2") + endif() + # Release + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /RELEASE") + # Remove symbols + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /OPT:REF") + + set(CMAKE_CXX_FLAGS_RELEASE "${COMMON_MSVC_FLAGS} ${MSVC_RELEASE_FLAGS} /EHsc") + set(CMAKE_C_FLAGS_RELEASE "${COMMON_MSVC_FLAGS} ${MSVC_RELEASE_FLAGS} /EHsc") + + + #SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "/debug /VERSION:${ANTARES_VERSION_HI}.${ANTARES_VERSION_LO}") + #SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "/VERSION:${ANTARES_VERSION_HI}.${ANTARES_VERSION_LO}") +else() + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=gnu++11") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=gnu++11") +endif() + +if (NOT MSVC) + # segv for gcc + if (CMAKE_COMPILER_IS_GNUCC) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) + + if (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7) + #set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fvisibility-ms-compat -fvisibility-inlines-hidden") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fvisibility-inlines-hidden") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fvisibility-ms-compat -fvisibility-inlines-hidden") + endif() + endif() +endif() + +if(WIN32) + add_definitions("-DANT_WINDOWS") + add_definitions("/D_CRT_SECURE_NO_WARNINGS") +endif() + +# Thread safety +add_definitions("-D_REENTRANT -DXUSE_MTSAFE_API -DCURL_STATICLIB") + + +# ICC Optimizations +if (ICC) + message(STATUS "{antares} Adding optimization flags for ICC") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Os /QaxSSE3 /Qunroll-aggressive /Qinline-calloc /Qms:0") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Os /QaxSSE3 /Qunroll-aggressive /Qinline-calloc /Qms:0") +endif() + + +# +# SQLite +# +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/ext/sqlite/src") +add_definitions("-DSQLITE_THREADSAFE=1") +add_definitions("-D_LARGEFILE_SOURCE=1") + + +# +# Yuni +# +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/ext/yuni/src") + +# +# Antares libs +# +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/libs") + + +# wxWidgets +# if(ANTARES_GUI) + # include("../FindWXWidgets.cmake") +# endif() + + + +macro(import_std_libs TARGET) + if(MSVC10) + # WinSock + target_link_libraries(${TARGET} wsock32.lib) + elseif(WIN32) + target_link_libraries(${TARGET} wsock32.lib legacy_stdio_definitions.lib) + endif() +endmacro() + + +macro(executable_strip TARGET) + if("${CMAKE_BUILD_TYPE}" STREQUAL "release") + if(NOT MSVC) + if(WIN32) + add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_STRIP} ${TARGET}.exe + COMMENT "Stripping the executable '${TARGET}.exe'") + else() + add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_STRIP} --strip-all ${TARGET} + COMMENT "Stripping the executable '${TARGET}'") + endif() + endif() + endif() +endmacro() + + +macro(library_strip TARGET) + if(NOT MSVC AND "${CMAKE_BUILD_TYPE}" STREQUAL "release") + if(WIN32) + add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_STRIP} ${TARGET}.dll + COMMENT "Stripping the library '${TARGET}.dll'") + else() + add_custom_command(TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_STRIP} --strip-all lib${TARGET}.so + COMMENT "Stripping the library 'lib${TARGET}.so'") + endif() + endif() +endmacro() + + + +if("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + set(YUNI_FROM_ANTARES_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELEASE}") +else() + set(YUNI_FROM_ANTARES_CXX_FLAGS "${CMAKE_CXX_FLAGS_DEBUG}") +endif() + + +if("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "tuning") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELEASE}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_RELEASE}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_DEBUG}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_DEBUG}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") +endif() + diff --git a/src/cmake/libcurl_openssl.cmake b/src/cmake/libcurl_openssl.cmake new file mode 100644 index 0000000000..e43e7f0a28 --- /dev/null +++ b/src/cmake/libcurl_openssl.cmake @@ -0,0 +1,75 @@ +set(ANTARES_CURL_INCLUDE "") +set(ANTARES_CURL_LIBS "") +set(ANTARES_CURL_LINK "") +set(ANTARES_OSSL_INCLUDE "") + + +if(NOT "${ANTARES_x86_64}" STREQUAL "") + set(ARCH_TYPE "x86_64") + + else() + set(ARCH_TYPE "x86") +endif() + +if (WIN32) + if(MSVC) + set(COMPILER_NAME "vc14") + set(COMPILER_LIB_INCLUDE "vc") + else(MSVC) + set(COMPILER_NAME "gcc4.x") + set(COMPILER_LIB_INCLUDE "gcc") + endif(MSVC) + + OMESSAGE("Libcurl support enabled") + set(ANTARES_CURL_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/ext/libcurl/builds/libcurl-${COMPILER_NAME}-${ANTARES_INSTALLER_REDIST_ARCH}-release-static-ssl-static-ipv6/include") + set(ANTARES_CURL_LINK "${CMAKE_CURRENT_SOURCE_DIR}/ext/libcurl/builds/libcurl-${COMPILER_NAME}-${ANTARES_INSTALLER_REDIST_ARCH}-release-static-ssl-static-ipv6/lib") + + + set(ANTARES_OSSL_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/ext/openssl/${COMPILER_LIB_INCLUDE}-release-${ARCH_TYPE}/include") + set(ANTARES_OSSL_LINK "${CMAKE_CURRENT_SOURCE_DIR}/ext/openssl/${COMPILER_LIB_INCLUDE}-release-${ARCH_TYPE}/lib") + if(NOT MINGW) + set(ANTARES_CURL_LIBS "${ANTARES_CURL_LINK}/libcurl_a.lib") + set(ANTARES_OSSL_LIBS "${ANTARES_OSSL_LINK}/libeay32.lib" "${ANTARES_OSSL_LINK}/ssleay32.lib") + else() + set(ANTARES_CURL_LIBS "${ANTARES_CURL_LINK}/libcurl.a") + set(ANTARES_OSSL_LIBS "${ANTARES_OSSL_LINK}/libssl.a" "${ANTARES_OSSL_LINK}/libcrypto.a") + endif() + + include_directories("${ANTARES_CURL_INCLUDE}") + link_directories("${ANTARES_CURL_LINK}") + OMESSAGE("Libcurl: ${ANTARES_CURL_LINK}") + + OMESSAGE("OpenSSL support enabled") + +else() + include(FindPackageHandleStandardArgs) + + set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) + + #libcurl + find_package(CURL 7.51.0) + + if (CURL_FOUND) + set(ANTARES_CURL_INCLUDE "${CURL_INCLUDE_DIRS}/curl") + set(ANTARES_CURL_LINK "${CURL_LIBRARIES}") + set(ANTARES_CURL_LIBS "${ANTARES_CURL_LINK}") + else() + OERROR("libcurl-dev is required") + endif() + + #openssl + if(NOT OPENSSL_ROOT_DIR) + set(OPENSSL_ROOT_DIR "/") # default value + endif() + + find_package(OpenSSL 1.1.0) + + if (OPENSSL_FOUND) + set(ANTARES_OSSL_INCLUDE "${OPENSSL_INCLUDE_DIR}/openssl") + set(ANTARES_OSSL_LINK "${OPENSSL_LIBRARIES}") + set(ANTARES_OSSL_LIBS "${ANTARES_OSSL_LINK}") + else() + OERROR("libssl-dev is required") + endif() + +endif() diff --git a/src/cmake/messages.cmake b/src/cmake/messages.cmake new file mode 100644 index 0000000000..a579ec14bb --- /dev/null +++ b/src/cmake/messages.cmake @@ -0,0 +1,67 @@ + +set(ANTARES_ERROR_HAS_OCCURED false) + + +macro(OMESSAGE msg) + if(UNIX) + message(STATUS "{antares} ${msg}") + else() + message(STATUS "{antares} ${msg}") + endif() + +endmacro() + + +macro(OMESSAGE_BOLD msg) + if(UNIX) + message(STATUS "{antares} ${msg}") + else() + message(STATUS "{antares} ${msg}") + endif() +endmacro() + + +macro(OMESSAGE_TITLE msg1 msg2) + if(UNIX) + message(STATUS "{antares} ${msg1}${msg2}") + else() + message(STATUS "{antares} ${msg1}${msg2}") + endif() +endmacro() + + +macro(OMESSAGE_MODULE msg) + OMESSAGE_TITLE("[module] " "${msg}") +endmacro() + + +macro(OWARNING msg) + if(UNIX) + message(STATUS "{antares} [warning] ${msg}") + else() + message(STATUS "{antares} [WARNING] ${msg}") + endif() +endmacro() + + +macro(OERROR msg) + if(UNIX) + message(STATUS "{antares} [error] ${msg}") + else() + message(STATUS "{antares} [ERROR] ${msg}") + endif() + set(ANTARES_ERROR_HAS_OCCURED true) +endmacro() + + +macro(OFATAL msg) + if(UNIX) + message(FATAL_ERROR "{antares} [error] ${msg}") + else() + message(FATAL_ERROR "{antares} [ERROR] ${msg}") + endif() + + set(ANTARES_ERROR_HAS_OCCURED true) +endmacro() + + diff --git a/src/cmake/wxWidgets.cmake b/src/cmake/wxWidgets.cmake new file mode 100644 index 0000000000..60ee704099 --- /dev/null +++ b/src/cmake/wxWidgets.cmake @@ -0,0 +1,24 @@ + +if(ANTARES_GUI) + + if(WIN32) + set(ANTARES_WX_VERSION_HI 3) + set(ANTARES_WX_VERSION_LO 0) + + set(ANTARES_WX_VERSION 30) + + set(ANTARES_WX_ROOT_PATH "${PROJECT_SOURCE_DIR}/ext/wxwidgets") + + + + + OMESSAGE("wxWidgets version to set: ${ANTARES_WX_VERSION_HI}.${ANTARES_WX_VERSION_LO}") + OMESSAGE("${ANTARES_WX_ROOT_PATH}") + + + + endif() + + include("../FindWXWidgets.cmake") + +endif() \ No newline at end of file diff --git a/src/cmake_clean.sh b/src/cmake_clean.sh new file mode 100644 index 0000000000..69244d59a2 --- /dev/null +++ b/src/cmake_clean.sh @@ -0,0 +1,6 @@ +#! /bin/sh + +find -name 'Makefile' -type f -exec rm -rf {} \+ +find -name 'CMakeFiles' -type d -exec rm -rf {} \+ +find -name 'CMakeCache.txt' -type f -exec rm -f {} \+ +find -name 'cmake_install.cmake' -type f -exec rm -f {} \+ diff --git a/src/config.h.cmake b/src/config.h.cmake new file mode 100644 index 0000000000..9a6cf4f016 --- /dev/null +++ b/src/config.h.cmake @@ -0,0 +1,44 @@ +#ifndef __ANTARES_CONFIG_H__ +# define __ANTARES_CONFIG_H__ + + +//! The Hi version +# define ANTARES_VERSION_HI @ANTARES_VERSION_HI@ +//! The Lo version +# define ANTARES_VERSION_LO @ANTARES_VERSION_LO@ +//! Build (Revision) of Antares +# define ANTARES_VERSION_BUILD @ANTARES_VERSION_REVISION@ +//! Canonical version +# define ANTARES_VERSION "@ANTARES_VERSION_HI@.@ANTARES_VERSION_LO@" +//! Date of publication +# define ANTARES_VERSION_YEAR @ANTARES_VERSION_YEAR@ + +//! Version in CString format +# define ANTARES_VERSION_STR "@ANTARES_VERSION_HI@.@ANTARES_VERSION_LO@.@ANTARES_VERSION_REVISION@" + +//! Version + Publisher +# define ANTARES_VERSION_PUB_STR "@ANTARES_VERSION_HI@.@ANTARES_VERSION_LO@.@ANTARES_VERSION_REVISION@ (@ANTARES_PUBLISHER@)" + + +# define ANTARES_VERSION_BUILD_DATE __DATE__ + +//! The Publisher +# define ANTARES_PUBLISHER "@ANTARES_PUBLISHER@" +//! The Website for RTE +# define ANTARES_WEBSITE "@ANTARES_WEBSITE@" + +# define ANTARES_PROXY_PARAMETERS_FILENAME "ProxyConnexionParameters.ini" + +# define ANTARES_SERVER_SCRIPT_ROOT "/check/" + +# define ANTARES_CA_BUNDLE "ca-bundle.crt" +// ---------------------------------------------------------------------------- + +//! Beta version +#cmakedefine ANTARES_BETA @ANTARES_BETA@ + +//! RC version +#cmakedefine ANTARES_RC @ANTARES_RC@ + +#endif // __ANTARES_CONFIG_H__ + diff --git a/src/distrib/unix/common.sh b/src/distrib/unix/common.sh new file mode 100644 index 0000000000..c2bfc259b8 --- /dev/null +++ b/src/distrib/unix/common.sh @@ -0,0 +1,52 @@ + +# +# \brief Print a message to the standard output +# +log() +{ + echo "[`date`][infos] " "$*" +} + +# +# \brief Print a notice message +# +notice() +{ + echo "[`date`][notic] " "$*" "" +} + + +# +# \brief Print an error to the standard error output +# +error() +{ + echo "[`date`][error] " "$*" > /dev/stderr +} + + +# +# \brief Check if a program exists +# \param $1 output variable name +# \param $2 program +# \param $3 'noabort' to ignore errors +# +check_program() +{ + local result="${1}" + local prgm="${2}" + + log "checking ${prgm}" + local w=$(which "${prgm}" 2>/dev/null) + + if [ "${w}" = "" ]; then + log "checking ${prgm}: " + if [ ! "${3}" = "noabort" ]; then + error "impossible to find the program \"${prgm}\"" + exit 1 + fi + else + log "checking ${prgm}: ${w}" + eval $result="'${w}'" + fi +} diff --git a/src/distrib/unix/packages.cmake b/src/distrib/unix/packages.cmake new file mode 100644 index 0000000000..d2d661172e --- /dev/null +++ b/src/distrib/unix/packages.cmake @@ -0,0 +1,16 @@ + +# Antares HI version +antares_version_hi="@ANTARES_VERSION_HI@" + +# Antares LO version +antares_version_lo="@ANTARES_VERSION_LO@" + +# Antares Revision +antares_rev="@ANTARES_VERSION_REVISION@" + + +# Antares Website +antares_website="@ANTARES_WEBSITE@" + +# Antares Publisher +antares_publisher="@ANTARES_PUBLISHER@" diff --git a/src/distrib/unix/rpm/create-rpms.sh b/src/distrib/unix/rpm/create-rpms.sh new file mode 100755 index 0000000000..a70f0f8aa8 --- /dev/null +++ b/src/distrib/unix/rpm/create-rpms.sh @@ -0,0 +1,223 @@ +#!/bin/bash + + +# ----------------------------------------------------------------------------- + +IFS=" +" + +root=$(cd `dirname "${0}"` && pwd -P) + +. "${root}/../common.sh" +if [ ! -f "${root}/../packages.sh" ]; then + error "Please run cmake before running this script" + exit 1 +fi +. "${root}/../packages.sh" + + +# +# \brief Start a new package +# \param $1 name of the package +# \param $2 version +# \param $3 revision +# \param $4 publisher +# \param $5 url +# +pkg_init() +{ + pkg_name="${1}" + pkg_version="${2}" + pkg_rev="${3}" + pkg_publisher="${4}" + pkg_url="${5}" + notice "package ${pkg_name} [${pkg_version}.${pkg_rev}]" + "${prgm_wipetree}" > /dev/null + "${prgm_setuptree}" + __pkg_cwd="${rpmtopdir}/SOURCES/${pkg_name}-${pkg_version}/" + __pkg_ori_cwd="/" + mkdir -p "${__pkg_cwd}" + if [ $? -ne 0 ]; then + error "impossible to create directory ${__pkg_cwd}" + exit 1 + fi + pkg_spec="${root}/${pkg_name}.spec" + log "package ${pkg_name}: ${pkg_spec}" + if [ ! -f "${pkg_spec}" ]; then + error "impossible to find the spec file from ${pkg_spec}" + exit 1 + fi + + pkg_filelist=$(mktemp) + pkg_import=$(mktemp) + pkg_installscript=$(mktemp) + pkg_filecount=0 + pkg_foldercount=0 + + echo "#!/bin/bash" > "${pkg_import}" + echo "" >> "${pkg_import}" + echo ". \"${root}/../common.sh\"" >> "${pkg_import}" +} + +pkg_cwd() +{ + ((pkg_foldercount++)) + __pkg_ori_cwd="${1}" + __pkg_cwd="${rpmtopdir}/SOURCES/${pkg_name}-${pkg_version}.${pkg_rev}/${1}" + echo "mkdir -p \"${__pkg_cwd}\"" >> "${pkg_import}" + echo "if [ \$? -ne 0 ]; then" >> "${pkg_import}" + echo " error \"impossible to create directory ${__pkg_cwd}\"" >> "${pkg_import}" + echo " exit 1" >> "${pkg_import}" + echo "fi" >> "${pkg_import}" + echo "install -m 0755 -d \"\${RPM_BUILD_ROOT}/${__pkg_ori_cwd}/\"" >> "${pkg_installscript}" +} + +# +# \brief Add a file +# \param $1 the file to add, relative to the `src` folder +# \param $2 Optional target filename +# +pkg_add_file() +{ + local file="${root}/../../../$1" + if [ ! -f "${file}" ]; then + error "pkg_add_file: impossible to find ${file}" + exit 1 + fi + local target="${2}" + if [ "${target}" = "" ]; then + target=$(basename "${1}") + fi + ((pkg_filecount++)) + echo "${__pkg_ori_cwd}/${target}" >> "${pkg_filelist}" + echo "install -m 0644 \"${file}\" \"\${RPM_BUILD_ROOT}/${__pkg_ori_cwd}/${target}\"" >> "${pkg_installscript}" +} + +# +# \brief Add a file as an executable +# \param $1 the file to add, relative to the `src` folder +# \param $2 Optional target filename +# +pkg_add_exec() +{ + local file="${root}/../../../$1" + if [ ! -f "${file}" ]; then + error "pkg_add_file: impossible to find ${file}" + exit 1 + fi + local target="${2}" + if [ "${target}" = "" ]; then + target=$(basename "${1}") + fi + ((pkg_filecount++)) + ${prgm_chrpath} --delete "${file}" + echo "${__pkg_ori_cwd}/${target}" >> "${pkg_filelist}" + echo "install -m 0755 \"${file}\" \"\${RPM_BUILD_ROOT}/${__pkg_ori_cwd}/${target}\"" >> "${pkg_installscript}" +} + + + +pkg_build() +{ + log "package ${pkg_name}: ${pkg_foldercount} folders" + log "package ${pkg_name}: ${pkg_filecount} files..." + chmod 750 "${pkg_import}" + "${pkg_import}" + + tar=$(cd "${rpmtopdir}/SOURCES" && tar czvf "${pkg_name}-${pkg_version}.${pkg_rev}.tar.gz" \ + "${pkg_name}-${pkg_version}.${pkg_rev}") + rm -rf "${rpmtopdir}/SOURCES/${pkg_name}-${pkg_version}.${pkg_rev}" + + log "package ${pkg_name}: please wait while building..." + r=$(cat "${pkg_spec}" | sed "s/%%VERSION%%/${pkg_version}.${pkg_rev}/g" \ + | sed "s/%%SOURCE%%/${pkg_name}-${pkg_version}.${pkg_rev}.tar.gz/g" \ + > "${rpmtopdir}/SPECS/${pkg_name}.spec") + + echo "" >> "${rpmtopdir}/SPECS/${pkg_name}.spec" + echo "" >> "${rpmtopdir}/SPECS/${pkg_name}.spec" + echo "%install" >> "${rpmtopdir}/SPECS/${pkg_name}.spec" + cat "${pkg_installscript}" >> "${rpmtopdir}/SPECS/${pkg_name}.spec" + + echo "" >> "${rpmtopdir}/SPECS/${pkg_name}.spec" + echo "" >> "${rpmtopdir}/SPECS/${pkg_name}.spec" + echo "%files" >> "${rpmtopdir}/SPECS/${pkg_name}.spec" + cat "${pkg_filelist}" >> "${rpmtopdir}/SPECS/${pkg_name}.spec" + + cd "${rpmtopdir}" && rpmbuild -ba "SPECS/${pkg_name}.spec" > //dev/null 2> /dev/null + + rm -f "${pkg_filelist}" + rm -f "${pkg_import}" + rm -f "${pkg_installscript}" + + # copying rpm + $(cd "${rpmtopdir}/RPMS" && find . -name '*debuginfo*' -exec rm -f '{}' \;) + local list=$(cd "${rpmtopdir}/RPMS" && find . -name '*.rpm') + IFS=" +" + for i in "${list}"; do + log "package ${pkg_name}: $(basename "${i}")" + cp "${rpmtopdir}/RPMS/$i" "${root}" + done +} + + + + + + +main() +{ + notice "--- Antares v${antares_version_hi}.${antares_version_lo}.${antares_rev} RPM Builder" + log "${antares_publisher} - ${antares_website}" + log + log "launched from ${root}" + + check_program prgm_rpm rpm + check_program prgm_setuptree rpmdev-setuptree + check_program prgm_wipetree rpmdev-wipetree + check_program prgm_chrpath chrpath + + # launchung setuptree, to create missing files if they don't exist + "${prgm_setuptree}" + + rpmtopdir=$("${prgm_rpm}" --eval "%{_topdir}") + if [ ! -d "${rpmtopdir}" ]; then + error "rpmbuild: the folder '${rpmtopdir}' does not exist" + exit 1 + fi + log "rpmtopdir ${rpmtopdir}" + log # for beauty + + local ver="${antares_version_hi}.${antares_version_lo}" + + pkg_init rte-antares "${ver}" "${antares_rev}" \ + "${antares_publisher}" \ + "${antares_website}" + pkg_cwd "/usr/bin" + pkg_add_exec "solver/antares-${ver}-solver" + pkg_add_exec "solver/antares-${ver}-solver-swap" + pkg_add_exec "analyzer/antares-${ver}-analyzer" + pkg_add_exec "tools/finder/antares-${ver}-study-finder" + pkg_add_exec "tools/batchrun/antares-${ver}-batchrun" + pkg_add_exec "tools/config/antares-${ver}-config" + pkg_add_exec "tools/updater/antares-${ver}-study-updater" + + pkg_cwd "/etc/antares/pkgs" + echo "/usr/bin/antares-${ver}-solver" > "${root}/pkginfo-solver" + pkg_add_file "distrib/unix/rpm/pkginfo-solver" "solver-${ver}" + echo "/usr/bin/antares-${ver}-solver-swap" > "${root}/pkginfo-solver-swap" + pkg_add_file "distrib/unix/rpm/pkginfo-solver-swap" "solver-swap-${ver}" + echo "/usr/bin/antares-${ver}-analyzer" > "${root}/pkginfo-analyzer" + pkg_add_file "distrib/unix/rpm/pkginfo-analyzer" "analyzer-${ver}" + echo "/usr/bin/antares-${ver}-config" > "${root}/pkginfo-config" + pkg_add_file "distrib/unix/rpm/pkginfo-config" "config-${ver}" + + pkg_build + + rm -rf "${rpmbuild}" + ${prgm_setuptree} + log done +} + + +main diff --git a/src/distrib/unix/rpm/rte-antares.spec b/src/distrib/unix/rpm/rte-antares.spec new file mode 100644 index 0000000000..f052cd1296 --- /dev/null +++ b/src/distrib/unix/rpm/rte-antares.spec @@ -0,0 +1,41 @@ +Name: rte-antares +Version: %%VERSION%% +Release: 1%{?dist} +Summary: A New Tool for Adequacy Reporting of Eletric Systems +Vendor: RTE +License: RTE Antares License +Group: Applications/Simulators +URL: http:://www.dma.tools.eu/antares + +Source0: %%SOURCE%% +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: chrpath + +Requires: glibc >= 2.12, libuuid >= 2.17, openssl >= 1.0 + +%description +Under the impulsion given by the worldwide growth of innovative technologies +(wind power, solar power, DC interconnectors, smart grids initiatives) and +new organizations (markets enlargments, regulatory frameworks), the assessment +of both adequacy and economic performance of large interconnected power systems +is getting more challenging than ever. + +Antares is a sequential Monte Carlo simulator designed to assess throughout a +whole year the economic behavior of large power systems with a 1-hour time +resolution and in several hundreds of stochastic scenarios regarding load and +generation (outages, wind speed, rainfall, nebulosity, temperature). + +%prep +%setup -q + + +%build + + +%clean +rm -rf $RPM_BUILD_ROOT + + + + +%changelog diff --git a/src/distrib/win32/build.template.cmake b/src/distrib/win32/build.template.cmake new file mode 100644 index 0000000000..0616ac54bd --- /dev/null +++ b/src/distrib/win32/build.template.cmake @@ -0,0 +1,6 @@ + +!define ANTARES_ARCH "@ANTARES_INSTALLER_ARCH@" +!define ANTARES_REDIST_ARCH "@ANTARES_INSTALLER_REDIST_ARCH@" +!define TARGET "@NSIS_TARGET@" + +!define COMPILER_MARK "@COMPILER_MARK@" diff --git a/src/distrib/win32/make-zip-from-installer.cmake b/src/distrib/win32/make-zip-from-installer.cmake new file mode 100644 index 0000000000..f67eec1365 --- /dev/null +++ b/src/distrib/win32/make-zip-from-installer.cmake @@ -0,0 +1,31 @@ + +REM +REM --- File generated by make-zip-from-installer.cmake +REM + +set ANTARES_ARCH=@ANTARES_INSTALLER_ARCH@ +set VERSION=@ANTARES_VERSION_HI@.@ANTARES_VERSION_LO@.@ANTARES_VERSION_REVISION@@ANTARES_INSTALLER_BETA@@ANTARES_INSTALLER_RC@ +set INSTALLER=rte-antares-%VERSION%-installer-%ANTARES_ARCH% +set CURRENT_DIR=%CD% + + +if not exist "%CURRENT_DIR%\%INSTALLER%.exe" goto error_prgm_missing + +if exist "%INSTALLER%" del /Q /S /F "%INSTALLER%" + +mkdir "%INSTALLER%" +copy "%INSTALLER%.exe" "%INSTALLER%" +copy "..\\..\\..\\changelog.txt" "%INSTALLER%" + +..\..\..\bin\zip.exe -9 -r "%INSTALLER%.zip" "%INSTALLER%" + +del /Q /S /F "%INSTALLER%" + +pause +goto end + + +:error_prgm_missing +REM The program %INSTALLER%.exe is missing. Please compile antares first + +:end diff --git a/src/distrib/win32/sourcefiles.inc.nsh b/src/distrib/win32/sourcefiles.inc.nsh new file mode 100644 index 0000000000..f8cb17194a --- /dev/null +++ b/src/distrib/win32/sourcefiles.inc.nsh @@ -0,0 +1,2 @@ +${SetOutPath} "$INSTDIR\Sources" +File /r ..\..\..\resources\antares-open\*.* diff --git a/src/distrib/win32/version.cmake b/src/distrib/win32/version.cmake new file mode 100644 index 0000000000..63d7cb7d2f --- /dev/null +++ b/src/distrib/win32/version.cmake @@ -0,0 +1,16 @@ + + +!define CMAKE_VERSION '@ANTARES_VERSION_HI@.@ANTARES_VERSION_LO@.@ANTARES_VERSION_REVISION@' +!define CMAKE_VERSION_BUILD '@ANTARES_VERSION_REVISION@' +!define CMAKE_SIMPLE_VERSION '@ANTARES_VERSION_HI@.@ANTARES_VERSION_LO@' + +!define CMAKE_PUBLISHER '@ANTARES_PUBLISHER@' +!define CMAKE_WEBSITE '@ANTARES_WEBSITE@' + +!define CMAKE_BUILD_TARGET '@ANTARES_VERSION_TARGET@' +!define CMAKE_INSTALLER_EXTENSION '@ANTARES_INSTALLER_EXTENSION@' + + +!define CMAKE_INSTALLER_BETA '@ANTARES_INSTALLER_BETA@' +!define CMAKE_INSTALLER_RC '@ANTARES_INSTALLER_RC@' + diff --git a/src/ext/Sirius_Solver/CMakeLists.txt b/src/ext/Sirius_Solver/CMakeLists.txt new file mode 100644 index 0000000000..037ceb8a46 --- /dev/null +++ b/src/ext/Sirius_Solver/CMakeLists.txt @@ -0,0 +1,442 @@ +if(NOT MSVC) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -Wno-unused-variable") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -Wno-unused-variable") +else() + #set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} /wd 4101") # unused local variable + #set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} /wd 4101") # unused local variable +endif() + +include_directories("branchAndBound") +include_directories("simplexe/lu") +include_directories("presolve") +include_directories("simplexe") +include_directories("pne") +include_directories("branchAndBound") +include_directories("allocateur") +include_directories("pointInterieur") + +set(RTESOLVER_PI + pointInterieur/pi_alloc_matrice.c + pointInterieur/pi_alloc_probleme.c + pointInterieur/pi_armijo.c + pointInterieur/pi_calculs_utilitaires.c + pointInterieur/pi_calstaf.c + pointInterieur/pi_cremat.c + pointInterieur/pi_cremat_systeme_augmente.c + pointInterieur/pi_incrementation.c + pointInterieur/pi_init_transposee.c + pointInterieur/pi_initxs.c + pointInterieur/pi_md_equa.c + pointInterieur/pi_qinit.c + pointInterieur/pi_quamin.c + pointInterieur/pi_quamin_calculs.c + pointInterieur/pi_resolution.c + pointInterieur/pi_gradient_conjugue.c + pointInterieur/pi_resolution_systeme_augmente.c + pointInterieur/pi_reconstruire_matrice_a_resoudre.c + pointInterieur/pi_restitution_des_resultats.c + pointInterieur/pi_scaling.c + pointInterieur/pi_sos1s2.c + pointInterieur/pi_split_colonnes.c + pointInterieur/pi_split_contraintes.c + pointInterieur/pi_constantes_externes.h + pointInterieur/pi_define.h + pointInterieur/pi_definition_arguments.h + pointInterieur/pi_fonctions.h + pointInterieur/pi_sys.h + ) + + +set(RTESOLVER_PNE + pne/pne_ajouter_la_contrainte_de_cout_max.c + pne/pne_alloc_probleme.c + pne/pne_allocations_pour_le_postsolve.c + pne/pne_ameliorer_coefficients.c + pne/pne_analyse_initiale_knapsack.c + pne/pne_analyse_initiale_variable_bounds.c + pne/pne_archiver_la_solution_courante.c + pne/pne_bb_solve_pb_rlx.c + pne/pne_calcul_coupes_dintersection.c + pne/pne_calculer_la_valeur_du_critere.c + pne/pne_calculer_les_coupes.c + pne/pne_calculer_les_gomory.c + pne/pne_calculer_restrictions_bornes.c + pne/pne_chainage_transposee.c + pne/pne_choix_des_variables_a_instancier.c + pne/pne_classer_coeff_contraintes_ordre_decroissant.c + pne/pne_cliques_controle_avant_resolution.c + pne/pne_cliques_determination.c + pne/pne_cliques_violees.c + pne/pne_clone_spx_noeud_racine.c + pne/pne_conflict_graph_alloc.c + pne/pne_conflict_graph_extensions.c + pne/pne_conflict_graph_fixer_les_voisins_dun_noeud.c + pne/pne_conflict_graph_fixer_variables.c + pne/pne_conflict_graph_MAJ.c + pne/pne_conflict_graph_supprimer_un_noeud.c + pne/pne_coupe_de_probing.c + pne/pne_coupes_de_probing_violees.c + pne/pne_cover_knapsack.c + pne/pne_cover_knapsack_combinaisons.c + pne/pne_cover_knapsack_combinaisons_complexes.c + pne/pne_cover_knapsack_lifting.c + pne/pne_cover_knapsack_simple.c + pne/pne_detection_des_contraintes_mixtes.c + pne/pne_detection_des_gub.c + pne/pne_detection_des_variables_big_M.c + pne/pne_determiner_les_variables_fractionnaires.c + pne/pne_ecrire_jeu_de_donnees_mps.c + pne/pne_ecrire_presolved_mps.c + pne/pne_enlever_tout_petits_termes.c + pne/pne_enrichir_probleme_avec_coupe.c + pne/pne_fixation_sur_critere.c + pne/pne_gomory_negligees.c + pne/pne_gomory_negligees_violees.c + pne/pne_gub.c + pne/pne_heuristique.c + pne/pne_heuristique_pilotage.c + pne/pne_heuristique_recherche_en_profondeur.c + pne/pne_heuristique_resolution_branch_and_bound_reduit.c + pne/pne_heuristique_RINS.c + pne/pne_heuristique_utilitaires.c + pne/pne_heuristique_variables_entieres_fixees.c + pne/pne_init_pne.c + pne/pne_inserer_une_contrainte.c + pne/pne_knapsack_lift_variable_continue.c + pne/pne_knapsack_negligees.c + pne/pne_knapsack_negligees_violees.c + pne/pne_knapsack_sur_coupe.c + pne/pne_lire_jeu_de_donnees_mps.c + pne/pne_MIR_agregation.c + pne/pne_majorant_knapsack.c + pne/pne_node_dm_A.c + pne/pne_node_dm_factoriser_matrice.c + pne/pne_node_dm_resoudre_primal.c + pne/pne_node_presolve.c + pne/pne_node_presolve_calculer_bornes_des_contraintes.c + pne/pne_normaliser_une_coupe.c + pne/pne_post_probing.c + pne/pne_postsolve.c + pne/pne_probing.c + pne/pne_probing_analyse_liste_de_contraintes.c + pne/pne_probing_modifier_matrice_des_contraintes.c + pne/pne_probing_nodepresolve_alloc.c + pne/pne_probing_nodepresolve_utilitaires.c + pne/pne_probing_variables_a_instancier.c + pne/pne_rand.c + pne/pne_recherche_symetries.c + pne/pne_recuperer_le_probleme_initial.c + pne/pne_recuperer_solution_et_critere.c + pne/pne_reduced_cost_fixing.c + pne/pne_reduced_cost_fixing_noeud_racine.c + pne/pne_relance_simplexe_au_noeud_racine.c + pne/pne_round.c + pne/pne_solve_pb_rlx_pi.c + pne/pne_solve_pb_rlx_spx_dual.c + pne/pne_solve_pb_rlx_spx_primal.c + pne/pne_solveur.c + pne/pne_solveur_calculs.c + pne/pne_solveur_sous_probleme.c + pne/pne_standalone.c + pne/pne_strong_branching.c + pne/pne_strong_branching_classer_le_resultat.c + pne/pne_trier_les_coupes_calculees.c + #pne/pne_two_step_mir.c + pne/mps_define.h + pne/mps_extern_global.h + pne/mps_global.h + pne/pne_constantes_externes.h + pne/pne_define.h + pne/pne_definition_arguments.h + pne/pne_fonctions.h + pne/pne_sys.h + pne/pne_cover_knapsack_lifting.c + pne/pne_knapsack_lift_variable_continue.c + pne/pne_normaliser_une_coupe.c + pne/pne_clone_spx_noeud_racine.c + pne/pne_gomory_negligees.c + pne/pne_gomory_negligees_violees.c + pne/pne_knapsack_negligees.c + pne/pne_knapsack_negligees_violees.c + pne/pne_knapsack_sur_coupe.c + pne/pne_coupes_de_probing_violees.c + pne/pne_cliques_violees.c + pne/pne_reduced_cost_fixing_noeud_racine.c + pne/pne_fixation_sur_critere.c + pne/pne_cliques_controle_avant_resolution.c + pne/pne_node_presolve.c + pne/pne_probing_nodepresolve_utilitaires.c + pne/pne_probing_analyse_liste_de_contraintes.c + pne/pne_node_presolve_calculer_bornes_des_contraintes.c + pne/pne_probing_nodepresolve_alloc.c + pne/pne_heuristique_pilotage.c + pne/pne_enlever_tout_petits_termes.c + pne/pne_mise_a_jour_seuil_coupes.c + pne/pne_reduced_cost_fixing_graphe_de_conflit.c + pne/pne_presolve_simplifie.c + pne/pne_contraintes_de_borne_variable_violees.c + pne/pne_probing_bornes_variables.c + pne/pne_compacter_matrice_des_contraintes.c + pne/pne_postsolve_si_presolve_uniquement.c + ) + + +set(RTESOLVER_LU + simplexe/lu/lu_allouer_lu.c + simplexe/lu/lu_calculs_markowitz.c + simplexe/lu/lu_classement_lignes_colonnes.c + simplexe/lu/lu_construire_probleme.c + simplexe/lu/lu_elimination_une_ligne.c + simplexe/lu/lu_elimination_une_ligne_cas_symetrique.c + simplexe/lu/lu_elimination_une_ligne_matrice_pleine.c + simplexe/lu/lu_elimination_une_ligne_turbo.c + simplexe/lu/lu_factorisation.c + simplexe/lu/lu_factorisation_calculs.c + simplexe/lu/lu_inconnues_indeterminees.c + simplexe/lu/lu_refactorisation.c + simplexe/lu/lu_refactorisation_de_la_matrice.c + simplexe/lu/lu_reorganisation_chainages.c + simplexe/lu/lu_resolution.c + simplexe/lu/lu_resolution_hyper_creux.c + simplexe/lu/lu_scaling.c + simplexe/lu/lu_scan_ligne.c + simplexe/lu/lu_scan_ligne_cas_symetrique.c + simplexe/lu/lu_scan_ligne_matrice_pleine.c + simplexe/lu/lu_scan_super_ligne.c + simplexe/lu/lu_scan_super_ligne_cas_symetrique.c + simplexe/lu/lu_selection_pivot.c + simplexe/lu/lu_selection_pivot_diagonal.c + simplexe/lu/lu_selection_pivot_matrice_pleine.c + simplexe/lu/lu_super_lignes_calculs_hashcode.c + simplexe/lu/lu_super_lignes_creations_et_fusions.c + simplexe/lu/lu_super_lignes_declenchement.c + simplexe/lu/lu_super_lignes_detection.c + simplexe/lu/lu_super_lignes_merge_toutes_super_lignes.c + simplexe/lu/lu_super_lignes_modifications.c + simplexe/lu/lu_super_lignes_reallocs.c + simplexe/lu/lu_switch_markowitz.c + simplexe/lu/lu_update.c + simplexe/lu/lu_init_tableaux_null.c + simplexe/lu/lu_constantes_externes.h + simplexe/lu/lu_define.h + simplexe/lu/lu_definition_arguments.h + simplexe/lu/lu_fonctions.h + simplexe/lu/lu_sys.h + simplexe/lu/lu_memoire.h + simplexe/lu/memstats.c + simplexe/lu/memstats.h + ) + + + +set(RTESOLVER_SPX + simplexe/spx_ajouter_coupes.c + simplexe/spx_allouer_probleme.c + simplexe/spx_calcul_couts_reduits.c + simplexe/spx_calcul_du_cout.c + simplexe/spx_calculer_a_barre_s.c + simplexe/spx_calculer_b_barre.c + simplexe/spx_calculer_pi.c + simplexe/spx_calculer_une_gomory.c + simplexe/spx_chainage_transposee.c + simplexe/spx_choix_variable_a_instancier_exploration_rapide_profondeur.c + simplexe/spx_construire_probleme.c + simplexe/spx_calcul_coupes_dintersection.c + simplexe/spx_creation_noeuds_en_exploration_rapide.c + simplexe/spx_dual_calculer_nbarre.c + simplexe/spx_dual_choix_variable_entrante.c + simplexe/spx_dual_choix_variable_sortante.c + simplexe/spx_dual_comparer_abarre_et_nbarre.c + simplexe/spx_dual_confirmer_dual_non_borne.c + simplexe/spx_dual_construire_base_initiale.c + simplexe/spx_dual_crash_base.c + simplexe/spx_dual_epurer_la_base.c + simplexe/spx_dual_phase_1_calculer_v.c + simplexe/spx_dual_phase_1_choix_variable_entrante.c + simplexe/spx_dual_phase_1_choix_variable_sortante.c + simplexe/spx_dual_phase_1_positionner_les_variables.c + simplexe/spx_dual_phase_1_simplexe.c + simplexe/spx_dual_simplexe.c + simplexe/spx_dual_steepest.c + simplexe/spx_dual_strong_branching.c + simplexe/spx_dual_strong_branching_GUB.c + simplexe/spx_ecrire_probleme_mps.c + simplexe/spx_factoriser_la_base.c + simplexe/spx_faire_changement_base.c + simplexe/spx_fixer_x_fonction_de_position.c + simplexe/spx_gestion_bases_en_exploration_rapide.c + simplexe/spx_gestion_temps_de_calcul.c + simplexe/spx_heuristique_arrondis.c + simplexe/spx_instancier_variable_dans_simplexe.c + simplexe/spx_mettre_a_jour_la_base.c + simplexe/spx_modifier_chainage_transposee.c + simplexe/spx_modifier_couts_ou_second_membre.c + simplexe/spx_modifier_probleme.c + simplexe/spx_recuperer_solution.c + simplexe/spx_recuperer_solution_exploration_rapide_en_profondeur.c + simplexe/spx_resoudre_by_egal_a.c + simplexe/spx_resoudre_ub_egal_c.c + simplexe/spx_sauvegardes_branch_and_bound.c + simplexe/spx_scaling.c + simplexe/spx_simplexe.c + simplexe/spx_simplexe_calculs.c + simplexe/spx_simplexe_generalise.c + simplexe/spx_translater_bornes.c + simplexe/spx_verifier_admissibilite_duale.c + simplexe/spx_gestion_listes_des_variables_EN_HORS_base.c + simplexe/spx_calcul_borne_auxiliaire.c + simplexe/spx_dual_controle_des_bornes_auxiliaires.c + simplexe/spx_dual_controle_optimalite.c + simplexe/spx_dual_calculer_nbarre_hyper_creux.c + simplexe/spx_dual_calculer_nbarrer_standard.c + simplexe/spx_dual_supprimer_les_bornes_auxilaires.c + simplexe/spx_verifier_erbmoins1.c + simplexe/spx_supprimer_une_borne_auxilaire.c + simplexe/spx_mettre_a_jour_b_barre.c + simplexe/spx_verifier_a_barre_s.c + simplexe/spx_calculer_erbmoins1.c + simplexe/spx_dual_controle_dual_non_borne.c + simplexe/spx_resolution_de_systeme.c + simplexe/spx_resolution_de_systeme_transposee.c + simplexe/spx_appliquer_eta_vecteurs.c + simplexe/spx_appliquer_eta_vecteurs_transposee.c + simplexe/spx_init_indicateurs_hypercreux.c + simplexe/spx_constantes_internes.h + simplexe/spx_constantes_externes.h + simplexe/spx_define.h + simplexe/spx_definition_arguments.h + simplexe/spx_fonctions.h + simplexe/spx_memoire.h + simplexe/spx_sys.h + simplexe/spx_calcul_du_cout_simplifie.c + simplexe/spx_calcul_MIR_pour_gomory_et_intersection.c + simplexe/spx_dual_reconstruire_une_base.c + simplexe/spx_dual_reconstruire_une_base.c + simplexe/spx_calculer_erbmoins1_avec_base_complete.c + simplexe/spx_calculer_b_barre_avec_base_complete.c + simplexe/spx_verifier_a_barre_s_avec_base_complete.c + simplexe/spx_calculer_erbmoins1_avec_base_reduite.c + simplexe/spx_calculer_a_barre_s_avec_base_complete.c + simplexe/spx_calculer_b_barre_avec_base_reduite.c + simplexe/spx_verifier_a_barre_s_avec_base_reduite.c + simplexe/spx_calculer_a_barre_s_avec_base_reduite.c + simplexe/spx_fixer_x_fonction_de_position_avec_base_complete.c + simplexe/spx_calcul_couts_reduits_avec_base_complete.c + simplexe/spx_mettre_a_jour_b_barre_avec_base_reduite.c + simplexe/spx_calcul_couts_reduits_avec_base_reduite.c + simplexe/spx_mettre_a_jour_b_barre_avec_base_complete.c + simplexe/spx_calculer_pi_avec_base_reduite.c + simplexe/spx_reinit_couts_natif.c + simplexe/spx_ordonner_contraintes_pour_la_base.c + simplexe/spx_dual_steepest_resolution_avec_base_complete.c + simplexe/spx_dual_steepest_resolution_avec_base_reduite.c + simplexe/spx_calculer_bbarre_hors_base_reduite.c + simplexe/spx_calculer_pi_avec_base_complete.c + simplexe/spx_construction_matrice_reduite.c + simplexe/spx_bruitage_initial_des_couts.c + ) + + +set(RTESOLVER_MEM + allocateur/mem_malloc.c + allocateur/mem_realloc.c + allocateur/mem_free.c + allocateur/mem_alloc_super_tableau.c + allocateur/mem_init_quit.c + allocateur/mem_sys.h + allocateur/mem_fonctions.h + allocateur/mem_allocateur.h + ) + + +set(RTESOLVER_BB + branchAndBound/bb_affichages_traces.c + branchAndBound/bb_alloc_desalloc_probleme.c + branchAndBound/bb_balayage_en_largeur.c + branchAndBound/bb_balayage_en_profondeur.c + branchAndBound/bb_best_first.c + branchAndBound/bb_branch_and_bound.c + branchAndBound/bb_branch_and_bound_calculs.c + branchAndBound/bb_choix_des_variables_a_instancier.c + branchAndBound/bb_controler_les_coupes_non_prises_en_compte.c + branchAndBound/bb_creation_noeud.c + branchAndBound/bb_creer_les_noeuds_fils.c + branchAndBound/bb_eliminer_les_noeuds_sous_optimaux.c + branchAndBound/bb_evaluer_en_profondeur_critiques.c + branchAndBound/bb_evaluer_fils_du_meilleur_minorant.c + branchAndBound/bb_exploration_rapide_en_profondeur.c + branchAndBound/bb_inserer_les_coupes.c + branchAndBound/bb_nettoyer_arbre.c + branchAndBound/bb_nettoyer_les_coupes.c + branchAndBound/bb_rechercher_le_meilleur_minorant.c + branchAndBound/bb_rechercher_le_noeud_avec_meilleur_ratio_fractionnaire.c + branchAndBound/bb_rechercher_le_noeud_le_moins_fractionnaire.c + branchAndBound/bb_resoudre_le_probleme_relaxe.c + branchAndBound/bb_stocker_les_coupes_du_noeud.c + branchAndBound/bb_supprimer_les_descendants_dun_noeud.c + branchAndBound/bb_define.h + branchAndBound/bb_fonctions.h + branchAndBound/bb_sys.h + ) + +set(RTESOLVER_PRS + presolve/prs_DM.c + presolve/prs_DM_A.c + presolve/prs_DM_factoriser_matrice.c + presolve/prs_DM_resoudre_dual.c + presolve/prs_DM_resoudre_primal.c + presolve/prs_DM_resoudre_systeme_transpose.c + presolve/prs_allocations.c + presolve/prs_alloc_reductions.c + presolve/prs_ameliorer_bornes.c + presolve/prs_ameliorer_coefficients.c + presolve/prs_ameliorer_contraintes_de_bornes_variables.c + presolve/prs_calcul_borne_sur_variable_avec_une_contrainte.c + presolve/prs_calcul_borne_sur_variable_duale_avec_une_variable.c + presolve/prs_calculer_bornes_contraintes.c + presolve/prs_colonnes_colineaires.c + presolve/prs_combinaisons_de_contraintes.c + presolve/prs_contraintes_colineaires.c + presolve/prs_contraintes_inactives.c + presolve/prs_contruire_graphe_DIMACS.c + presolve/prs_desactiver_contrainte.c + presolve/prs_determiner_le_type_de_borne_pour_dual.c + presolve/prs_enlever_contraintes_inactives.c + presolve/prs_fixer_une_variable_a_une_valeur.c + presolve/prs_fixer_variables_sur_critere.c + presolve/prs_maj_variable_duale.c + presolve/prs_mettre_a_jour_bornes_des_variables.c + presolve/prs_mettre_a_jour_bornes_des_variables_duales.c + presolve/prs_presolve.c + presolve/prs_singleton_colonne.c + presolve/prs_singleton_ligne.c + presolve/prs_substituer_variables.c + presolve/prs_substituer_variables_non_bornees.c + presolve/prs_supprimer_contraintes_sans_variables.c + presolve/prs_variable_probing.c + presolve/prs_variables_hors_contraintes.c + presolve/prs_variables_duales_ameliorer_bornes.c + presolve/prs_variables_duales_et_couts_reduits.c + presolve/prs_variables_duales_non_bornees.c + presolve/prs_variables_non_bornees.c + presolve/prs_define.h + presolve/prs_fonctions.h + presolve/prs_sys.h + ) + +set(SRC_SOLVER + ${RTESOLVER_SPX} + ${RTESOLVER_LU} + ${RTESOLVER_PRS} + ${RTESOLVER_PNE} + ${RTESOLVER_BB} + ${RTESOLVER_PI} + ${RTESOLVER_MEM} +) + +add_library(libsolver_antares STATIC ${SRC_SOLVER}) + +add_library(libsolver_antares-swap STATIC ${SRC_SOLVER}) + +set_target_properties(libsolver_antares-swap + PROPERTIES COMPILE_FLAGS " -DANTARES_SWAP_SUPPORT=1") \ No newline at end of file diff --git a/src/ext/Sirius_Solver/LICENSE.txt b/src/ext/Sirius_Solver/LICENSE.txt new file mode 100644 index 0000000000..e7b4a87947 --- /dev/null +++ b/src/ext/Sirius_Solver/LICENSE.txt @@ -0,0 +1,82 @@ + + +Eclipse Public License - v 2.0 + +THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + + 1. DEFINITIONS + + "Contribution" means: + a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + + where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution "originates" from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works. + + "Contributor" means any person or entity that Distributes the Program. + + "Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. + + "Program" means the Contributions Distributed in accordance with this Agreement. + + "Recipient" means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors. + + "Derivative Works" shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. + + "Modified Works" shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. + + "Distribute" means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. + + "Source Code" means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. + + "Secondary License" means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. + 2. GRANT OF RIGHTS + a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works. + b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. + c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. + d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. + e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). + 3. REQUIREMENTS + 3.1 If a Contributor Distributes the Program in any form, then: + a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and + b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; + ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; + iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and + iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. + 3.2 When the Program is Distributed as Source Code: + a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and + b) a copy of this Agreement must be included with each copy of the Program. + 3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability ("notices") contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. + 4. COMMERCIAL DISTRIBUTION + + Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. + + For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. + 5. NO WARRANTY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. + 6. DISCLAIMER OF LIABILITY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + 7. GENERAL + + If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + + If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. + + All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. + + Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version. + + Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. + Exhibit A - Form of Secondary Licenses Notice + + "This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. + + You may add additional accurate notices of copyright ownership. diff --git a/src/ext/Sirius_Solver/allocateur/mem_alloc_super_tableau.c b/src/ext/Sirius_Solver/allocateur/mem_alloc_super_tableau.c new file mode 100644 index 0000000000..048f26d340 --- /dev/null +++ b/src/ext/Sirius_Solver/allocateur/mem_alloc_super_tableau.c @@ -0,0 +1,111 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Allocation d'un super tableau + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "mem_allocateur.h" + +/**************************************************************************/ + +char MEM_AllocSuperTableau( void * h, long Taille ) +{ +long i; long j; MEMOIRE_THREAD * Mem; BLOCS_LIBRES * BlocsLibres; long Shift; + +Mem = (MEMOIRE_THREAD *) h; + +i = Mem->NombreDeSuperTableaux; +Mem->NombreDeSuperTableaux++; +if ( i == 0 ) { + Mem->AdresseSuperTableau = (char **) malloc( Mem->NombreDeSuperTableaux * sizeof( unsigned long ) ); + if ( Mem->AdresseSuperTableau == NULL ) return( 0 ); + Mem->DescriptionDesBlocsLibres = (BLOCS_LIBRES **) malloc( Mem->NombreDeSuperTableaux * sizeof( unsigned long ) ); + if ( Mem->DescriptionDesBlocsLibres == NULL ) return( 0 ); +} +else { + Mem->AdresseSuperTableau = (char **) realloc( Mem->AdresseSuperTableau, Mem->NombreDeSuperTableaux * sizeof( unsigned long ) ); + if ( Mem->AdresseSuperTableau == NULL ) return( 0 ); + Mem->DescriptionDesBlocsLibres = (BLOCS_LIBRES **) realloc( Mem->DescriptionDesBlocsLibres, Mem->NombreDeSuperTableaux * sizeof( unsigned long ) ); + if ( Mem->DescriptionDesBlocsLibres == NULL ) return( 0 ); +} + + +Mem->AdresseSuperTableau[i] = (char *) malloc( (size_t) Taille ); +if ( Mem->AdresseSuperTableau[i] == NULL ) return( 0 ); +Mem->DescriptionDesBlocsLibres[i] = (BLOCS_LIBRES *) malloc( sizeof( BLOCS_LIBRES ) ); + +/* On cree l'entete */ +BlocsLibres = Mem->DescriptionDesBlocsLibres[i]; + +j = CHUNK_CELLULES_DESCRIPITIVES; +BlocsLibres->AdresseDuBlocLibre = (char **) malloc( j * sizeof( unsigned long ) ); +if ( BlocsLibres->AdresseDuBlocLibre == NULL ) return( 0 ); +BlocsLibres->TailleDuBlocLibre = (long *) malloc( j * sizeof( long ) ); +if ( BlocsLibres->TailleDuBlocLibre == NULL ) return( 0 ); + +BlocsLibres->NombreDeCellulesDescriptivesAllouees = j; + +BlocsLibres->NombreDeBlocsLibres = 1; +BlocsLibres->NombreDeNouveauxBlocsLibres = 0; +BlocsLibres->AdresseDuBlocLibre[0] = Mem->AdresseSuperTableau[i]; +BlocsLibres->TailleDuBlocLibre [0] = Taille; +BlocsLibres->PlusGrandeTailleDispo = Taille; +BlocsLibres->TailleInitialeDuSuperTableau = Taille; +BlocsLibres->TailleDisponible = Taille; + +if ( Taille != Mem->TailleStandard ) { + BlocsLibres->SuperTableauStandard = 0; +} +else { + BlocsLibres->SuperTableauStandard = 1; + Mem->NombreDeSuperTableauxStandards++; + /* Mise a jour eventuelle de la taille standard */ + Shift = Mem->NombreDeSuperTableauxStandards / CYCLE_SHIFT; + /* On limite le shift a 4 ce qui est equivalent a limiter la taille standard a 16 fois la + taille de depart */ + if ( Shift > 4 ) Shift = 4; + Mem->TailleStandard = Mem->TailleStandardDeDepart << Shift; + + # ifdef TRACES_ALLOC_SUPERTABLEAU + if ( Shift != 0 ) { + printf("SuperTableauxStandards %ld NombreDeSuperTableaux %d taille standard %ld taille initiale %ld shift %ld\n", + Mem->NombreDeSuperTableauxStandards, Mem->NombreDeSuperTableaux, Mem->TailleStandard, + (long) TAILLE_STANDARD, Shift); + } + # endif + +} + +/* S'il n'y a aucun tableau standard alors on dit que le tableau qui vient d'etre cree est standard */ +/* Ceci permet d'ajuster la taille standard de depart si la taille parametree ne convient pas */ +if ( Mem->NombreDeSuperTableauxStandards == 0 ) { + BlocsLibres->SuperTableauStandard = 1; + Mem->NombreDeSuperTableauxStandards = 1; + Mem->TailleStandard = Taille; + Mem->TailleStandardDeDepart = Taille; +} + +Mem->PageAllocEnCours = i; + +return( 1 ); +} + + diff --git a/src/ext/Sirius_Solver/allocateur/mem_allocateur.h b/src/ext/Sirius_Solver/allocateur/mem_allocateur.h new file mode 100644 index 0000000000..d360a5e5fe --- /dev/null +++ b/src/ext/Sirius_Solver/allocateur/mem_allocateur.h @@ -0,0 +1,96 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __CPLUSPLUS + extern "C" + { +# endif +# ifndef DONNEES_INTERNES_MEMOIRE_DEJA_DEFINIES +/*****************************************************************/ + +# define DEBUG +# undef DEBUG + +# define TRACES_MALLOC +# undef TRACES_MALLOC + +# define TRACES_ALLOC_SUPERTABLEAU +# undef TRACES_ALLOC_SUPERTABLEAU + +# define TRACES_DEFRAG +# undef TRACES_DEFRAG + +# define TRACES_QUIT +# undef TRACES_QUIT + +# define FREQUENCE_DEFRAG 100 +# define CHUNK_CELLULES_DESCRIPITIVES 1000 + +# define ALIGN(x) x=x>>3;x=x<<3;x+=8 + +# include "mem_sys.h" + +typedef struct { +long Taille; /* En octets */ +char * AdresseBlocsLibres; +long NombreDAllocs; +long PourMutipleDe8; +} ENTETE; + +/* Blocs libres d'un super tableau */ +typedef struct { +long NombreDeBlocsLibres; +long * TailleDuBlocLibre; +char ** AdresseDuBlocLibre; +long NombreDeCellulesDescriptivesAllouees; +long NombreDeNouveauxBlocsLibres; +long PlusGrandeTailleDispo; /* C'est approximatif */ +long TailleDisponible; +long TailleInitialeDuSuperTableau; +long SuperTableauStandard; /* 1 si oui, 0 si non */ +} BLOCS_LIBRES; + +# include "mem_fonctions.h" + +typedef struct { +long PageAllocEnCours; +/* Pour chaque super tableau */ +long NombreDeSuperTableaux; +BLOCS_LIBRES ** DescriptionDesBlocsLibres; +char ** AdresseSuperTableau; + +long NombreDeSuperTableauxStandards; +long TailleStandardDeDepart; +long TailleStandard; + +} MEMOIRE_THREAD; + +# define CYCLE_SHIFT 5 +# define TAILLE_STANDARD (1024*1024*2) +# define TAILLE_MIN_USER (1024) /* Ce qu'il doit rester au minimum pour creer un bloc */ +# define TAILLE_MIN_BLOC ( sizeof( ENTETE ) + TAILLE_MIN_USER ) + +long MEM_ClassementTriRapide( char ** , long * , long , long ); +void MEM_Classement( char ** , long * , long , long ); +void MEM_DefragmenterLEspaceLibre( BLOCS_LIBRES * ); +char MEM_AllocSuperTableau( void * , long ); + +/*****************************************************************/ +# define DONNEES_INTERNES_MEMOIRE_DEJA_DEFINIES +# endif +# ifdef __CPLUSPLUS + } +# endif diff --git a/src/ext/Sirius_Solver/allocateur/mem_fonctions.h b/src/ext/Sirius_Solver/allocateur/mem_fonctions.h new file mode 100644 index 0000000000..3337c23a7b --- /dev/null +++ b/src/ext/Sirius_Solver/allocateur/mem_fonctions.h @@ -0,0 +1,36 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __CPLUSPLUS + extern "C" + { +# endif +# ifndef FONCTION_EXTERNES_MEMOIRE_DEJA_DEFINIES +/*****************************************************************/ + +void * MEM_Init( void ); +void MEM_Quit( void * ); +char * MEM_Malloc( void * , size_t ); +void MEM_Free( void * ); +char * MEM_Realloc( void * , void * , size_t ); +long MEM_QuantiteLibre( BLOCS_LIBRES * ); + +/*****************************************************************/ +# define FONCTION_EXTERNES_MEMOIRE_DEJA_DEFINIES +# endif +# ifdef __CPLUSPLUS + } +# endif diff --git a/src/ext/Sirius_Solver/allocateur/mem_free.c b/src/ext/Sirius_Solver/allocateur/mem_free.c new file mode 100644 index 0000000000..ba66b48e08 --- /dev/null +++ b/src/ext/Sirius_Solver/allocateur/mem_free.c @@ -0,0 +1,103 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/*********************************************************************** + +FONCTION: Remplace le free + +AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "mem_allocateur.h" + +/**************************************************************************/ + +void MEM_Free( void * Adresse ) +{ +long j; char * AdresseALibere; long Taille ; long * TailleDuBlocLibre ; +BLOCS_LIBRES * BlocsLibres ; long NombreDeBlocsLibres; char ** AdresseDuBlocLibre; + +if ( Adresse == NULL ) return; + +AdresseALibere = (char *) Adresse - sizeof( ENTETE ); + +Taille = ((ENTETE *) AdresseALibere)->Taille; + +BlocsLibres = (BLOCS_LIBRES *) ((ENTETE *) AdresseALibere)->AdresseBlocsLibres; + +NombreDeBlocsLibres = BlocsLibres->NombreDeBlocsLibres; +AdresseDuBlocLibre = BlocsLibres->AdresseDuBlocLibre; +TailleDuBlocLibre = BlocsLibres->TailleDuBlocLibre; + +/* On regarde si on peut merger la nouvelle zone avec la derniere libre */ +if ( NombreDeBlocsLibres > 0 ) { + j = NombreDeBlocsLibres - 1; + if ( AdresseALibere + Taille == AdresseDuBlocLibre[j] ) { + AdresseDuBlocLibre[j] = AdresseALibere; + TailleDuBlocLibre [j]+= Taille; + if ( TailleDuBlocLibre[j] > BlocsLibres->PlusGrandeTailleDispo ) { + BlocsLibres->PlusGrandeTailleDispo = TailleDuBlocLibre[j]; + } + BlocsLibres->TailleDisponible+= Taille; + if ( NombreDeBlocsLibres == 1 ) BlocsLibres->PlusGrandeTailleDispo = TailleDuBlocLibre[0]; + BlocsLibres->NombreDeNouveauxBlocsLibres++; + return; + } + if ( AdresseDuBlocLibre[j] + TailleDuBlocLibre[j] == AdresseALibere ) { + TailleDuBlocLibre[j]+= Taille; + if ( TailleDuBlocLibre[j] > BlocsLibres->PlusGrandeTailleDispo ) { + BlocsLibres->PlusGrandeTailleDispo = TailleDuBlocLibre[j]; + } + BlocsLibres->TailleDisponible+= Taille; + if ( NombreDeBlocsLibres == 1 ) BlocsLibres->PlusGrandeTailleDispo = TailleDuBlocLibre[0]; + BlocsLibres->NombreDeNouveauxBlocsLibres++; + return; + } +} + +/* On place le bloc a la fin */ + +if ( NombreDeBlocsLibres >= BlocsLibres->NombreDeCellulesDescriptivesAllouees ) { + BlocsLibres->NombreDeCellulesDescriptivesAllouees+= CHUNK_CELLULES_DESCRIPITIVES; + j = BlocsLibres->NombreDeCellulesDescriptivesAllouees; + + BlocsLibres->AdresseDuBlocLibre = (char **) realloc( BlocsLibres->AdresseDuBlocLibre, j * sizeof( unsigned long ) ); + if ( BlocsLibres->AdresseDuBlocLibre == NULL ) { + printf("Saturation memoire dans l'allocateur de memoire\n"); + return; + } + BlocsLibres->TailleDuBlocLibre = (long *) realloc( BlocsLibres->TailleDuBlocLibre , j * sizeof( long ) ); + if ( BlocsLibres->TailleDuBlocLibre == NULL ) { + printf("Saturation memoire dans l'allocateur de memoire\n"); + return; + } +} + +BlocsLibres->AdresseDuBlocLibre[NombreDeBlocsLibres] = AdresseALibere; +BlocsLibres->TailleDuBlocLibre [NombreDeBlocsLibres] = Taille; + +if ( Taille > BlocsLibres->PlusGrandeTailleDispo ) BlocsLibres->PlusGrandeTailleDispo = Taille; + +BlocsLibres->TailleDisponible+= Taille; +BlocsLibres->NombreDeBlocsLibres++; +BlocsLibres->NombreDeNouveauxBlocsLibres++; +if ( BlocsLibres->NombreDeBlocsLibres == 1 ) BlocsLibres->PlusGrandeTailleDispo = BlocsLibres->TailleDuBlocLibre[0]; + +return; +} + diff --git a/src/ext/Sirius_Solver/allocateur/mem_init_quit.c b/src/ext/Sirius_Solver/allocateur/mem_init_quit.c new file mode 100644 index 0000000000..ec0ffb8988 --- /dev/null +++ b/src/ext/Sirius_Solver/allocateur/mem_init_quit.c @@ -0,0 +1,199 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/*********************************************************************** +FONCTION: Init et Quit de l'allocateur et utilitaires + +AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "mem_allocateur.h" + +/**************************************************************************/ + +void * MEM_Init() +{ +MEMOIRE_THREAD * h; + +h = (MEMOIRE_THREAD *) malloc( sizeof( MEMOIRE_THREAD ) ); +if ( h != NULL ) { + h->NombreDeSuperTableaux = 0; + h->PageAllocEnCours = 0; + h->NombreDeSuperTableauxStandards = 0; + h->TailleStandard = (long) TAILLE_STANDARD; + h->TailleStandardDeDepart = (long) TAILLE_STANDARD; +} + +/* Allocation d'un super petit tableau */ +if ( MEM_AllocSuperTableau( (void *)h, (long) (TAILLE_STANDARD >> 1) ) == 0 ) return( NULL ); + +/* Allocation d'un super tableau taille standard: il en faut au moins 1 de taille standard au depart */ +if ( MEM_AllocSuperTableau( (void *)h, (long) TAILLE_STANDARD ) == 0 ) return( NULL ); + +return( (void *) h ); +} + +/**************************************************************************/ + +void MEM_Quit( void * h ) +{ +long i; MEMOIRE_THREAD * Mem; BLOCS_LIBRES * BlocsLibres; + +if ( h == NULL ) return; +Mem = (MEMOIRE_THREAD *) h; + +# ifdef TRACES_QUIT + printf("Nombre de super tableaux alloues %ld\n",Mem->NombreDeSuperTableaux); +# endif + +for ( i = 0 ; i < Mem->NombreDeSuperTableaux ; i++ ) { + BlocsLibres = Mem->DescriptionDesBlocsLibres[i]; + free( Mem->AdresseSuperTableau[i] ); + free( BlocsLibres->AdresseDuBlocLibre ); + free( BlocsLibres->TailleDuBlocLibre ); + free( BlocsLibres ); +} + +/*printf("Liberation du tas terminee nombre d'allocations %ld\n",Mem->Allocation);*/ + +free( Mem->AdresseSuperTableau ); +free( Mem->DescriptionDesBlocsLibres ); +free( Mem ); + +return; +} + +/**************************************************************************/ + +long MEM_QuantiteLibre( BLOCS_LIBRES * BlocsLibres ) +{ long k; long T; long * TailleDuBlocLibre; + T = 0; + TailleDuBlocLibre = BlocsLibres->TailleDuBlocLibre; + for ( k = 0 ; k < BlocsLibres->NombreDeBlocsLibres; k++ ) { + T+= TailleDuBlocLibre[k]; + } + return( T ); +} + +/**************************************************************************/ + +long MEM_ClassementTriRapide( char ** AdresseDuBlocLibre, long * TailleDuBlocLibre, + long Deb, long Fin ) +{ +long Compt; char * Pivot; long i; long DebPlus1; char * Adresse; long Taille; + +DebPlus1 = Deb + 1; +Compt = Deb; +Pivot = AdresseDuBlocLibre[Deb]; + +for ( i = DebPlus1 ; i <= Fin ; i++) { + if ( AdresseDuBlocLibre[i] < Pivot) { + Compt++; + Adresse = AdresseDuBlocLibre[Compt]; + AdresseDuBlocLibre[Compt] = AdresseDuBlocLibre[i]; + AdresseDuBlocLibre[i] = Adresse; + Taille = TailleDuBlocLibre[Compt]; + TailleDuBlocLibre[Compt] = TailleDuBlocLibre[i]; + TailleDuBlocLibre[i] = Taille; + } +} + +Adresse = AdresseDuBlocLibre[Compt]; +AdresseDuBlocLibre[Compt] = AdresseDuBlocLibre[Deb]; +AdresseDuBlocLibre[Deb] = Adresse; +Taille = TailleDuBlocLibre[Compt]; +TailleDuBlocLibre[Compt] = TailleDuBlocLibre[Deb]; +TailleDuBlocLibre[Deb] = Taille; + +return(Compt); +} + +/**************************************************************************/ +void MEM_Classement( char ** AdresseDuBlocLibre, long * TailleDuBlocLibre, + long Debut, long Fin ) +{ +long Pivot; +if ( Debut < Fin ) { + Pivot = MEM_ClassementTriRapide( AdresseDuBlocLibre, TailleDuBlocLibre, Debut, Fin ); + MEM_Classement( AdresseDuBlocLibre, TailleDuBlocLibre, Debut , Pivot-1 ); + MEM_Classement( AdresseDuBlocLibre, TailleDuBlocLibre, Pivot+1, Fin ); +} +return; +} +/**************************************************************************/ + +void MEM_DefragmenterLEspaceLibre( BLOCS_LIBRES * BlocsLibres ) +{ +long * TailleDuBlocLibre; char ** AdresseDuBlocLibre; long NombreDeBlocsLibres; long N1; +char * A0; char * A1; long T1; long i; long j; long PlusGrandeTailleDispo; + +NombreDeBlocsLibres = BlocsLibres->NombreDeBlocsLibres; +AdresseDuBlocLibre = BlocsLibres->AdresseDuBlocLibre; +TailleDuBlocLibre = BlocsLibres->TailleDuBlocLibre; + +# ifdef TRACES_DEFRAG + printf("Defragmentation d'un super tableau:\n"); + printf(" Avant:\n"); + printf(" Taille du super tableau %ld\n", BlocsLibres->TailleInitialeDuSuperTableau); + printf(" Taille disponible %ld\n", BlocsLibres->TailleDisponible); + printf(" NombreDeBlocsLibres %ld\n", BlocsLibres->NombreDeBlocsLibres); + printf(" Plus grand bloc libre %ld (approx)\n", BlocsLibres->PlusGrandeTailleDispo); + BlocsLibres->PlusGrandeTailleDispo = 0; + for ( i = 0 ; i < NombreDeBlocsLibres ; i++ ) { + if ( TailleDuBlocLibre[i] > BlocsLibres->PlusGrandeTailleDispo ) BlocsLibres->PlusGrandeTailleDispo = TailleDuBlocLibre[i]; + } + printf(" Plus grand bloc libre %ld (calcule)\n", BlocsLibres->PlusGrandeTailleDispo); +# endif + +/* On reclasse les blocs dans l'ordre croissant des adresses */ +MEM_Classement( AdresseDuBlocLibre, TailleDuBlocLibre,0 ,NombreDeBlocsLibres-1 ); + +PlusGrandeTailleDispo = 0; + +/* On fusionne */ +N1 = 0; +for ( i = 0 ; i < NombreDeBlocsLibres ; ) { + A0 = AdresseDuBlocLibre[i]; + T1 = TailleDuBlocLibre[i]; + A1 = A0 + T1; + for ( j = i+1 ; j < NombreDeBlocsLibres ; j++ ) { + if ( A1 == AdresseDuBlocLibre[j] ) { + A1+= TailleDuBlocLibre[j]; + T1+= TailleDuBlocLibre[j]; + } + else break; + } + AdresseDuBlocLibre[N1] = A0; + TailleDuBlocLibre [N1] = T1; + if ( T1 > PlusGrandeTailleDispo ) PlusGrandeTailleDispo = T1; + N1++; + i = j; +} + +BlocsLibres->NombreDeBlocsLibres = N1; +BlocsLibres->NombreDeNouveauxBlocsLibres = 0; +BlocsLibres->PlusGrandeTailleDispo = PlusGrandeTailleDispo; + +# ifdef TRACES_DEFRAG + printf(" Apres:\n"); + printf(" NombreDeBlocsLibres %ld\n", BlocsLibres->NombreDeBlocsLibres); + printf(" Plus grand bloc libre %ld\n", BlocsLibres->PlusGrandeTailleDispo); +# endif + +return; +} diff --git a/src/ext/Sirius_Solver/allocateur/mem_malloc.c b/src/ext/Sirius_Solver/allocateur/mem_malloc.c new file mode 100644 index 0000000000..6b9a860f9f --- /dev/null +++ b/src/ext/Sirius_Solver/allocateur/mem_malloc.c @@ -0,0 +1,193 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + +FONCTION: Remplace le malloc + +AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "mem_allocateur.h" + +/**************************************************************************/ + +char * MEM_Malloc( void * h, size_t NombreDOctets ) +{ +long NbOctetsAReserver ; long i; long j; long Taille; long i0; long i1; char Flag; +MEMOIRE_THREAD * Mem ; ENTETE * EnteteAAllouer ; char * AdresseAllouee ; +BLOCS_LIBRES * BlocsLibres; long NombreDeBlocsLibres ; long DernierBloc ; +char ** AdresseDuBlocLibre; long * TailleDuBlocLibre ; long TailleRestante ; +long PlusGrandBlocLibre ; long TailleBlocLibre ; +# ifdef TRACES_MALLOC + long T; long Ti; +# endif + +AdresseAllouee = NULL; +if ( h == NULL ) return( AdresseAllouee ); + +Mem = (MEMOIRE_THREAD *) h; + +NbOctetsAReserver = (long ) NombreDOctets + sizeof( ENTETE ); + +ALIGN( NbOctetsAReserver ); + +RechercheBlocLibre: +i0 = Mem->PageAllocEnCours; +i1 = Mem->NombreDeSuperTableaux; +Flag = 0; +NewMalloc: +for ( i = i0 ; i < i1 ; i++ ) { + + /* Boucle sur les blocs libres du super tableau */ + BlocsLibres = Mem->DescriptionDesBlocsLibres[i]; + if ( BlocsLibres->NombreDeBlocsLibres == 0 ) continue; + + # ifdef DEBUG + /* Controle */ + if ( MEM_QuantiteLibre( BlocsLibres ) != BlocsLibres->TailleDisponible ) { + printf("Malloc: erreur taille disponible T %ld TailleDisponible %ld TailleInitialeDuSuperTableau %ld\n", + MEM_QuantiteLibre( BlocsLibres ),BlocsLibres->TailleDisponible,BlocsLibres->TailleInitialeDuSuperTableau); + } + # endif + + if ( BlocsLibres->TailleDisponible < NbOctetsAReserver ) continue; + + if ( BlocsLibres->NombreDeNouveauxBlocsLibres > FREQUENCE_DEFRAG ) { + MEM_DefragmenterLEspaceLibre( BlocsLibres ); + } + + if ( BlocsLibres->PlusGrandeTailleDispo < NbOctetsAReserver ) continue; + + NombreDeBlocsLibres = BlocsLibres->NombreDeBlocsLibres; + AdresseDuBlocLibre = BlocsLibres->AdresseDuBlocLibre; + TailleDuBlocLibre = BlocsLibres->TailleDuBlocLibre; + PlusGrandBlocLibre = 0; + + /* Strategie first fit */ + + for ( j = 0 ; j < NombreDeBlocsLibres ; j++ ) { + TailleBlocLibre = TailleDuBlocLibre[j]; + if ( TailleBlocLibre > PlusGrandBlocLibre ) PlusGrandBlocLibre = TailleBlocLibre; + if ( TailleBlocLibre >= NbOctetsAReserver ) { + /* Mise a jour de l'entete */ + EnteteAAllouer = (ENTETE *) AdresseDuBlocLibre[j]; + TailleRestante = TailleBlocLibre - NbOctetsAReserver; + if ( TailleRestante >= (long) TAILLE_MIN_BLOC ) { + /* On peut creer un bloc libre juste apres */ + EnteteAAllouer->Taille = NbOctetsAReserver; + EnteteAAllouer->AdresseBlocsLibres = (char *) BlocsLibres; + EnteteAAllouer->NombreDAllocs = 0; + + /* Mise a jour des blocs libres */ + AdresseDuBlocLibre[j]+= NbOctetsAReserver; + TailleDuBlocLibre [j]-= NbOctetsAReserver; + BlocsLibres->TailleDisponible-= NbOctetsAReserver; + if ( NombreDeBlocsLibres == 1 ) BlocsLibres->PlusGrandeTailleDispo = TailleDuBlocLibre[0]; + } + else { + /* On alloue tout le bloc */ + EnteteAAllouer->Taille = TailleBlocLibre; + EnteteAAllouer->AdresseBlocsLibres = (char *) BlocsLibres; + EnteteAAllouer->NombreDAllocs = 0; + + BlocsLibres->TailleDisponible-= TailleBlocLibre; + /* On supprime le bloc */ + DernierBloc = NombreDeBlocsLibres - 1; + AdresseDuBlocLibre[j] = AdresseDuBlocLibre[DernierBloc]; + TailleDuBlocLibre [j] = TailleDuBlocLibre[DernierBloc]; + if ( NombreDeBlocsLibres == 1 ) BlocsLibres->PlusGrandeTailleDispo = TailleDuBlocLibre[0]; + BlocsLibres->NombreDeBlocsLibres--; + BlocsLibres->NombreDeNouveauxBlocsLibres--; + } + AdresseAllouee = (char *) EnteteAAllouer + sizeof( ENTETE ); + Mem->PageAllocEnCours = i; + /*printf("Adresse allouee %X taille utile %ld taille reservee %d\n",AdresseAllouee,NombreDOctets,NbOctetsAReserver);*/ + return( AdresseAllouee ); + } + } + BlocsLibres->PlusGrandeTailleDispo = PlusGrandBlocLibre; +} +if ( Flag == 0 ) { + Flag = 1; + i0 = 0; + i1 = Mem->PageAllocEnCours; + goto NewMalloc; +} + +/* Avant de creer un nouveau super tableau, on vire tous les tableaux vides dans lesquels on n'a rien pu mettre */ + +/* Un gros tableau inutilise est vire */ +for ( i = 0 ; i < Mem->NombreDeSuperTableaux ; ) { + BlocsLibres = Mem->DescriptionDesBlocsLibres[i]; + if ( BlocsLibres->NombreDeBlocsLibres == 1 ) { + if ( BlocsLibres->TailleInitialeDuSuperTableau == BlocsLibres->TailleDuBlocLibre[0] ) { + # ifdef TRACES_MALLOC + printf("On vire un super tableau de taille %ld \n",BlocsLibres->TailleInitialeDuSuperTableau); + # endif + + if ( BlocsLibres->SuperTableauStandard == 1 ) Mem->NombreDeSuperTableauxStandards--; + + free( BlocsLibres->AdresseDuBlocLibre ); + free( BlocsLibres->TailleDuBlocLibre ); + free( BlocsLibres ); + free( Mem->AdresseSuperTableau[i] ); + + j = Mem->NombreDeSuperTableaux-1; + Mem->DescriptionDesBlocsLibres[i] = Mem->DescriptionDesBlocsLibres[j]; + Mem->AdresseSuperTableau [i] = Mem->AdresseSuperTableau[j]; + Mem->NombreDeSuperTableaux--; + + continue; + } + } + i++; +} +Mem->PageAllocEnCours = 0; /* Mise a jour a la creation du prochain super tableau */ + +# ifdef TRACES_MALLOC + T = 0; + Ti = 0; + for ( i = 0 ; i < Mem->NombreDeSuperTableaux ; i++ ) { + BlocsLibres = Mem->DescriptionDesBlocsLibres[i]; + T+= BlocsLibres->TailleInitialeDuSuperTableau; + NombreDeBlocsLibres = BlocsLibres->NombreDeBlocsLibres; + TailleDuBlocLibre = BlocsLibres->TailleDuBlocLibre; + for ( j = 0 ; j < NombreDeBlocsLibres ; j++ ) Ti+= TailleDuBlocLibre[j]; + } + printf("Nombre de tableaux deja alloues %ld Taille %ld Mo taille inutilisee %ld\n", + Mem->NombreDeSuperTableaux,T/(1024*1024),Ti/(1024*1024)); +# endif + +Taille = Mem->TailleStandard; +if ( NbOctetsAReserver > Taille ) { + Taille = NbOctetsAReserver + Mem->TailleStandard /*(long) ceil( 1.5 * NbOctetsAReserver )*/; + # ifdef TRACES_MALLOC + printf("Alloc gros tableau %ld\n",Taille); + # endif +} +/* Allocation d'un super tableau */ +if ( MEM_AllocSuperTableau( (void *) Mem, Taille ) == 0 ) return( NULL ); + +goto RechercheBlocLibre; /* Comme ce nouveau super tableau est adapter, c'est celui qui va etre utilise */ + +/* On ne passe donc jamais la */ +return( AdresseAllouee ); +} + + + diff --git a/src/ext/Sirius_Solver/allocateur/mem_realloc.c b/src/ext/Sirius_Solver/allocateur/mem_realloc.c new file mode 100644 index 0000000000..9eefd73037 --- /dev/null +++ b/src/ext/Sirius_Solver/allocateur/mem_realloc.c @@ -0,0 +1,178 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/*********************************************************************** + +FONCTION: Remplace le realloc + +AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "mem_allocateur.h" + +/**************************************************************************/ + +char * MEM_Realloc( void * h, void * Pt, size_t NombreDOctets ) +{ +long i;long j;long Taille ; long NouvelleTaille ; long TailleDispo ; +char * NouvelleAdresse ; MEMOIRE_THREAD * Mem ; ENTETE * Entete ; +BLOCS_LIBRES * BlocsLibres; long NombreDeBlocsLibres; long Supplement ; +char ** AdresseDuBlocLibre; long * TailleDuBlocLibre; long Nboct ; +long TaillePageRecuperee ; long NombreDAllocs ; char * AdresseFin; +long NboctPossible ; long TailleRestante ; long T2 ; + +NouvelleAdresse = NULL; + +if ( h == NULL ) return( NouvelleAdresse ); + +Mem = (MEMOIRE_THREAD *) h; + +/* Si la taille demandee est plus petite on ne fait rien */ +Entete = (ENTETE *) ((char *) Pt - sizeof( ENTETE )); +Taille = Entete->Taille; +BlocsLibres = (BLOCS_LIBRES *) Entete->AdresseBlocsLibres; +Entete->NombreDAllocs++; + +TailleDispo = Taille - sizeof(ENTETE); +NombreDAllocs = Entete->NombreDAllocs; + +Nboct = (long) NombreDOctets + sizeof( ENTETE ); +ALIGN( Nboct ); + +/* Si l'utilisateur veut retailler la zone en beaucoup plus petit, on le fait */ +if ( Nboct < (long) (0.1 * Taille) ) { + /*printf("On retaille une zone allouee en plus petit ancienne taille %ld nouvelle taille %ld\n",Taille,Nboct);*/ + TaillePageRecuperee = Taille - Nboct; + if ( TaillePageRecuperee >= (long) TAILLE_MIN_BLOC ) { + NombreDeBlocsLibres = BlocsLibres->NombreDeBlocsLibres; + AdresseDuBlocLibre = BlocsLibres->AdresseDuBlocLibre; + TailleDuBlocLibre = BlocsLibres->TailleDuBlocLibre; + /* On peut creer un bloc libre juste apres */ + /* On retaille le bloc */ + Entete->Taille = Nboct; + + /* On cree un nouveeau bloc libre derriere entete derriere */ + if ( NombreDeBlocsLibres >= BlocsLibres->NombreDeCellulesDescriptivesAllouees ) { + BlocsLibres->NombreDeCellulesDescriptivesAllouees+= CHUNK_CELLULES_DESCRIPITIVES; + j = BlocsLibres->NombreDeCellulesDescriptivesAllouees; + BlocsLibres->AdresseDuBlocLibre = (char **) realloc( BlocsLibres->AdresseDuBlocLibre, j * sizeof( unsigned long ) ); + if ( BlocsLibres->AdresseDuBlocLibre == NULL ) { + printf("Saturation memoire dans l'allocateur de memoire\n"); + return( NULL ); + } + BlocsLibres->TailleDuBlocLibre = (long *) realloc( BlocsLibres->TailleDuBlocLibre , j * sizeof( long ) ); + if ( BlocsLibres->TailleDuBlocLibre == NULL ) { + printf("Saturation memoire dans l'allocateur de memoire\n"); + return( NULL ); + } + } + + BlocsLibres->AdresseDuBlocLibre[NombreDeBlocsLibres] = (char *) Entete + Nboct; + BlocsLibres->TailleDuBlocLibre [NombreDeBlocsLibres] = TaillePageRecuperee; + + if ( TaillePageRecuperee > BlocsLibres->PlusGrandeTailleDispo ) BlocsLibres->PlusGrandeTailleDispo = TaillePageRecuperee; + + BlocsLibres->TailleDisponible+= TaillePageRecuperee; + BlocsLibres->NombreDeBlocsLibres++; + BlocsLibres->NombreDeNouveauxBlocsLibres++; + if ( BlocsLibres->NombreDeBlocsLibres == 1 ) BlocsLibres->PlusGrandeTailleDispo = BlocsLibres->TailleDuBlocLibre[0]; + } + return( (char *) Pt ); +} + +/* S'il y a la place necessaire derriere, on ne fait rien */ +if ( TailleDispo >= (long) NombreDOctets ) { + return( (char *) Pt ); +} + +/* S'il n' a qu'une seule zone libre et qu'elle est derriere et que ca fait le supertableau alors on la donne */ +NombreDeBlocsLibres = BlocsLibres->NombreDeBlocsLibres; +AdresseDuBlocLibre = BlocsLibres->AdresseDuBlocLibre; +TailleDuBlocLibre = BlocsLibres->TailleDuBlocLibre; + +AdresseFin = (char *) Entete + Taille; + +for ( i = 0 ; i < NombreDeBlocsLibres ; i++ ) { + if ( AdresseDuBlocLibre[i] == AdresseFin ) { + T2 = TailleDuBlocLibre[i]; + NboctPossible = Taille + T2; + if ( NboctPossible >= Nboct ) { + TailleRestante = NboctPossible - Nboct; + if ( TailleRestante >= (long) TAILLE_MIN_BLOC ) { + /* On peut conserver un bloc libre juste apres */ + Entete->Taille = Nboct; + + /* Mise a jour des blocs libres */ + AdresseDuBlocLibre[i] = (char *) Entete + Nboct; + TailleDuBlocLibre [i] = TailleRestante; + BlocsLibres->TailleDisponible-= T2 - TailleRestante; + } + else { + /* On alloue tout le bloc */ + Entete->Taille = Taille + T2; + + j = NombreDeBlocsLibres - 1; + AdresseDuBlocLibre[i] = AdresseDuBlocLibre[j]; + TailleDuBlocLibre[i] = TailleDuBlocLibre[j]; + BlocsLibres->TailleDisponible-= T2; + BlocsLibres->NombreDeBlocsLibres--; + } + if ( NombreDeBlocsLibres == 1 ) BlocsLibres->PlusGrandeTailleDispo = TailleDuBlocLibre[0]; + return( (char *) Pt ); + } + } +} + +/* On est contraints de faire un realloc donc on prend encore plus de marge */ + +Supplement = NombreDAllocs * ( (long) NombreDOctets - TailleDispo ); + +if ( Supplement > (long) NombreDOctets ) Supplement = (long) NombreDOctets; + +NouvelleAdresse = MEM_Malloc( h, NombreDOctets + Supplement ); +if ( NouvelleAdresse == NULL ) return( NULL ); + +Entete = (ENTETE *) ((char *) NouvelleAdresse - sizeof( ENTETE )); +NouvelleTaille = Entete->Taille; +Entete->NombreDAllocs = NombreDAllocs; + +if ( NouvelleTaille < Taille ) Taille = NouvelleTaille; +NombreDOctets = Taille - sizeof( ENTETE ); + +memcpy( (char *) NouvelleAdresse, (char *) Pt, NombreDOctets * sizeof( char ) ); +/* +char * pt1; char * pt2; +pt2 = NouvelleAdresse; pt1 = Pt; +for ( i = 0 ; i < NombreDOctets ; i++ ) { + *pt2 = *pt1; pt1++; pt2++; +} +*/ +MEM_Free( Pt ); + +# ifdef DEBUG + if ( MEM_QuantiteLibre( BlocsLibres ) != BlocsLibres->TailleDisponible ) { + printf("Realloc: erreur taille disponible T %ld TailleDisponible %ld TailleInitialeDuSuperTableau %ld\n", + MEM_QuantiteLibre( BlocsLibres ),BlocsLibres->TailleDisponible,BlocsLibres->TailleInitialeDuSuperTableau); + } +# endif + +return( NouvelleAdresse ); + +} + + diff --git a/src/ext/Sirius_Solver/allocateur/mem_sys.h b/src/ext/Sirius_Solver/allocateur/mem_sys.h new file mode 100644 index 0000000000..d30161b9c9 --- /dev/null +++ b/src/ext/Sirius_Solver/allocateur/mem_sys.h @@ -0,0 +1,26 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# include +# include +# include +# include +# include +# include +# include +# include +# include + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_affichages_traces.c b/src/ext/Sirius_Solver/branchAndBound/bb_affichages_traces.c new file mode 100644 index 0000000000..ccfa8fbcd5 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_affichages_traces.c @@ -0,0 +1,296 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution d'un probleme relaxe + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" +#include "pne_fonctions.h" + +#define TAILLE_DU_MEGA_OCTET 1048576 /* 1024 * 1024 */ + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_AfficherLesTraces( BB * Bb, NOEUD * NoeudCourant ) +{ +double TempsEcoule; ldiv_t QuotientEtReste; PROBLEME_PNE * Pne; double X; NOEUD * Noeud; +int AverageG; int AverageI; int AverageK; char Tracer; +# if VERBOSE_BB +int cpt; int i; int * pt1 ; char * pt2; +# endif + +if ( NoeudCourant == Bb->NoeudRacine ) { + Bb->TempsDuDernierAffichage = 0; + Bb->NombreDeProblemesDepuisLeDernierAffichage = 0; + Bb->NombreDAffichages = 0; +} + +if ( Bb->NombreDeProblemesResolus > 0 ) { + + Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; + time( &(Pne->HeureDeCalendrierCourant) ); + TempsEcoule = difftime( Pne->HeureDeCalendrierCourant , Pne->HeureDeCalendrierDebut ); + if ( TempsEcoule <= 0.0 ) TempsEcoule = 0.0; + + QuotientEtReste = ldiv( (int)TempsEcoule , (int)CYCLE_DINFORMATIONS ); + + if ( Bb->TempsDexecutionMaximum > 0 ) { + if ( TempsEcoule >= Bb->TempsDexecutionMaximum ) { + Bb->ArreterLesCalculs = OUI; + if ( Bb->AffichageDesTraces == OUI ) printf("Stopping calculation because time limit reached.\n"); + } + } + + if ( Bb->AffichageDesTraces == OUI && + ( (QuotientEtReste.rem == 0 && QuotientEtReste.quot != Bb->TempsDuDernierAffichage) || + Bb->NombreDeProblemesDepuisLeDernierAffichage >= CYCLE_DINFORMATIONS_EN_NOMBRE_DE_PROBLEMES || + Bb->ForcerAffichage == OUI ) ) { + Bb->TempsDuDernierAffichage = QuotientEtReste.quot; + Bb->NombreDeProblemesDepuisLeDernierAffichage = 0; + + BB_RechercherLeMeilleurMinorant( Bb, RECHERCHER_LE_PLUS_PETIT ); + + if ( Bb->NombreDAffichages == 0 || Bb->NombreDAffichages >= CYCLE_DAFFICHAGE_LEGENDE ) { + Bb->NombreDAffichages = 0; + printf(" "); + printf("| Nodes |"); + printf(" Depth (max) |"); + printf(" Active nodes |"); + printf(" Sol |"); + printf(" Best Sol. |"); + printf(" Best bound |"); + printf(" Gap %% |"); + printf(" Seconds |"); + printf(" Cuts: average in use (over) |"); + printf("\n"); + } + Bb->NombreDAffichages++; + + printf(" "); + printf("| %7d |",Bb->NombreDeProblemesResolus); + printf(" %5d (%5d) |",NoeudCourant->ProfondeurDuNoeud,Bb->NombreDeVariablesEntieresDuProbleme); + printf(" %6d |",Bb->NbNoeudsOuverts); + printf(" %3d |",Bb->NombreDeSolutionsEntieresTrouvees); + + if ( Bb->NombreDeSolutionsEntieresTrouvees > 0 ) { + if ( Bb->ForcerAffichage == OUI ) { + if ( Bb->CoutDeLaMeilleureSolutionEntiere >= 0.0 ) { + printf("* %12.8e |",Bb->CoutDeLaMeilleureSolutionEntiere); + } + else { + printf("* %11.7e |",Bb->CoutDeLaMeilleureSolutionEntiere); + } + } + else { + if ( Bb->CoutDeLaMeilleureSolutionEntiere >= 0.0 ) { + printf(" %12.8e |",Bb->CoutDeLaMeilleureSolutionEntiere); + } + else { + printf(" %11.7e |",Bb->CoutDeLaMeilleureSolutionEntiere); + } + } + } + else { + printf(" -------------- |"); + } + + if ( Bb->NoeudDuMeilleurMinorant != 0 ) X = Bb->ValeurDuMeilleurMinorant; + else X = Bb->CoutDeLaMeilleureSolutionEntiere; + + if ( X >= 0.0 ) printf(" %12.8e |",X); + else printf(" %11.7e |",X); + + if ( Bb->NombreDeSolutionsEntieresTrouvees > 0 && fabs( Bb->ValeurDuMeilleurMinorant ) > 1.e-9 ) { + if ( Bb->NoeudDuMeilleurMinorant != 0 ) { + Bb->EcartBorneInf = (Bb->CoutDeLaMeilleureSolutionEntiere - Bb->ValeurDuMeilleurMinorant) / (0.01 * Bb->ValeurDuMeilleurMinorant ); + Bb->EcartBorneInf = fabs( Bb->EcartBorneInf ); + } + else Bb->EcartBorneInf = 0.0; + /*printf(" %6.2f |", Bb->EcartBorneInf );*/ + printf(" %6.4e |", Bb->EcartBorneInf ); + } + else { + printf(" ---------- |"); + } + printf(" %6d |" , (int) TempsEcoule); + if ( Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes <= 0 ) { + printf(" --------------------- |"); + printf("\n"); + } + else { + AverageG = (int) ceil(Bb->NombreTotalDeGDuPoolUtilisees/Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes); + AverageI = (int) ceil(Bb->NombreTotalDeIDuPoolUtilisees/Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes); + AverageK = (int) ceil(Bb->NombreTotalDeKDuPoolUtilisees/Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes); + Bb->AverageG = AverageG; + Bb->AverageI = AverageI; + Bb->AverageK = AverageK; + Tracer = NON; + if ( Bb->NoeudRacine->NombreDeG >= 0 ) { + printf(" G: %5d (%5d) !",AverageG,Bb->NoeudRacine->NombreDeG); + Tracer = OUI; + } + if ( Bb->NoeudRacine->NombreDeI >= 0 ) { + if ( Tracer == NON ) { + printf("\n"); + printf(" I: %5d (%5d) !",AverageI,Bb->NoeudRacine->NombreDeI); + } + else { + printf("\n"); + printf(" "); + printf("| |"); + printf(" |"); + printf(" |"); + printf(" |"); + printf(" |"); + printf(" |"); + printf(" |"); + printf(" |"); + printf(" I: %5d (%5d) !",AverageI,Bb->NoeudRacine->NombreDeI); + } + Tracer = OUI; + } + if ( Bb->NoeudRacine->NombreDeK >= 0 ) { + if ( Tracer == NON ) { + printf("\n"); + printf(" K: %5d (%5d) !",AverageK,Bb->NoeudRacine->NombreDeK); + } + else { + printf("\n"); + printf(" "); + printf("| |"); + printf(" |"); + printf(" |"); + printf(" |"); + printf(" |"); + printf(" |"); + printf(" |"); + printf(" |"); + printf(" K: %5d (%5d) !",AverageK,Bb->NoeudRacine->NombreDeK); + } + Tracer = OUI; + } + } + printf("\n"); + + if ( Bb->NombreDeNoeudsElagues != 0 && Bb->NombreDeSimplexes != 0 ) { + Bb->AveragePruningDepth = (int) ceil( Bb->SommeDesProfondeursDElaguage / Bb->NombreDeNoeudsElagues ); + printf("Pruned nodes: %d / Average pruning depth: %d / Average simplex iterations: %d\n", + Bb->NombreDeNoeudsElagues, + Bb->AveragePruningDepth, + (int) ceil( (double) Bb->SommeDuNombreDIterations / (double) Bb->NombreDeSimplexes ) ); + } + + fflush(stdout); + Bb->ForcerAffichage = NON; + } + if ( Bb->NombreMaxDeSolutionsEntieres >= 0 ) { + if ( Bb->NombreDeSolutionsEntieresTrouvees >= Bb->NombreMaxDeSolutionsEntieres ) { + Bb->ArreterLesCalculs = OUI; + if ( Bb->AffichageDesTraces == OUI ) { + printf("Stopping calculation. Integer solutions found has reached max. allowed (%d).\n",Bb->NombreMaxDeSolutionsEntieres); + } + } + } + if ( Bb->NombreDeSolutionsEntieresTrouvees > 0 && fabs( Bb->ValeurDuMeilleurMinorant ) > 1.e-9 ) { + X = (Bb->CoutDeLaMeilleureSolutionEntiere - Bb->ValeurDuMeilleurMinorant) / (0.01 * fabs( Bb->ValeurDuMeilleurMinorant )); + X = fabs( X ); + if ( X <= Bb->ToleranceDOptimalite ) { + Bb->ArreterLesCalculs = OUI; + Bb->EcartBorneInf = X; + } + /* Si on n'a pas choisi d'arreter on refait le test sans la partie fixe */ + if ( Bb->ArreterLesCalculs != OUI ) { + /* On ne fait ce calcul que si la partie fixe est du meme ordre que ValeurDuMeilleurMinorant */ + if ( fabs( Pne->Z0 ) < 10. * fabs( Bb->ValeurDuMeilleurMinorant ) ) { + X = (Bb->CoutDeLaMeilleureSolutionEntiere - Bb->ValeurDuMeilleurMinorant) / (0.01 * fabs( Bb->ValeurDuMeilleurMinorant - Pne->Z0 )); + X = fabs( X ); + if ( X <= Bb->ToleranceDOptimalite ) { + Bb->ArreterLesCalculs = OUI; + Bb->EcartBorneInf = X; + } + } + } + } + else { + if ( Bb->NombreDeSolutionsEntieresTrouvees > 0 ) { + BB_RechercherLeMeilleurMinorant( Bb, RECHERCHER_LE_PLUS_PETIT ); + if ( fabs( Bb->ValeurDuMeilleurMinorant ) > 1.e-9 ) { + Bb->EcartBorneInf = (Bb->CoutDeLaMeilleureSolutionEntiere - Bb->ValeurDuMeilleurMinorant) / (0.01 * fabs( Bb->ValeurDuMeilleurMinorant )); + Bb->EcartBorneInf = fabs( Bb->EcartBorneInf ); + if ( Bb->EcartBorneInf <= Bb->ToleranceDOptimalite ) { + Bb->ArreterLesCalculs = OUI; + } + /* Si on n'a pas choisi d'arreter on refait le test sans la partie fixe */ + if ( Bb->ArreterLesCalculs != OUI ) { + /* On ne fait ce calcul que si la partie fixe est du meme ordre que ValeurDuMeilleurMinorant */ + if ( fabs( Pne->Z0 ) < 10. * fabs( Bb->ValeurDuMeilleurMinorant ) ) { + X = (Bb->CoutDeLaMeilleureSolutionEntiere - Bb->ValeurDuMeilleurMinorant) / (0.01 * fabs( Bb->ValeurDuMeilleurMinorant - Pne->Z0 )); + X = fabs( X ); + if ( X <= Bb->ToleranceDOptimalite ) { + Bb->ArreterLesCalculs = OUI; + Bb->EcartBorneInf = X; + } + } + } + } + } + } + +} + +#if VERBOSE_BB + +printf("\n Resolution du probleme relaxe \n "); +printf(" Etat des variables entieres du probleme: \n "); + +printf(" variable instanciee / valeurs : \n"); fflush(stdout); +for( cpt = 0 , i = 0 , pt1 = NoeudCourant->IndicesDesVariablesEntieresInstanciees; + i < NoeudCourant->NombreDeVariablesEntieresInstanciees ; i++ , pt1++ , cpt++ ) { + printf(" %4d ",*pt1); + if ( cpt == 30 ) { printf("\n"); cpt = 0;} +} +printf("\n"); +for( cpt = 0 , i = 0 , pt2 = NoeudCourant->ValeursDesVariablesEntieresInstanciees; + i < NoeudCourant->NombreDeVariablesEntieresInstanciees ; i++ , pt2++ , cpt++ ) { + printf(" %4c ",*pt2); + if ( cpt == 30 ) { printf("\n"); cpt = 0;} +} +printf("\n "); +fflush(stdout); + +#endif + +Noeud = NoeudCourant->NoeudAntecedent; +/* +if ( Noeud != 0 ) { + printf("Nombre de variables fractionnaires du noeud pere: %d\n",Noeud->NbValeursFractionnairesApresResolution); +} +*/ + +return; +} + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_alloc_desalloc_probleme.c b/src/ext/Sirius_Solver/branchAndBound/bb_alloc_desalloc_probleme.c new file mode 100644 index 0000000000..d2dc3002f5 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_alloc_desalloc_probleme.c @@ -0,0 +1,134 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Desallocations finales + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_BranchAndBoundAllouerProbleme( BB * Bb ) +{ + +Bb->ValeursCalculeesDesVariablesPourLeProblemeRelaxeCourant = (double *) malloc( Bb->NombreDeVariablesDuProbleme * sizeof( double ) ); +Bb->ValeursCalculeesDesVariablesEntieresPourLeProblemeRelaxeCourant = (double *) malloc( Bb->NombreDeVariablesEntieresDuProbleme * sizeof( double ) ); + +Bb->NumerosDesVariablesEntieresDuProbleme = (int *) malloc( Bb->NombreDeVariablesEntieresDuProbleme * sizeof( int ) ); +Bb->ValeursOptimalesDesVariables = (double *) malloc( Bb->NombreDeVariablesDuProbleme * sizeof( double ) ); +Bb->ValeursOptimalesDesVariablesEntieres = (double *) malloc( Bb->NombreDeVariablesEntieresDuProbleme * sizeof( double ) ); + +/* Il faut revoir ces dimensionnements. On dimensionne plus large le complement de base pour pouvoir mettre des coupes mais ce n'est pas la + bonne methode, il vaut mieux faire des realloc */ +Bb->PositionDeLaVariableAEntierInf = (int *) malloc( ( Bb->NombreDeVariablesDuProbleme + Bb->NombreDeContraintesDuProbleme ) * sizeof( int ) ); +Bb->ComplementDeLaBaseAEntierInf = (int *) malloc( ( Bb->NombreDeContraintesDuProbleme + Bb->NombreDeVariablesDuProbleme ) * sizeof( int ) ); +Bb->PositionDeLaVariableAEntierSup = (int *) malloc( ( Bb->NombreDeVariablesDuProbleme + Bb->NombreDeContraintesDuProbleme ) * sizeof( int ) ); +Bb->ComplementDeLaBaseAEntierSup = (int *) malloc( ( Bb->NombreDeContraintesDuProbleme + Bb->NombreDeVariablesDuProbleme ) * sizeof( int ) ); + +if ( Bb->ValeursCalculeesDesVariablesPourLeProblemeRelaxeCourant == NULL || + Bb->ValeursCalculeesDesVariablesEntieresPourLeProblemeRelaxeCourant == NULL || + + Bb->NumerosDesVariablesEntieresDuProbleme == NULL || + Bb->ValeursOptimalesDesVariables == NULL || + Bb->ValeursOptimalesDesVariablesEntieres == NULL || + + Bb->PositionDeLaVariableAEntierInf == NULL || + Bb->ComplementDeLaBaseAEntierInf == NULL || + Bb->PositionDeLaVariableAEntierSup == NULL || + Bb->ComplementDeLaBaseAEntierSup == NULL +) { + + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_BranchAndBoundAllouerProbleme \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} + +Bb->NombreDeNoeudsEvaluesSansCalculdeCoupes = 0; + +/* Les zones ci-dessous sont allouees au moment de la resolution du probleme relaxe */ +Bb->CoupeSaturee = NULL; +Bb->CoupeSatureeAEntierInf = NULL; +Bb->CoupeSatureeAEntierSup = NULL; + +/* Initialise a une grande valeur */ +Bb->AverageG = NON_INITIALISE; +Bb->AverageI = NON_INITIALISE; +Bb->AverageK = NON_INITIALISE; + +return; + +} + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_BranchAndBoundDesallouerProbleme( BB * Bb ) +{ +PROBLEME_PNE * Pne; + +if ( Bb == NULL ) return; + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; + Pne->ProblemeBbDuSolveur = NULL; + MEM_Quit( Bb->Tas ); + return; +# endif + +/* On libere toute l'arborescence */ +Bb->NoeudEnExamen = NULL; + +if ( Bb->NoeudRacine != NULL ) { + BB_SupprimerTousLesDescendantsDUnNoeud( Bb, Bb->NoeudRacine ); + /* Le sp ci-dessus ne supprime pas le noeud de depart */ + BB_DesallouerUnNoeud( Bb, Bb->NoeudRacine ); +} + +free( Bb->ValeursCalculeesDesVariablesPourLeProblemeRelaxeCourant ); +free( Bb->ValeursCalculeesDesVariablesEntieresPourLeProblemeRelaxeCourant ); +free( Bb->NumerosDesVariablesEntieresDuProbleme ); +free( Bb->ValeursOptimalesDesVariables ); +free( Bb->ValeursOptimalesDesVariablesEntieres ); +free( Bb->PositionDeLaVariableAEntierInf ); +free( Bb->ComplementDeLaBaseAEntierInf ); +free( Bb->PositionDeLaVariableAEntierSup ); +free( Bb->ComplementDeLaBaseAEntierSup ); + +free( Bb->CoupeSaturee ); +free( Bb->CoupeSatureeAEntierInf ); +free( Bb->CoupeSatureeAEntierSup ); + +Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; +Pne->ProblemeBbDuSolveur = NULL; + +free( Bb ); + +return; + +} + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_balayage_en_largeur.c b/src/ext/Sirius_Solver/branchAndBound/bb_balayage_en_largeur.c new file mode 100644 index 0000000000..3308448541 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_balayage_en_largeur.c @@ -0,0 +1,248 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/************************************************************************* + + FONCTION: Exploration de l'arbre en largeur a partir du noeud. Le noeud + de depart est lui aussi examine, mais il est le seul de son etage a + etre examine. Attention, le noeud de depart doit deja exister. + + AUTEUR: R. GONZALEZ + +**************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_BalayageEnLargeur( BB * Bb , NOEUD * NoeudDeDepart , int ProfondeurDuNoeudDeDepart ) +{ +int i ; int YaUneSolution ; +int SolutionEntiereTrouvee ; int ProfondeurDuNoeud ; +NOEUD ** NoeudsAExplorer ; NOEUD ** NoeudsAExplorerAuProchainEtage ; +NOEUD * NoeudCourant ; +int NombreDeNoeudsAExplorer ; int NombreDeNoeudsAExplorerAuProchainEtage; +int ProfondeurRelative ; +int NombreDeProblemesEvalues ; int PremierIndice ; +int DernierIndice ; + + + + +#if VERBOSE_BB + printf("************************************************\n"); + printf(" Balayage En Largeur \n"); + printf(" ------------------- \n"); +#endif + + /* Initialisation */ + +ProfondeurDuNoeud = ProfondeurDuNoeudDeDepart; +ProfondeurRelative = 0; +NoeudsAExplorer = (NOEUD **) malloc( 1 * sizeof( void * ) ); +if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_BalayageEnLargeur \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +NombreDeNoeudsAExplorer = 1; +NoeudsAExplorer[0] = NoeudDeDepart; + +Bb->NbNoeuds1_PNE_BalayageEnLargeur = NombreDeNoeudsAExplorer; /* Pour le nettoyage eventuel */ +Bb->Liste1_PNE_BalayageEnLargeur = NoeudsAExplorer; /* Pour le nettoyage eventuel */ + +while ( 1 ) { + + ProfondeurRelative++; + + Bb->TailleTableau = NombreDeNoeudsAExplorer * 2 * sizeof( void * ); + + NoeudsAExplorerAuProchainEtage = (NOEUD **) malloc( NombreDeNoeudsAExplorer * 2 * sizeof( void * ) ); + if ( NoeudsAExplorerAuProchainEtage == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_BalayageEnLargeur \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } + Bb->NbNoeuds2_PNE_BalayageEnLargeur = 0; /* Pour le nettoyage eventuel */ + Bb->Liste2_PNE_BalayageEnLargeur = NoeudsAExplorerAuProchainEtage; /* Pour le nettoyage eventuel */ + + NombreDeNoeudsAExplorerAuProchainEtage = 0; + NombreDeProblemesEvalues = 0; + PremierIndice = 0; + + for ( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + + Bb->TypeDExplorationEnCours = LARGEUR_TOUT_SEUL; + /* Lorsqu'on est dans un balayage en largeur on ne calcule pas de coupes */ + Bb->CalculerDesCoupes = NON_PNE; + + NoeudCourant = NoeudsAExplorer[i]; + if ( NoeudCourant != 0 ) { + if ( NoeudCourant->StatutDuNoeud == A_EVALUER && + NoeudCourant->NoeudTerminal != OUI && + NoeudCourant->StatutDuNoeud != A_REJETER ) { + + #if VERBOSE_BB + printf("\n************************************************\n"); + printf("\n Balayage en largeur: Noeud %x , Profondeur en cours %d , numero du noeud dans la profondeur %d , nb de noeuds dans la largeur %d\n ", + NoeudCourant,ProfondeurDuNoeud,i,NombreDeNoeudsAExplorer); + #endif + + Bb->NoeudEnExamen = NoeudCourant; + /* Exploration du noeud */ + NombreDeProblemesEvalues++; + YaUneSolution = BB_ResoudreLeProblemeRelaxe( Bb , NoeudCourant , &SolutionEntiereTrouvee ); + + BB_NettoyerLArbre( Bb , &YaUneSolution , NoeudCourant ); /* Fait aussi la mise a jour du statut */ + + BB_CreerLesNoeudsFils( Bb , NoeudCourant ); + + } + /* Renseigner la table des noeuds du prochain etage */ + Bb->NbNoeuds2_PNE_BalayageEnLargeur++; /* Pour le nettoyage eventuel */ + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = NoeudCourant->NoeudSuivantGauche; + + Bb->NbNoeuds2_PNE_BalayageEnLargeur++; /* Pour le nettoyage eventuel */ + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = NoeudCourant->NoeudSuivantDroit; + + } + + if ( NombreDeProblemesEvalues == CYCLE_POUR_RECHERCHE_EN_PROFONDEUR ) { + DernierIndice = i + 1; + BB_FaireUneRechercheEnProfondeurDansUneRechercheEnLargeur( Bb ); + PremierIndice = DernierIndice; + NombreDeProblemesEvalues = 0; + } + + /* Fin for */ + } + /* C'est termine ? */ + if( NombreDeNoeudsAExplorerAuProchainEtage == 0 ) { + #if VERBOSE_BB + printf(" Plus de noeud a explorer \n"); + #endif + if( NombreDeNoeudsAExplorerAuProchainEtage == 0 ) break; /* Exploration de l'arbre terminee */ + } + + /* Exploration en profondeur du noeud de plus petit minorant a partir d'une certaine profondeur relative */ + + if ( ProfondeurRelative >= 0 /*3*/ ) { + #if VERBOSE_BB + printf(" Exploration en profondeur dans une exploration en largeur \n"); + #endif + BB_FaireUneRechercheEnProfondeurDansUneRechercheEnLargeur( Bb ); + } + + /* Temps maximum depasse ?*/ + if ( Bb->ArreterLesCalculs == OUI ) break; + + /* Nettoyage des coupes */ + /* + BB_NettoyerLesCoupes( Bb , NombreDeNoeudsAExplorer , NoeudsAExplorer ); + */ + /* Preparations pour l'etage suivant */ + free( NoeudsAExplorer ); + ProfondeurDuNoeud++; + NoeudsAExplorer = (NOEUD **) malloc( NombreDeNoeudsAExplorerAuProchainEtage * sizeof( void * ) ); + if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_BalayageEnLargeur \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorer = NombreDeNoeudsAExplorerAuProchainEtage; + + Bb->NbNoeuds1_PNE_BalayageEnLargeur = NombreDeNoeudsAExplorer; /* Pour le nettoyage eventuel */ + Bb->Liste1_PNE_BalayageEnLargeur = NoeudsAExplorer; /* Pour le nettoyage eventuel */ + for ( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudsAExplorer[i] = NoeudsAExplorerAuProchainEtage[i]; + } + free( NoeudsAExplorerAuProchainEtage ); +/* Fin while */ +} + +free( NoeudsAExplorer ); +free( NoeudsAExplorerAuProchainEtage ); + +Bb->NbNoeuds1_PNE_BalayageEnLargeur = 0; +Bb->NbNoeuds2_PNE_BalayageEnLargeur = 0; + +return; +} + +/*----------------------------------------------------------------------------------*/ +/* Fait une recherche en profondeur jusqu'a trouver une solution entiere */ + +void BB_FaireUneRechercheEnProfondeurDansUneRechercheEnLargeur( BB * Bb ) +{ +char SolutionEntiereTrouveeGauche; + +/* +printf("Recherche en profondeur dans un balayage en largeur\n"); fflush(stdout); +*/ + +Bb->TypeDExplorationEnCours = PROFONDEUR_DANS_LARGEUR; + +if ( Bb->ArreterLesCalculs == NON ) BB_BestFirst( Bb ); + +SolutionEntiereTrouveeGauche = NON; + +if ( SolutionEntiereTrouveeGauche == NON && Bb->ArreterLesCalculs == NON ) { + + /* Si l'ecart borne inf est trop grand on prend RECHERCHER_LE_PLUS_PETIT_GAP_PROPORTIONNEL + sinon on prend RECHERCHER_LE_PLUS_PETIT */ + /* + if ( Bb->EcartBorneInf > 50. ) { + BB_RechercherLeMeilleurMinorant( Bb, RECHERCHER_LE_PLUS_PETIT ); + } + else { + BB_RechercherLeMeilleurMinorant( Bb, RECHERCHER_LE_PLUS_PETIT_GAP_PROPORTIONNEL ); + } + */ + + BB_RechercherLeMeilleurMinorant( Bb, RECHERCHER_LE_PLUS_PETIT_GAP_PROPORTIONNEL ); + + if ( Bb->NoeudDuMeilleurMinorant != 0 ) { + Bb->SolutionAmelioranteTrouvee = NON; + SolutionEntiereTrouveeGauche = BB_BalayageEnProfondeur( Bb, + Bb->NoeudDuMeilleurMinorant, + Bb->NoeudDuMeilleurMinorant->ProfondeurDuNoeud ); + + if ( Bb->ArreterLesCalculs == NON ) BB_BestFirst( Bb ); + + } +} + +return; +} + + + + + + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_balayage_en_profondeur.c b/src/ext/Sirius_Solver/branchAndBound/bb_balayage_en_profondeur.c new file mode 100644 index 0000000000..fa967c974d --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_balayage_en_profondeur.c @@ -0,0 +1,693 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Exploration d'une branche en profondeur a partir d'un + noeud (y compris le noeud lui-meme). + + Utilite: trouver une solution admissible au plus tot. + + Attention: le noeud de depart doit deja exister. + + Apres chaque noeud explore on cree les 2 noeuds fils. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" +#include "pne_fonctions.h" + +# define CYCLE_DE_PROFONDEUR_POUR_LE_CALCUL_DES_GOMORY 1 /*1*/ +# define MARGE_SUR_LES_MINORANTS 1.e-4 +# define NEUTRALISATION_CALCUL_COUPES 0 /*0*/ + +# define TAILLE_MOYENNE_MOBILE 10 +# define MARGE_POUR_SOMME_MOYENNE_MOBILE 0.25 /*0.0*/ +# define CYCLE_TEST_MOYENNE_MOBILE 1 + +/*---------------------------------------------------------------------------------------------------------*/ + +int BB_BalayageEnProfondeur( BB * Bb , NOEUD * NoeudDeDepart , int ProfondeurDuNoeudDeDepart ) +{ +NOEUD * NoeudsAExplorer[2]; NOEUD * NoeudCourant ; NOEUD * NoeudAntecedent ; +NOEUD * NoeudPereSuivant ; ldiv_t QuotientEtReste; int ProfondeurLimite; char ProfondeurRapide; +int ProfondeurMoyenneDesSolutionsEntieres; int ProfondeurMoyenneDesSolutionsAmeliorantes; +double MinorantPredit0; char MinorantPredit0Initialise; +double MinorantPredit1; char MinorantPredit1Initialise; +int IndiceChoisi ; char UnIndiceAEteChoisi ; char Les2ChoixSontPossibles; +char EvaluerLAutreNoeud; double MinorantPreditDeLAutreNoeud; int NbProblemesResolus ; +int NombreDeNoeudsAExplorer; /* Utile uniquement pour l'appel a BB_NettoyerLArbre */ +int NombreDeNoeudsAExplorerAuProchainEtage; /* Utile uniquement pour l'appel a BB_NettoyerLArbre */ +int YaUneSolution; int ProfondeurDuNoeud; int SolutionEntiereTrouvee; +int NombreMaxDeProblemesProfondeurDansLargeur; int i; PROBLEME_PNE * Pne; +double VecteurPourMoyenneMobile[TAILLE_MOYENNE_MOBILE]; char TesterLaDecroissance; int NbTestsMoyenneMobile; +int IndexMoyenneMobile; double SommePourMoyenneMobilePrecedente; double SommePourMoyenneMobile; +char SommePourMoyenneMobilePrecedenteEstInitialisee; + +Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; + +ProfondeurRapide = OUI; + +MinorantPredit0 = PLUS_LINFINI; /* Pour eviter les warning de compilation */ +MinorantPredit1 = PLUS_LINFINI; /* Pour eviter les warning de compilation */ + +SolutionEntiereTrouvee = NON; +NoeudAntecedent = 0; +NoeudsAExplorer[0] = NoeudDeDepart; +NoeudsAExplorer[1] = 0; +ProfondeurDuNoeud = ProfondeurDuNoeudDeDepart; +NombreDeNoeudsAExplorer = 2; +NombreDeNoeudsAExplorerAuProchainEtage = 0; + +IndexMoyenneMobile = 0; +SommePourMoyenneMobilePrecedente = 0; +SommePourMoyenneMobile = 0; +SommePourMoyenneMobilePrecedenteEstInitialisee = NON; +TesterLaDecroissance = NON; + +Bb->NbNoeuds1_PNE_BalayageEnProfondeur = NombreDeNoeudsAExplorer; /* Pour le nettoyage eventuel */ +Bb->Liste1_PNE_BalayageEnProfondeur = NoeudsAExplorer; /* Pour le nettoyage eventuel */ + +/* Calcul de la profondeur limite dans le cas d'une recherche en profondeur pendant une recherche en largeur */ +ProfondeurLimite = (int) ( COEFFICIENT_POUR_LE_CALCUL_DE_LA_PROFONDEUR_LIMITE * + ( Bb->NombreDeVariablesEntieresDuProbleme - NoeudDeDepart->NombreDeVariablesEntieresInstanciees ) ); +if ( ProfondeurLimite < PROFONDEUR_MIN_PENDANT_LA_RECHERCHE_EN_LARGEUR ) ProfondeurLimite = PROFONDEUR_MIN_PENDANT_LA_RECHERCHE_EN_LARGEUR; +if ( ProfondeurLimite > PROFONDEUR_MAX_PENDANT_LA_RECHERCHE_EN_LARGEUR ) ProfondeurLimite = PROFONDEUR_MAX_PENDANT_LA_RECHERCHE_EN_LARGEUR; + +ProfondeurLimite += ProfondeurDuNoeudDeDepart; + +/* On s'autorise a descendre au moins jusqu'a la profondeur ou on a trouve la meilleure solution entiere */ +if ( Bb->TypeDExplorationEnCours == PROFONDEUR_DANS_LARGEUR ) { + if ( Bb->ProfondeurMaxiSiPlongeePendantUneRechercheEnLargeur > ProfondeurLimite ) { + ProfondeurLimite = Bb->ProfondeurMaxiSiPlongeePendantUneRechercheEnLargeur; + } +} + +ProfondeurMoyenneDesSolutionsEntieres = Bb->ProfondeurMoyenneDesSolutionsEntieres; + +ProfondeurMoyenneDesSolutionsAmeliorantes = Bb->NombreDeVariablesEntieresDuProbleme; +if ( Bb->NombreDeSolutionsAmeliorantes != 0 ) { + ProfondeurMoyenneDesSolutionsAmeliorantes = (int) ceil( (float) Bb->SommeDesProfondeursDesSolutionsAmeliorantes / + (float) Bb->NombreDeSolutionsAmeliorantes ); + ProfondeurMoyenneDesSolutionsAmeliorantes = (int) ( 0.8 * ProfondeurMoyenneDesSolutionsAmeliorantes ); + if ( ProfondeurLimite < ProfondeurMoyenneDesSolutionsAmeliorantes ) ProfondeurLimite = ProfondeurMoyenneDesSolutionsAmeliorantes; +} + +/* Etant donne que la recherche de la premiere solution entiere se fait en profondeur d'abord, il n'est pas rare qu'on la trouve tres + bas dans l'arbre. Il faut donc eviter un coefficient trop grand sinon on risque de passer trop de temps dans la recherche + en profondeur dans les etapes suivantes */ + +NombreMaxDeProblemesProfondeurDansLargeur = (int) ceil( 1.0 /*1.5*/ * Bb->NbProbPourLaPremiereSolutionEntiere ); + +/***********************************************************************************************************************/ +/***********************************************************************************************************************/ +/***********************************************************************************************************************/ +/***********************************************************************************************************************/ +/* Le 30/01/2015: Test d'une strategie supplementaire: on tient compte du nombre d'etages qu'on s'autorise a parcourir */ +if ( Bb->TypeDExplorationEnCours == PROFONDEUR_DANS_LARGEUR ) { + if ( NombreMaxDeProblemesProfondeurDansLargeur < 2 * ( ProfondeurLimite - ProfondeurDuNoeudDeDepart ) ) { + NombreMaxDeProblemesProfondeurDansLargeur = 2 * ( ProfondeurLimite - ProfondeurDuNoeudDeDepart ); + } +} +/***********************************************************************************************************************/ +/***********************************************************************************************************************/ +/***********************************************************************************************************************/ +/***********************************************************************************************************************/ + +if ( NombreMaxDeProblemesProfondeurDansLargeur < NOMBRE_MIN_DE_PROBLEMES_PROFONDEUR_DANS_LARGEUR ) { + NombreMaxDeProblemesProfondeurDansLargeur = NOMBRE_MIN_DE_PROBLEMES_PROFONDEUR_DANS_LARGEUR; +} + +/* On arrete la recherche en profondeur sur un critere de variation de la moyenne mobile de la fractionnalitea + a partir du moment ou on a depasse NombreMaxDeProblemesProfondeurDansLargeur */ + +if ( NombreMaxDeProblemesProfondeurDansLargeur < TAILLE_MOYENNE_MOBILE * 3/*2*/ ) { + NombreMaxDeProblemesProfondeurDansLargeur = TAILLE_MOYENNE_MOBILE * 3/*2*/; +} + +/* +if ( Bb->TypeDExplorationEnCours == PROFONDEUR_DANS_LARGEUR ) { + printf("********************** Profondeur dans largeur NombreMaxDeProblemesProfondeurDansLargeur %d ProfondeurLimite %d\n", + NombreMaxDeProblemesProfondeurDansLargeur,ProfondeurLimite); +} +*/ + +NbTestsMoyenneMobile = NombreMaxDeProblemesProfondeurDansLargeur; + +NbProblemesResolus = 0; +while ( 1 ) { + + if ( Bb->ArreterLesCalculs == OUI ) { + Bb->NbNoeuds1_PNE_BalayageEnProfondeur = 0; + Bb->NoeudEnExamen = 0; + return( ARRET_CAR_TEMPS_MAXIMUM_ATTEINT ); + } + + /* Test exploration rapide en profondeur */ + if ( Bb->TypeDExplorationEnCours == PROFONDEUR_DANS_LARGEUR && NbProblemesResolus >= 10 && ProfondeurRapide == OUI && 0 ) { /* Car pas encore au point */ + BB_ExplorationRapideEnProfondeur( Bb ); + NbProblemesResolus = 0; + ProfondeurRapide = OUI/*NON*/; + if ( Bb->NombreDeSolutionsEntieresTrouvees != 0 ) { + /* On a trouve une solution entiere */ + Bb->NbNoeuds1_PNE_BalayageEnProfondeur = 0; + Bb->NoeudEnExamen = 0; + return( OUI ); + } + } + /* Fin test exploration rapide en profondeur */ + + if ( Bb->TypeDExplorationEnCours == PROFONDEUR_DANS_LARGEUR ) { + if ( ProfondeurDuNoeud > ProfondeurLimite || NbProblemesResolus > NombreMaxDeProblemesProfondeurDansLargeur ) { + TesterLaDecroissance = OUI; + if ( IndexMoyenneMobile == TAILLE_MOYENNE_MOBILE ) { + /* Calcul de la moyenne mobile */ + SommePourMoyenneMobile = 0;; + for ( i = 0 ; i < TAILLE_MOYENNE_MOBILE ; i++ ) SommePourMoyenneMobile += VecteurPourMoyenneMobile[i]; + if ( SommePourMoyenneMobilePrecedenteEstInitialisee == NON ) { + SommePourMoyenneMobilePrecedente = SommePourMoyenneMobile; + SommePourMoyenneMobilePrecedenteEstInitialisee = OUI; + TesterLaDecroissance = NON; /* Car la premiere fois on calcule SommePourMoyenneMobilePrecedente */ + } + } + else TesterLaDecroissance = NON; /* Pas assez de valeurs pour calculer la moyenne mobile */ + if ( TesterLaDecroissance == OUI && NbProblemesResolus % CYCLE_TEST_MOYENNE_MOBILE == 0 ) { + if ( NbTestsMoyenneMobile >= 0 && SommePourMoyenneMobile <= SommePourMoyenneMobilePrecedente + (MARGE_POUR_SOMME_MOYENNE_MOBILE*SommePourMoyenneMobilePrecedente) ) { + /* Si la moyenne mobile du nombre de variables fractionnaires decroit ou reste stationnaire on n'arrete pas */ + /* + printf("La moyenne mobile decroit alors on continue: SommePourMoyenneMobilePrecedente %e SommePourMoyenneMobile %e\n", + SommePourMoyenneMobilePrecedente,SommePourMoyenneMobile); + */ + SommePourMoyenneMobilePrecedente = SommePourMoyenneMobile; + NbTestsMoyenneMobile--; + } + else { + /* Traces */ + /* + printf("La moyenne mobile ne decroit pas on arrete: SommePourMoyenneMobilePrecedente %d SommePourMoyenneMobile %d\n", + SommePourMoyenneMobilePrecedente,SommePourMoyenneMobile); + */ + /* + printf("NbProblemesResolus %d ProfondeurDuNoeud %d\n",NbProblemesResolus,ProfondeurDuNoeud); + if ( ProfondeurDuNoeud > ProfondeurLimite ) printf("->>>>>>>>>> Fin par atteinte de ProfondeurLimite %d\n",ProfondeurLimite); + else if ( NbProblemesResolus > NombreMaxDeProblemesProfondeurDansLargeur ) { + printf("->>>>>>>>>> Fin par atteinte de NombreMaxDeProblemesProfondeurDansLargeur %d Profondeur %d\n", + NombreMaxDeProblemesProfondeurDansLargeur,ProfondeurDuNoeud); + } + */ + /* Fin traces */ + break; + } + } + } + } + + /* Dans un balayage en profondeur, on ne calcule des Gomory qu'apres avoir descendu un certain nombre d'etages */ + Bb->CalculerDesCoupes = NON_PNE; + if ( Bb->TypeDExplorationEnCours == PROFONDEUR_DANS_LARGEUR ) { + Bb->CalculerDesCoupes = OUI_PNE; + Bb->CalculerDesCoupesDeGomory = OUI_PNE; + /*printf(" Demande de calcul de coupes dans PROFONDEUR_DANS_LARGEUR \n");*/ + } + else { + if ( NbProblemesResolus >= NEUTRALISATION_CALCUL_COUPES ) { + QuotientEtReste = ldiv( (int)(ProfondeurDuNoeud - ProfondeurDuNoeudDeDepart) , (int)CYCLE_DE_PROFONDEUR_POUR_LE_CALCUL_DES_GOMORY ); + if ( QuotientEtReste.rem == 0 ) { + Bb->CalculerDesCoupes = OUI_PNE; + Bb->CalculerDesCoupesDeGomory = OUI_PNE; + } + } + } + + /* Evaluation du noeud de plus petit minorant attendu */ + NoeudCourant = NoeudsAExplorer[0]; + MinorantPredit0Initialise = NON; + if ( NoeudCourant != 0 ) { + if( NoeudCourant->NoeudTerminal != OUI && NoeudCourant->StatutDuNoeud != A_REJETER && NoeudCourant->StatutDuNoeud == A_EVALUER ) { + MinorantPredit0 = NoeudCourant->MinorantPredit; + MinorantPredit0Initialise = OUI; + + } + } + NoeudCourant = NoeudsAExplorer[1]; + MinorantPredit1Initialise = NON; + if ( NoeudCourant != 0 ) { + if( NoeudCourant->NoeudTerminal != OUI && NoeudCourant->StatutDuNoeud != A_REJETER && NoeudCourant->StatutDuNoeud == A_EVALUER ) { + MinorantPredit1 = NoeudCourant->MinorantPredit; + MinorantPredit1Initialise = OUI; + } + } + + UnIndiceAEteChoisi = NON; + Les2ChoixSontPossibles = NON; + if ( MinorantPredit0Initialise == OUI ) { + IndiceChoisi = 0; + UnIndiceAEteChoisi = OUI; + if ( MinorantPredit1Initialise == OUI ) { + Les2ChoixSontPossibles = OUI; + if ( MinorantPredit1 < MinorantPredit0 ) { + IndiceChoisi = 1; + UnIndiceAEteChoisi = OUI; + } + } + } + else { + if ( MinorantPredit1Initialise == OUI ) { + IndiceChoisi = 1; + UnIndiceAEteChoisi = OUI; + } + } + + /* Evaluation du noeud choisi */ + if ( UnIndiceAEteChoisi == OUI ) { + + NoeudCourant = NoeudsAExplorer[IndiceChoisi]; + if( NoeudCourant->StatutDuNoeud == EVALUE && NoeudCourant->LaSolutionRelaxeeEstEntiere == OUI ) { + Bb->NbNoeuds1_PNE_BalayageEnProfondeur = 0; + Bb->NoeudEnExamen = 0; + return( OUI ); + } + #if VERBOSE_BB + if ( Bb->TypeDExplorationEnCours == PROFONDEUR_TOUT_SEUL ) { + printf(" ************************************************ \n"); + printf(" Noeud (%d) %x / Recherche en profondeur seule, profondeur du noeud %d\n",IndiceChoisi, + NoeudCourant,ProfondeurDuNoeud); + } + else { + printf(" ************************************************ \n"); + printf(" Noeud (%d) %x / Recherche en profondeur dans un balayage en largeur, profondeur de depart %d , profondeur du noeud %d profondeur limite %d\n", + IndiceChoisi, NoeudCourant,ProfondeurDuNoeudDeDepart,ProfondeurDuNoeud, + ProfondeurDuNoeudDeDepart+ProfondeurLimite); + } + fflush(stdout); + #endif + + if ( NoeudCourant == Bb->NoeudRacine ) { + /* Calcul de coupes au noeud racine */ + Bb->CalculerDesCoupes = OUI_PNE; + Bb->CalculerDesCoupesDeGomory = OUI_PNE; + } + + NbProblemesResolus++; + YaUneSolution = BB_ExaminerUnNoeudEnProfondeur( Bb, NoeudCourant, &SolutionEntiereTrouvee + /*, NombreDeNoeudsAExplorer , NoeudsAExplorer + , NombreDeNoeudsAExplorerAuProchainEtage , NoeudsAExplorerAuProchainEtage*/ ); + + if ( SolutionEntiereTrouvee == OUI ) { + /* On a trouve une solution entiere */ + /*printf("!!!!!!!!!!!!!!!!!!!!!! Fin par atteinte de SolutionEntiereTrouvee \n");*/ + Bb->NbNoeuds1_PNE_BalayageEnProfondeur = 0; + Bb->NoeudEnExamen = 0; + return( OUI ); + } + else { + + if ( Bb->TypeDExplorationEnCours == PROFONDEUR_DANS_LARGEUR && YaUneSolution == OUI ) { + if ( IndexMoyenneMobile < TAILLE_MOYENNE_MOBILE ) { + if ( Pne->NombreDeVariablesAValeurFractionnaire > 0 ) { + VecteurPourMoyenneMobile[IndexMoyenneMobile] = Pne->NormeDeFractionnalite / Pne->NombreDeVariablesAValeurFractionnaire; + } + else VecteurPourMoyenneMobile[IndexMoyenneMobile] = 0; + IndexMoyenneMobile++; + } + else { + /* On fait de la place a la fin */ + for ( i = 0 ; i < TAILLE_MOYENNE_MOBILE - 1 ; i++ ) { + VecteurPourMoyenneMobile[i] = VecteurPourMoyenneMobile[i+1]; + } + /* On range la valeur a la fin */ + if ( Pne->NombreDeVariablesAValeurFractionnaire > 0 ) { + VecteurPourMoyenneMobile[TAILLE_MOYENNE_MOBILE - 1] = Pne->NormeDeFractionnalite / Pne->NombreDeVariablesAValeurFractionnaire; + } + else VecteurPourMoyenneMobile[TAILLE_MOYENNE_MOBILE - 1] = 0; + } + } + + /* Choix de la variable a instancier si le noeud est choisi au prochain etage */ + BB_CreerLesNoeudsFils( Bb, NoeudCourant ); + if ( Bb->SolutionEntiereTrouveeParHeuristique == OUI ) { + /* printf("!!!!!!!!!!!!!!!!! Fin par atteinte de SolutionEntiereTrouveeParHeuristique \n"); */ + Bb->NbNoeuds1_PNE_BalayageEnProfondeur = 0; + Bb->NoeudEnExamen = 0; + return( OUI ); + } + + } + + /* Si le critere du probleme (sans nouvelles coupes) est plus eleve que le minorant predit de l'autre noeud, + on evalue aussi l'autre noeud */ + EvaluerLAutreNoeud = NON; + if ( Les2ChoixSontPossibles == OUI ) { + if ( IndiceChoisi == 1 ) IndiceChoisi = 0; + else IndiceChoisi = 1; + MinorantPreditDeLAutreNoeud = NoeudsAExplorer[IndiceChoisi]->MinorantPredit; + /* Si on est en phase de recherche en largeur, on evalue les 2 noeuds */ + if ( Bb->TypeDExplorationEnCours == PROFONDEUR_DANS_LARGEUR ) { + /* Pour ne pas trop se perdre dans les calculs on se contente de diminuer le minorant predit */ + MinorantPreditDeLAutreNoeud *= 0.5; + } + + if ( PNE_ValeurOptimaleDuProblemeCourantAvantNouvellesCoupes( Pne ) >= MinorantPreditDeLAutreNoeud - MARGE_SUR_LES_MINORANTS ) { + #if VERBOSE_BB + printf(" Minorant calcule au noeud %lf minorant de l'autre noeud %e\n", + PNE_ValeurOptimaleDuProblemeCourantAvantNouvellesCoupes( Pne ),MinorantPreditDeLAutreNoeud); + #endif + EvaluerLAutreNoeud = OUI; + } + + if ( YaUneSolution == NON ) EvaluerLAutreNoeud = OUI; + /* Si le noeud au dessus est le noeud racine, on evalue les 2 noeuds */ + if ( NoeudCourant->ProfondeurDuNoeud <= 2 ) EvaluerLAutreNoeud = OUI; + + } + + if ( EvaluerLAutreNoeud == OUI ) { + NoeudCourant = NoeudsAExplorer[IndiceChoisi]; + if( NoeudCourant->StatutDuNoeud == EVALUE && NoeudCourant->LaSolutionRelaxeeEstEntiere == OUI ) { + Bb->NbNoeuds1_PNE_BalayageEnProfondeur = 0; + Bb->NoeudEnExamen = 0; + return( OUI ); + } + #if VERBOSE_BB + if ( Bb->TypeDExplorationEnCours == PROFONDEUR_TOUT_SEUL ) { + printf(" ************************************************ \n"); + printf(" Noeud (%d) %x (erreur de minorant predit) / Recherche en profondeur seule, profondeur du noeud %d\n", + IndiceChoisi,NoeudCourant,ProfondeurDuNoeud); + } + else { + printf(" ************************************************ \n"); + printf(" Noeud (%d) %x (erreur de minorant predit) / Recherche en profondeur dans un balayage en largeur, profondeur de depart %d , profondeur du noeud %d profondeur limite %d\n", + IndiceChoisi,NoeudCourant,ProfondeurDuNoeudDeDepart,ProfondeurDuNoeud,ProfondeurDuNoeudDeDepart+ProfondeurLimite); + } + fflush(stdout); + #endif + + if ( NoeudCourant == Bb->NoeudRacine ) { + /* Calcul de coupes au noeud racine */ + Bb->CalculerDesCoupes = OUI_PNE; + Bb->CalculerDesCoupesDeGomory = OUI_PNE; + } + + NbProblemesResolus++; + YaUneSolution = BB_ExaminerUnNoeudEnProfondeur( Bb, NoeudCourant, &SolutionEntiereTrouvee + /*, NombreDeNoeudsAExplorer , NoeudsAExplorer + , NombreDeNoeudsAExplorerAuProchainEtage , NoeudsAExplorerAuProchainEtage*/ ); + if ( SolutionEntiereTrouvee == OUI ) { + /*printf("!!!!!!!!!!!!!!!!!!!!!! Fin par atteinte de SolutionEntiereTrouvee \n");*/ + /* On a trouve une solution entiere */ + Bb->NbNoeuds1_PNE_BalayageEnProfondeur = 0; + Bb->NoeudEnExamen = 0; + return( OUI ); + } + else { + + if ( Bb->TypeDExplorationEnCours == PROFONDEUR_DANS_LARGEUR && YaUneSolution == OUI ) { + if ( IndexMoyenneMobile < TAILLE_MOYENNE_MOBILE ) { + if ( Pne->NombreDeVariablesAValeurFractionnaire > 0 ) { + VecteurPourMoyenneMobile[IndexMoyenneMobile] = Pne->NormeDeFractionnalite / Pne->NombreDeVariablesAValeurFractionnaire; + } + else VecteurPourMoyenneMobile[IndexMoyenneMobile] = 0; + IndexMoyenneMobile++; + } + else { + /* On fait de la place a la fin */ + for ( i = 0 ; i < TAILLE_MOYENNE_MOBILE - 1 ; i++ ) { + VecteurPourMoyenneMobile[i] = VecteurPourMoyenneMobile[i+1]; + } + /* On range la valeur a la fin */ + if ( Pne->NombreDeVariablesAValeurFractionnaire > 0 ) { + VecteurPourMoyenneMobile[TAILLE_MOYENNE_MOBILE - 1] = Pne->NormeDeFractionnalite / Pne->NombreDeVariablesAValeurFractionnaire; + } + else VecteurPourMoyenneMobile[TAILLE_MOYENNE_MOBILE - 1] = 0; + } + } + + /* Choix de la variable a instancier si le noeud est choisi au prochain etage */ + BB_CreerLesNoeudsFils( Bb, NoeudCourant ); + if ( Bb->SolutionEntiereTrouveeParHeuristique == OUI ) { + /* printf("!!!!!!!!!!!!!!!!!!!!!! Fin par atteinte de SolutionEntiereTrouveeParHeuristique \n"); */ + Bb->NbNoeuds1_PNE_BalayageEnProfondeur = 0; + Bb->NoeudEnExamen = 0; + return( OUI ); + } + } + } + } + + /* Preparation de l'etage suivant */ + NoeudPereSuivant = BB_NoeudPereSuivantDansRechercheEnProfondeur( NoeudsAExplorer ); + + if ( NoeudPereSuivant == 0 ) { + /*printf("Pas de NoeudPereSuivant NbProblemesResolus = %d\n",NbProblemesResolus);*/ + NoeudPereSuivant = BB_RemonterDansRechercheEnProfondeur( NoeudAntecedent, ProfondeurDuNoeudDeDepart ); + if ( NoeudPereSuivant != 0 ) { + /* Le NoeudPereSuivant est le pere de celui la */ + NoeudPereSuivant = NoeudPereSuivant->NoeudAntecedent; + } + else { + /*printf("Fin par NoeudPereSuivant = 0 \n");*/ + /*printf("Confirmation pas de NoeudPereSuivant NbProblemesResolus = %d\n",NbProblemesResolus);*/ + break; /* Pas de solution */ + } + + /* Normalement les 2 fils doivent deja exister sinon c'est un bug */ + if ( NoeudPereSuivant->NoeudSuivantGauche == 0 || NoeudPereSuivant->NoeudSuivantDroit == 0 ) { + printf(" BUG dans la recherche en profondeur: le noeud pere n'a pas ses 2 fils \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + } + + NoeudAntecedent = NoeudPereSuivant; + ProfondeurDuNoeud = NoeudAntecedent->ProfondeurDuNoeud; /* Profondeur du prochain etage */ + ProfondeurDuNoeud++; /* Profondeur du prochain etage */ + +/* printf("NoeudPereSuivant %08X \n",NoeudPereSuivant); fflush(stdout); */ + + /* Renseigner la table des noeuds du prochain etage */ + NoeudsAExplorer[0] = NoeudPereSuivant->NoeudSuivantGauche; + NoeudsAExplorer[1] = NoeudPereSuivant->NoeudSuivantDroit; + +/* Fin while */ +} + +Bb->NbNoeuds1_PNE_BalayageEnProfondeur = 0; /* Pour le nettoyage eventuel */ + +#if VERBOSE_BB + printf("\n Le probleme n'a pas de solution entiere dans la recherche en profondeur \n"); fflush(stdout); +#endif + +Bb->NoeudEnExamen = 0; +SolutionEntiereTrouvee = NON; +/*printf(" !!!!!!!!!!!!! Pas de solution trouvee dans la recherche en profondeur \n");*/ +return( NON ); /* return avec l'indicateur ya pas de solution */ +} + +/*-----------------------------------------------------------------------------------------------*/ + +int BB_ExaminerUnNoeudEnProfondeur( BB * Bb, NOEUD * NoeudCourant, + int * SolutionEntiereTrouvee + /*int NombreDeNoeudsAExplorer, + NOEUD ** NoeudsAExplorer, + int NombreDeNoeudsAExplorerAuProchainEtage, + NOEUD ** NoeudsAExplorerAuProchainEtage*/ ) +{ +int YaUneSolution; + +Bb->NoeudEnExamen = NoeudCourant; + /* Exploration du noeud */ +YaUneSolution = BB_ResoudreLeProblemeRelaxe( Bb, NoeudCourant, SolutionEntiereTrouvee ); + +BB_NettoyerLArbre( Bb, &YaUneSolution , NoeudCourant ); /* Fait aussi la mise a jour du statut */ + +return( YaUneSolution ); +} + +/*-----------------------------------------------------------------------------------------------*/ +/* + Recherche d'un noeud pere suivant en descendant dans l'arbre. Le noeud pere sera + eventuellement divise. + */ + +NOEUD * BB_NoeudPereSuivantDansRechercheEnProfondeur( NOEUD ** NoeudsAExplorer ) +{ +NOEUD * NoeudGauche; NOEUD * NoeudDroit; NOEUD * NoeudPereSuivant; NOEUD * NoeudFils; +double PlusPetitMinorantPredit; + +/* +Noeud pere suivant: +- Ne doit pas etre TERMINAL +- Ne doit pas etre A_REJETER +- Est celui des 2 qui a le plus petit minorant +*/ + +NoeudPereSuivant = 0; + +/* printf("\n Recherche d un NoeudPereSuivant sur NoeudsAExplorer[0] et NoeudsAExplorer[1] \n"); fflush(stdout); */ + +NoeudGauche = NoeudsAExplorer[0]; +NoeudDroit = NoeudsAExplorer[1]; + +PlusPetitMinorantPredit = PLUS_LINFINI; + +if ( NoeudGauche != 0 && NoeudDroit != 0 ) { + /* Les 2 noeuds existent: on prend celui dont les fils ont le plus petit minorant predit */ + if ( NoeudGauche->NoeudTerminal == OUI || NoeudGauche->StatutDuNoeud == A_REJETER ) { + /* Le noeud gauche est inutilisable, il reste donc le noeud droit */ + if ( NoeudDroit->NoeudTerminal != OUI && NoeudDroit->StatutDuNoeud != A_REJETER ) { + NoeudPereSuivant = NoeudDroit; + } + return( NoeudPereSuivant ); + } + if ( NoeudDroit->NoeudTerminal == OUI || NoeudDroit->StatutDuNoeud == A_REJETER ) { + /* Le noeud droit est inutilisable, il reste donc le noeud gauche */ + if ( NoeudGauche->NoeudTerminal != OUI && NoeudGauche->StatutDuNoeud != A_REJETER ) { + NoeudPereSuivant = NoeudGauche; + } + return( NoeudPereSuivant ); + } + /* On peut utiliser les 2 noeud => on prend celui qui a le plus petit minorant predit */ + /* + NoeudPereSuivant = NoeudGauche; + if ( NoeudDroit->MinorantDuCritereAuNoeud < NoeudGauche->MinorantDuCritereAuNoeud ) { + NoeudPereSuivant = NoeudDroit; + } + */ + /* Alternative: On peut utiliser les 2 noeud => on prend celui dont les fils ont les plus petits minorant predit */ + NoeudFils = NoeudGauche->NoeudSuivantGauche; + if ( NoeudFils != 0 ) { + if ( NoeudFils->MinorantPredit < PlusPetitMinorantPredit ) { + PlusPetitMinorantPredit = NoeudFils->MinorantPredit; + NoeudPereSuivant = NoeudGauche; + } + } + NoeudFils = NoeudGauche->NoeudSuivantDroit; + if ( NoeudFils != 0 ) { + if ( NoeudFils->MinorantPredit < PlusPetitMinorantPredit ) { + PlusPetitMinorantPredit = NoeudFils->MinorantPredit; + NoeudPereSuivant = NoeudGauche; + } + } + NoeudFils = NoeudDroit->NoeudSuivantGauche; + if ( NoeudFils != 0 ) { + if ( NoeudFils->MinorantPredit < PlusPetitMinorantPredit ) { + PlusPetitMinorantPredit = NoeudFils->MinorantPredit; + NoeudPereSuivant = NoeudDroit; + } + } + NoeudFils = NoeudDroit->NoeudSuivantDroit; + if ( NoeudFils != 0 ) { + if ( NoeudFils->MinorantPredit < PlusPetitMinorantPredit ) { + PlusPetitMinorantPredit = NoeudFils->MinorantPredit; + NoeudPereSuivant = NoeudDroit; + } + } + + return( NoeudPereSuivant ); +} + +/* On a soit NoeudGauche = 0 soit NoeudDroit = 0 soit les deux */ +if ( NoeudGauche != 0 ) { + /* Alors NoeudDroit = 0 n'est pas utilisable */ + if ( NoeudGauche->NoeudTerminal != OUI && NoeudGauche->StatutDuNoeud != A_REJETER ) { + NoeudPereSuivant = NoeudGauche; + } + return( NoeudPereSuivant ); +} + +if ( NoeudDroit != 0 ) { + /* Alors NoeudGauche = 0 n'est pas utilisable */ + if ( NoeudDroit->NoeudTerminal != OUI && NoeudDroit->StatutDuNoeud != A_REJETER ) { + NoeudPereSuivant = NoeudDroit; + } + return( NoeudPereSuivant ); +} + +return( NoeudPereSuivant ); + +} + +/*-----------------------------------------------------------------------------------------------*/ +/* + Cas ou on n'a pas trouve de noeud pere en descendant. On remonte donc l'arbre jusqu'a + trouver un noeud pere qui sera eventuellement divise. + */ + +NOEUD * BB_RemonterDansRechercheEnProfondeur( NOEUD * NoeudAntecedent, int ProfondeurDuNoeudDeDepart ) +{ +NOEUD * Noeud; NOEUD * NoeudPereSuivant; NOEUD * NoeudCourant; +/* + Aucun noeud a diviser => 2 possibilites: + - Les noeuds de l'etage examine ont deja ete divises et ne sont pas terminaux. Dans ce cas on descend sur les fils. + - Les 2 noeuds sont terminaux. Comme on n'a pas encore trouve de solution, on remonte dans l'arbre pour prendre un + autre chemin non encore explore. +*/ + +NoeudPereSuivant = 0; +NoeudCourant = NoeudAntecedent; + +while ( NoeudCourant != 0 && NoeudCourant->ProfondeurDuNoeud >= ProfondeurDuNoeudDeDepart ) { + /* + printf("\n Recherche en profondeur, on remonte d'un cran NoeudCourant %d ProfondeurDuNoeud %d ProfondeurDuNoeudDeDepart %d\n", + NoeudCourant,NoeudCourant->ProfondeurDuNoeud,ProfondeurDuNoeudDeDepart); + */ + /* + On s'arrete se remonter lorsqu'on a trouve un NoeudCourant: + - qui n'est ni A_REJETER ni Terminal + et dont un des fils: + - n'est ni A_REJETER ni Terminal + Dans ce cas le NoeudPereSuivant est le fils + */ + + if ( NoeudCourant->StatutDuNoeud != A_REJETER && NoeudCourant->NoeudTerminal != OUI ) { + /* Le noeud n'est ni a rejeter ni terminal => on peut regarder */ + /* Si un de ses fils n'est ni a rejeter ni terminal, on le prend */ + Noeud = NoeudCourant->NoeudSuivantGauche; /* Fils 0 */ + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud != A_REJETER && Noeud->NoeudTerminal != OUI ) { + NoeudPereSuivant = Noeud; + break; + } + } + Noeud = NoeudCourant->NoeudSuivantDroit; /* Fils 1 */ + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud != A_REJETER && Noeud->NoeudTerminal != OUI ) { + NoeudPereSuivant = Noeud; + break; + } + } + /* Comme les 2 noeuds sont terminaux ou a rejeter, le pere est terminal et a rejeter aussi */ + NoeudCourant->StatutDuNoeud = A_REJETER; + NoeudCourant->NoeudTerminal = OUI; + } + /* On remonte encore d'un cran */ + NoeudCourant = NoeudCourant->NoeudAntecedent; +} + +return( NoeudPereSuivant ); + +} + + + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_best_first.c b/src/ext/Sirius_Solver/branchAndBound/bb_best_first.c new file mode 100644 index 0000000000..1b4798ed82 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_best_first.c @@ -0,0 +1,103 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/************************************************************************* + + FONCTION: Exploration du meilleur minorant. Cette routine ne peut + etre appelee que si on dispose deja d'une solution + entiere. + + AUTEUR: R. GONZALEZ + +**************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_BestFirst( BB * Bb ) +{ +double Gap; double Seuil; double MinorantDuCritereAuNoeud; int Nb; int NbMx; double X; +char Break; NOEUD * Noeud; + +/* Precaution */ +if ( Bb->NombreDeSolutionsEntieresTrouvees <= 0 ) return; +/* Precaution */ +Bb->EvaluerLesFilsDuMeilleurMinorant = OUI; + +NbMx = Bb->NombreDEvaluationDuMeilleurMinorant; + +Nb = 0; +BB_RechercherLeMeilleurMinorant( Bb, RECHERCHER_LE_PLUS_PETIT ); +if ( Bb->NoeudDuMeilleurMinorant == 0 ) return; + +Bb->ValeurDuMeilleurPremierMinorant = Bb->NoeudDuMeilleurMinorant->MinorantDuCritereAuNoeud; + +Bb->ValeurDuMeilleurDernierMinorant = Bb->ValeurDuMeilleurPremierMinorant; + +Gap = Bb->CoutDeLaMeilleureSolutionEntiere - Bb->ValeurDuMeilleurMinorant; +Seuil = 0.99 * Gap; + +if ( Bb->NoeudDuMeilleurMinorant != 0 ) { + MinorantDuCritereAuNoeud = Bb->NoeudDuMeilleurMinorant->MinorantDuCritereAuNoeud; + while ( Nb < NbMx && (Bb->NoeudDuMeilleurMinorant->MinorantDuCritereAuNoeud - MinorantDuCritereAuNoeud) < Seuil && + Bb->ArreterLesCalculs == NON ) { + Nb++; + X = Bb->NoeudDuMeilleurMinorant->MinorantDuCritereAuNoeud; + BB_EvaluerLesDeuxFilsDuMeilleurMinorant( Bb, Bb->NoeudDuMeilleurMinorant ); + Break = NON; + if ( Bb->NoeudDuMeilleurMinorant != 0 && 0 ) { + Noeud = Bb->NoeudDuMeilleurMinorant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + if ( Noeud->MinorantDuCritereAuNoeud - X < 1.e-8 ) Break = OUI; + } + Noeud = Bb->NoeudDuMeilleurMinorant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + if ( Noeud->MinorantDuCritereAuNoeud - X < 1.e-8 ) Break = OUI; + } + } + BB_RechercherLeMeilleurMinorant( Bb, RECHERCHER_LE_PLUS_PETIT ); + if ( Bb->NoeudDuMeilleurMinorant == 0 ) break; + Bb->ValeurDuMeilleurDernierMinorant = Bb->NoeudDuMeilleurMinorant->MinorantDuCritereAuNoeud; + if ( Break == OUI ) break; + } +} + +/* Precaution */ +Bb->EvaluerLesFilsDuMeilleurMinorant = NON; + +if ( Bb->ValeurDuMeilleurDernierMinorant - Bb->ValeurDuMeilleurPremierMinorant < 1.e-7 ) { + /* On n'arrive pas a faire monter les minorants. + Il vaut mieux passer du temps a chercher des solutions entieres */ + /*Bb->NombreDEvaluationDuMeilleurMinorant = 2;*/ + /* Apres test: mieux vaut conserver la meme valeur */ + Bb->NombreDEvaluationDuMeilleurMinorant = NOMBRE_DEVALUATIONS_DU_MEILLEUR_MINORANT; +} +else { + Bb->NombreDEvaluationDuMeilleurMinorant = NOMBRE_DEVALUATIONS_DU_MEILLEUR_MINORANT; +} + +return; +} + + + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_branch_and_bound.c b/src/ext/Sirius_Solver/branchAndBound/bb_branch_and_bound.c new file mode 100644 index 0000000000..d3f22c0384 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_branch_and_bound.c @@ -0,0 +1,100 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Pilotage du branch and bound + + Appele comme un sous-programme du programme fortran maitre. Ce + sous-programme orchestre le déroulement de la recherche arborescente. + Les etapes sont les suivantes: + 1- Creation du noeud racine. + 2- Recherche en profondeur a partie du noeud racine pour trouver une + solution entiere admissible. + 3- Recherche en largeur a partir du noeud racine pour trouver la + solution optimale. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "bb_sys.h" +# include "bb_define.h" +# include "bb_fonctions.h" + +# include "pne_define.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*---------------------------------------------------------------------------------------------------------*/ + +int BB_BranchAndBound( void * PneE, + int TempsDexecutionMaximum, int NombreMaxDeSolutionsEntieres, double ToleranceDOptimalite, + int NbVar, int NbContr , int NbVarEntieres , char AffichageDesTraces , + int * NumVarEntieres ) +{ +BB * Bb; PROBLEME_PNE * Pne; int YaUneSolution; void * Tas; + +Bb = NULL; + +if ( Bb == NULL ) { + # ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + Tas = MEM_Init(); + Bb = (BB *) MEM_Malloc( Tas, sizeof( BB ) ); + if ( Bb == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet BB\n"); + YaUneSolution = BB_ERREUR_INTERNE; + return( YaUneSolution ); + } + Bb->Tas = Tas; + # else + Bb = (BB *) malloc( sizeof( BB ) ); + if ( Bb == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet BB\n"); + YaUneSolution = BB_ERREUR_INTERNE; + return( YaUneSolution ); + } + Tas = NULL; + Bb->Tas = Tas; + # endif +} + +Pne = (PROBLEME_PNE *) PneE; +/* Initialisation de ProblemeBbDuSolveur pour la partie PNE */ +Pne->ProblemeBbDuSolveur = (void *) Bb; +Bb->ProblemePneDuBb = PneE; + +Bb->AnomalieDetectee = NON; +setjmp( Bb->EnvBB ); +if ( Bb->AnomalieDetectee == OUI ) { + YaUneSolution = BB_ERREUR_INTERNE; + /* Liberation du probleme */ + BB_BranchAndBoundDesallouerProbleme( Bb ); + Pne->ProblemeBbDuSolveur = NULL; +} +else { + /* Recherche arborescente */ + YaUneSolution = BB_BranchAndBoundCalculs( Bb, TempsDexecutionMaximum, NombreMaxDeSolutionsEntieres, ToleranceDOptimalite, + NbVar, NbContr, NbVarEntieres, AffichageDesTraces, NumVarEntieres ); + Pne->ProblemeBbDuSolveur = NULL; +} + +return( YaUneSolution ); + +} + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_branch_and_bound_calculs.c b/src/ext/Sirius_Solver/branchAndBound/bb_branch_and_bound_calculs.c new file mode 100644 index 0000000000..f2f6fbf722 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_branch_and_bound_calculs.c @@ -0,0 +1,273 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Pilotage du branch and bound + + Appele comme un sous-programme du programme fortran maitre. Ce + sous-programme orchestre le déroulement de la recherche arborescente. + Les etapes sont les suivantes: + 1- Creation du noeud racine. + 2- Recherche en profondeur a partie du noeud racine pour trouver une + solution entiere admissible. + 3- Recherche en largeur a partir du noeud racine pour trouver la + solution optimale. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "spx_define.h" + +#include "pne_fonctions.h" + +char TestLocalBranching = NON/*OUI*/; + +/*---------------------------------------------------------------------------------------------------------*/ + +int BB_BranchAndBoundCalculs( BB * Bb, + int TempsDexecutionMaximum, int NombreMaxDeSolutionsEntieres, + double ToleranceDOptimalite, int NbVar, int NbContr, + int NbVarEntieres, char AffichageDesTraces, + int * NumVarEntieres ) +{ +NOEUD * NoeudAntecedent; NOEUD * Noeud; NOEUD * NoeudDeDepart; int ProfondeurDuNoeud; int ProfondeurDuNoeudDeDepart; +int i; int YaUneSolution; int ValeurDeLaNouvelleVariableIntanciee; int IndiceDeLaNouvelleVariableIntanciee; +int FilsACreer; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; + +Bb->ArreterLesCalculs = NON; +Bb->TempsDexecutionMaximum = TempsDexecutionMaximum; +Bb->ForcerAffichage = NON; +Bb->AffichageDesTraces = AffichageDesTraces; +Bb->NombreMaxDeSolutionsEntieres = NombreMaxDeSolutionsEntieres; +Bb->ToleranceDOptimalite = ToleranceDOptimalite; + +Bb->CoutDeLaMeilleureSolutionEntiere = PLUS_LINFINI; +Bb->NoeudDeLaMeilleureSolutionEntiere = 0; +Bb->ProfondeurMoyenneDesSolutionsEntieres = -1; + +Bb->ValeurDuMeilleurMinorant = -PLUS_LINFINI; + +Bb->NombreDeVariablesEntieresDuProbleme = NbVarEntieres; + +Bb->ProfondeurMaxiSiPlongeePendantUneRechercheEnLargeur = -1; + +Bb->NombreDEvaluationDuMeilleurMinorant = NOMBRE_DEVALUATIONS_DU_MEILLEUR_MINORANT; + +Bb->EnleverToutesLesCoupesDuPool = NON; + +Bb->NbMaxDeCoupesCalculeesAtteint = NON; +Bb->NombreMaxDeCoupes = NOMBRE_MAX_DE_COUPES; +Bb->NombreMoyenMinimumDeCoupesUtiles = NOMBRE_MOYEN_MINIMUM_DE_COUPES_UTILES; + +#if VERBOSE_BB + printf("\n Nombre de variable entieres du probleme: %d\n", Bb->NombreDeVariablesEntieresDuProbleme); +#endif + +Bb->NombreDeVariablesDuProbleme = NbVar ; + +#if VERBOSE_BB + printf(" Nombre de variable du probleme: %d\n", Bb->NombreDeVariablesDuProbleme); +#endif + +Bb->NombreDeContraintesDuProbleme = NbContr; + +#if VERBOSE_BB + printf(" Nombre de contraintes du probleme: %d\n", Bb->NombreDeContraintesDuProbleme); +#endif + +Bb->NombreDeProblemesRelaxesResolus = 0; +Bb->NombreDeProblemesResolus = 0; +Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes = 0; +Bb->NombreDeSolutionsEntieresTrouvees = 0; +Bb->NbProbPourLaPremiereSolutionEntiere = 0; + +Bb->NombreTotalDeCoupesDuPoolUtilisees = 0; +Bb->NombreTotalDeGDuPoolUtilisees = 0; +Bb->NombreTotalDeIDuPoolUtilisees = 0; +Bb->NombreTotalDeKDuPoolUtilisees = 0; + +Bb->NombreDeNoeudsElagues = 0; +Bb->AveragePruningDepth = 0; +Bb->SommeDesProfondeursDesSolutionsAmeliorantes = 0; +Bb->NombreDeSolutionsAmeliorantes = 0; + +Bb->SommeDesProfondeursDElaguage = 0; + +Bb->NombreDeSimplexes = 0; +Bb->SommeDuNombreDIterations = 0; + +Bb->EvaluerLesFilsDuMeilleurMinorant = NON; +Bb->EcartBorneInf = 1.e+70; + +Bb->NbNoeudsOuverts = 0; + +Bb->DernierNoeudResolu = 0; + +BB_BranchAndBoundAllouerProbleme( Bb ); + +for ( i = 0 ; i < Bb->NombreDeVariablesEntieresDuProbleme ; i++ ) { + Bb->NumerosDesVariablesEntieresDuProbleme[i] = NumVarEntieres[i]; +} + +Bb->NbNoeuds1_PNE_BalayageEnProfondeur = 0; +Bb->NbNoeuds1_PNE_NettoyerLArbreDeLaRechercheEnProfondeur = 0; +Bb->NbNoeuds2_PNE_NettoyerLArbreDeLaRechercheEnProfondeur = 0; +Bb->NbNoeuds1_PNE_BalayageEnLargeur = 0; +Bb->NbNoeuds2_PNE_BalayageEnLargeur = 0; +Bb->NbNoeuds1_PNE_EliminerLesNoeudsSousOptimaux = 0; +Bb->NbNoeuds2_PNE_EliminerLesNoeudsSousOptimaux = 0; +Bb->NbNoeuds1_PNE_SupprimerTousLesDescendantsDUnNoeud = 0; +Bb->NbNoeuds2_PNE_SupprimerTousLesDescendantsDUnNoeud = 0; + +Bb->NombreMaxDeCoupesParProblemeRelaxe = (int) ceil ( MAX_COUPES_PAR_PROBLEME_RELAXE * Bb->NombreDeContraintesDuProbleme ); +if ( Bb->NombreMaxDeCoupesParProblemeRelaxe < 100 ) Bb->NombreMaxDeCoupesParProblemeRelaxe = 100; + +/* Creation du noeud racine */ + +NoeudAntecedent = 0; +ProfondeurDuNoeud = 0; +FilsACreer = FILS_DROIT; /* Mais cela n'a pas d'importance car c'est le noeud racine */ +ValeurDeLaNouvelleVariableIntanciee = 1; +IndiceDeLaNouvelleVariableIntanciee = -1; + +Noeud = BB_AllouerUnNoeud( Bb, NoeudAntecedent, + ProfondeurDuNoeud, + FilsACreer, + ValeurDeLaNouvelleVariableIntanciee, + 0, + &IndiceDeLaNouvelleVariableIntanciee, + -PLUS_LINFINI ); +Bb->NoeudRacine = Noeud; +Bb->BaseDisponibleAuNoeudRacine = NON; + +/* Recherche d'une solution entiere admissible par un balayage en profondeur a partir du noeud racine */ +Bb->UtiliserCoutDeLaMeilleureSolutionEntiere = NON_SPX; +Bb->TypeDExplorationEnCours = PROFONDEUR_TOUT_SEUL; + +ProfondeurDuNoeudDeDepart = 0; +NoeudDeDepart = Bb->NoeudRacine; + +YaUneSolution = BB_BalayageEnProfondeur( Bb, NoeudDeDepart , ProfondeurDuNoeudDeDepart ); + +if ( Pne->YaUneSolutionEntiere == NON_PNE ) YaUneSolution = NON_PNE; + +if( YaUneSolution != OUI ) { + /* On a neanmoins pu trouver une solution entiere */ + if ( Pne->YaUneSolutionEntiere == NON_PNE ) { + #if VERBOSE_BB + printf("PAS DE SOLUTION ENTIERE \n"); + #endif + YaUneSolution = NON; + goto FinDuBranchAndBound; + } +} + +/**********************************************************************/ +if ( TestLocalBranching == OUI ) { + TestLocalBranching = NON; + goto RestitutionPremiereSolution; +} +/**********************************************************************/ + +if ( Bb->NombreDeVariablesEntieresDuProbleme > 0 ) { + + /* Recherche de la solution optimale par un balayage en largeur a partir du noeud racine */ + Bb->NbProbPourLaPremiereSolutionEntiere = Bb->NombreDeProblemesResolus; + + Bb->UtiliserCoutDeLaMeilleureSolutionEntiere = OUI_SPX; + + ProfondeurDuNoeudDeDepart = 0; + NoeudDeDepart = Bb->NoeudRacine; + BB_BalayageEnLargeur( Bb, NoeudDeDepart, ProfondeurDuNoeudDeDepart ); + + #if VERBOSE_BB + printf("\n \n FIN DE LA RECHERCHE EN LARGEUR \n \n"); + #endif + +} + +if ( Pne->YaUneSolutionEntiere == NON_PNE ) YaUneSolution = NON_PNE; + +if( YaUneSolution != OUI ) { + /* On a neanmoins pu trouver une solution entiere */ + if ( Pne->YaUneSolutionEntiere == NON_PNE ) { + #if VERBOSE_BB + printf("PAS DE SOLUTION ENTIERE \n"); + #endif + YaUneSolution = NON; + goto FinDuBranchAndBound; + } +} + +/* Resultat */ + +RestitutionPremiereSolution: + +YaUneSolution = OUI; +if ( Bb->ArreterLesCalculs == OUI ) { + if ( Bb->EcartBorneInf > Bb->ToleranceDOptimalite ) YaUneSolution = ARRET_CAR_TEMPS_MAXIMUM_ATTEINT; +} + +PNE_RestituerLaSolutionArchivee( Pne ); + +FinDuBranchAndBound: + +if ( Bb->NombreDeVariablesEntieresDuProbleme > 0 && YaUneSolution != NON && Bb->AffichageDesTraces == OUI ) { + printf("\n"); + printf("** Solution summary **\n"); + if ( YaUneSolution == ARRET_CAR_TEMPS_MAXIMUM_ATTEINT ) { + printf(" Stopping calculation because maximum allowed time has been reached.\n"); + } + else if ( YaUneSolution == OUI ) { + printf(" Optimal solution found\n"); + } + printf(" Solved nodes before finding the first feasible solution: %d\n",Bb->NbProbPourLaPremiereSolutionEntiere); + if ( YaUneSolution == ARRET_CAR_TEMPS_MAXIMUM_ATTEINT ) { + printf(" Best feasible solution found after: %d nodes\n",Bb->NumeroDeProblemeDeLaSolutionAmeliorante); + } + else if ( YaUneSolution == OUI ) { + printf(" Solved nodes to find an optimal solution: %d\n",Bb->NumeroDeProblemeDeLaSolutionAmeliorante); + } + printf(" Total solved nodes: %d\n",Bb->NombreDeProblemesResolus); + printf(" Feasible solutions found: %d\n",Bb->NombreDeSolutionsEntieresTrouvees); + + { PROBLEME_PNE * Pne; double TempsEcoule; + Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; + time( &(Pne->HeureDeCalendrierCourant) ); + TempsEcoule = difftime( Pne->HeureDeCalendrierCourant , Pne->HeureDeCalendrierDebut ); + if ( TempsEcoule <= 0.0 ) TempsEcoule = 0.0; + printf(" Elapsed time: %d seconds\n",(int) TempsEcoule); + } + + printf(" Solved relaxed problems: %d\n",Bb->NombreDeProblemesRelaxesResolus); + printf("\n"); +} + +/* On libere le probleme */ +BB_BranchAndBoundDesallouerProbleme( Bb ); + +return( YaUneSolution ); + +} + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_choix_des_variables_a_instancier.c b/src/ext/Sirius_Solver/branchAndBound/bb_choix_des_variables_a_instancier.c new file mode 100644 index 0000000000..44186dfc70 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_choix_des_variables_a_instancier.c @@ -0,0 +1,81 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Apres la resolution d'un probleme relaxe, ce sous-programme + initialise le numero de la prochaine variable a instancier dans les + 2 noeuds fils. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_fonctions.h" + +/*---------------------------------------------------------------------------------------------------------*/ + +int BB_ChoixDesVariablesAInstancier( BB * Bb, + NOEUD * NoeudCourant, + int * ValeurDInstanciationAGauche, + int * NombreDeVariablesAInstancierAGauche, + int ** NumerosDesVariablesAInstancierAGauche, + int * ValeurDInstanciationADroite, + int * NombreDeVariablesAInstancierADroite, + int ** NumerosDesVariablesAInstancierADroite + ) +{ +int CodeRetour; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; + +CodeRetour = PAS_DE_VARIABLES_A_INSTANCIER; + +if( NoeudCourant->LaSolutionRelaxeeEstEntiere == OUI ) { + CodeRetour = PAS_DE_VARIABLES_A_INSTANCIER; + return( CodeRetour ); +} + +if( NoeudCourant->NoeudTerminal == OUI ) { + CodeRetour = PAS_DE_VARIABLES_A_INSTANCIER; + return( CodeRetour ); +} + +/* Si le noeud est A_REJETER, il n'y a rien a instancier */ +if ( NoeudCourant->StatutDuNoeud == A_REJETER ) { + CodeRetour = PAS_DE_VARIABLES_A_INSTANCIER; + return( CodeRetour ); +} + +/* Appel de la partie PNE: on recupere soit une variable, soit une Gub */ +PNE_ChoixDesVariablesAInstancier( Pne, + ValeurDInstanciationAGauche, + NombreDeVariablesAInstancierAGauche, + NumerosDesVariablesAInstancierAGauche, + ValeurDInstanciationADroite, + NombreDeVariablesAInstancierADroite, + NumerosDesVariablesAInstancierADroite + ); + +CodeRetour = VARIABLES_A_INSTANCIER; +return( CodeRetour ); + +} + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_controler_les_coupes_non_prises_en_compte.c b/src/ext/Sirius_Solver/branchAndBound/bb_controler_les_coupes_non_prises_en_compte.c new file mode 100644 index 0000000000..520f6bb1b8 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_controler_les_coupes_non_prises_en_compte.c @@ -0,0 +1,87 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Controle des coupes qui n'avaient pas ete inserees dans le + probleme. Si necessaire on les introduit dans le probleme + en vue d'une nouvelle resolution. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" +#include "pne_fonctions.h" + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_ControlerLesCoupesNonInsereesInitialement( BB * Bb, char * YaDesCoupesAjoutees ) +{ +COUPE ** Coupe; int NumeroDeCoupe; int il; double X; double Marge; NOEUD * NoeudCourant; +int i; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; + +NoeudCourant = Bb->NoeudEnExamen; +Marge = 1.; + +*YaDesCoupesAjoutees = NON; + +Coupe = Bb->NoeudRacine->CoupesGenereesAuNoeud; +for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud ; NumeroDeCoupe++ ) { + Coupe[NumeroDeCoupe]->CoupeExamineeAuNoeudCourant = NON; +} +for ( i = 0 ; i < Bb->NombreDeCoupesAjoutees ; i++ ) { + Coupe[Bb->NoeudRacine->NumeroDesCoupeAjouteeAuProblemeCourant[i]]->CoupeExamineeAuNoeudCourant = OUI; +} + +/* Marquage des coupes que l'on pourra utiliser */ +for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud ; NumeroDeCoupe++ ) { + if ( Coupe[NumeroDeCoupe]->CoupeExamineeAuNoeudCourant == OUI ) continue; + X = 0.; + for ( il = 0 ; il < Coupe[NumeroDeCoupe]->NombreDeTermes ; il++ ) { + X += Coupe[NumeroDeCoupe]->Coefficient[il] * + Bb->ValeursCalculeesDesVariablesPourLeProblemeRelaxeCourant[ Coupe[NumeroDeCoupe]->IndiceDeLaVariable[il] ]; + } + if ( X > Coupe[NumeroDeCoupe]->SecondMembre + Marge ) { + *YaDesCoupesAjoutees = OUI; + /* La coupe est violee => on l'ajoute au probleme courant */ + Bb->NoeudRacine->NumeroDesCoupeAjouteeAuProblemeCourant[Bb->NombreDeCoupesAjoutees] = NumeroDeCoupe; + Bb->NombreDeCoupesAjoutees++; + /* Pour avoir une base inversible */ + Coupe[NumeroDeCoupe]->CoupeSaturee = NON_PNE; + PNE_InsererUneContrainte( Pne, + Coupe[NumeroDeCoupe]->NombreDeTermes, + Coupe[NumeroDeCoupe]->Coefficient, + Coupe[NumeroDeCoupe]->IndiceDeLaVariable, + Coupe[NumeroDeCoupe]->SecondMembre, + Coupe[NumeroDeCoupe]->CoupeSaturee, + Coupe[NumeroDeCoupe]->TypeDeCoupe + ); + Bb->NombreTotalDeCoupesDuPoolUtilisees++; + } +} + +return; +} + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_creation_noeud.c b/src/ext/Sirius_Solver/branchAndBound/bb_creation_noeud.c new file mode 100644 index 0000000000..3ee81fd4f5 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_creation_noeud.c @@ -0,0 +1,491 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Allocation / Desallocation + + Allocation d'un noeud: il renseigne le champ adresse de l'antecedent + mais pas les adresses des noeuds suivants. + Si le noeud antecedent est a rejeter ou terminal, le fils n'est pas cree et on renvoie Noeud = 0 + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*---------------------------------------------------------------------------------------------------------------*/ + +NOEUD * BB_AllouerUnNoeud( BB * Bb, + NOEUD * NoeudAntecedent, + int ProfondeurDuNoeud, + int FilsACreer, + int ValeurDInstanciation, + int NombreDeVariablesAInstancier, + int * NumerosDesVariablesAInstancier, + double MinorantPredit ) +{ +NOEUD * Noeud; int i; int Marge; int Var; + +Bb->NbNoeudsOuverts++; + +if( NoeudAntecedent != 0 ) { + if ( NoeudAntecedent->StatutDuNoeud == A_REJETER ) { + BB_DesallocationPartielleDUnNoeud( NoeudAntecedent ); + return( 0 ); + } + if ( NoeudAntecedent->NoeudTerminal == OUI ) { + BB_DesallocationPartielleDUnNoeud( NoeudAntecedent ); + return( 0 ); + } +} + +Noeud = (NOEUD *) malloc( sizeof(NOEUD) ); +if ( Noeud == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_AllouerUnNoeud \n"); fflush(stdout); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} + +Noeud->ProfondeurDuNoeud = ProfondeurDuNoeud; +Noeud->StatutDuNoeud = A_EVALUER; +Noeud->NoeudTerminal = NON; + +Noeud->NombreDeVariablesEntieresInstanciees = 0; + +Noeud->NbValeursFractionnairesApresResolution = Bb->NombreDeVariablesEntieresDuProbleme + - Noeud->NombreDeVariablesEntieresInstanciees; +if( NoeudAntecedent == 0 ) { + /* C'est le noeud racine */ + Noeud->BaseFournie = NON; + Noeud->IndiceDeLaNouvelleVariableInstanciee = -1; + /* Taille des tableaux a allouer */ + i = 1; +} +else { + i = NoeudAntecedent->NombreDeVariablesEntieresInstanciees; + /* Taille des tableaux a allouer */ + i+= NombreDeVariablesAInstancier; +} + +Noeud->ValeursDesVariablesEntieresInstanciees = (char *) malloc( i * sizeof(char) ); +Noeud->IndicesDesVariablesEntieresInstanciees = (int *) malloc( i * sizeof(int) ); + +if ( Noeud->ValeursDesVariablesEntieresInstanciees == NULL || Noeud->IndicesDesVariablesEntieresInstanciees == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_AllouerUnNoeud \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} + +/* Pour pouvoir travailler avec la forme standard, on surdimensionne le vecteur avec le nombre de contraintes (inutile maintenant) */ +Noeud->PositionDeLaVariable = (int *) malloc( ( Bb->NombreDeVariablesDuProbleme /*+ Bb->NombreDeContraintesDuProbleme*/ ) * sizeof(int) ); +if ( Noeud->PositionDeLaVariable == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_AllouerUnNoeud \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} + +Noeud->NbVarDeBaseComplementairesSansCoupes = 0; +Noeud->ComplementDeLaBaseSansCoupes = NULL; +Noeud->PositionDeLaVariableSansCoupes = NULL; +if ( NoeudAntecedent == 0 ) { + /* Cas du noeud racine, il faut quand-meme allouer la memoire pour ces tables */ + Noeud->TailleComplementDeBase = Bb->NombreDeContraintesDuProbleme; + Noeud->ComplementDeLaBase = (int *) malloc( Noeud->TailleComplementDeBase * sizeof(int) ); + Noeud->ComplementDeLaBaseSansCoupes = (int *) malloc( Noeud->TailleComplementDeBase * sizeof(int) ); + Noeud->PositionDeLaVariableSansCoupes = (int *) malloc( Bb->NombreDeVariablesDuProbleme * sizeof(int) ); + if ( Noeud->ComplementDeLaBase == NULL || Noeud->ComplementDeLaBaseSansCoupes == NULL || + Noeud->PositionDeLaVariableSansCoupes == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_AllouerUnNoeud \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } +} + +Noeud->CoupesGenereesAuNoeud = 0 ; +Noeud->NombreDeCoupesGenereesAuNoeud = 0; +Noeud->NombreDeG = 0; +Noeud->NombreDeK = 0; +Noeud->NombreDeI = 0; + +Noeud->NombreDeCoupesExaminees = 0; +Noeud->NumeroDesCoupesExaminees = NULL; +Noeud->LaCoupeEstSaturee = NULL; + +Noeud->NombreDeCoupesViolees = 0; +Noeud->NumeroDesCoupesViolees = NULL; + +Noeud->NumeroDesCoupeAjouteeAuProblemeCourant = NULL; + +Noeud->MinorantDuCritereAuNoeud = PLUS_LINFINI; +Noeud->MinorantPredit = MinorantPredit; +Noeud->LaSolutionRelaxeeEstEntiere = NON; + +Noeud->NoeudAntecedent = NoeudAntecedent; + +Noeud->NoeudSuivantGauche = 0; +Noeud->NoeudSuivantDroit = 0; + +Noeud->NbVarDeBaseComplementaires = 0; + +Noeud->BaseSimplexeDuNoeud = NULL; + +/* Initialisation des tables des bornes au noeud */ + +if( NoeudAntecedent == 0 ) { + Noeud->NombreDeBornesModifiees = 0; + Noeud->NumeroDeLaVariableModifiee = NULL; + Noeud->TypeDeBorneModifiee = NULL; + Noeud->NouvelleValeurDeBorne = NULL; +} +else { + i = NoeudAntecedent->NombreDeBornesModifiees; + Noeud->NombreDeBornesModifiees = i; + Noeud->NumeroDeLaVariableModifiee = NULL; + Noeud->TypeDeBorneModifiee = NULL; + Noeud->NouvelleValeurDeBorne = NULL; + if ( i > 0 ) { + Noeud->NumeroDeLaVariableModifiee = (int *) malloc( i * sizeof( int ) ); + Noeud->TypeDeBorneModifiee = (char *) malloc( i * sizeof( char ) ); + Noeud->NouvelleValeurDeBorne = (double *) malloc( i * sizeof( double ) ); + if ( Noeud->NumeroDeLaVariableModifiee == NULL || Noeud->TypeDeBorneModifiee == NULL || Noeud->NouvelleValeurDeBorne == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_AllouerUnNoeud \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + memcpy( (char *) Noeud->NumeroDeLaVariableModifiee, (char *) NoeudAntecedent->NumeroDeLaVariableModifiee, i * sizeof( int ) ); + memcpy( (char *) Noeud->TypeDeBorneModifiee, (char *) NoeudAntecedent->TypeDeBorneModifiee, i * sizeof( char ) ); + memcpy( (char *) Noeud->NouvelleValeurDeBorne, (char *) NoeudAntecedent->NouvelleValeurDeBorne, i * sizeof( double ) ); + } +} + +if( NoeudAntecedent == 0 ) { + /* Car c'est le noeud racine */ + return( Noeud ); +} + +/* Recopie de la liste des variables fixees du pere et incrementation avec les nouvelles variables */ + +memcpy( (char *) Noeud->ValeursDesVariablesEntieresInstanciees , (char *) NoeudAntecedent->ValeursDesVariablesEntieresInstanciees , + NoeudAntecedent->NombreDeVariablesEntieresInstanciees * sizeof( char ) ); + +memcpy( (char *) Noeud->IndicesDesVariablesEntieresInstanciees , (char *) NoeudAntecedent->IndicesDesVariablesEntieresInstanciees , + NoeudAntecedent->NombreDeVariablesEntieresInstanciees * sizeof( int ) ); + +Noeud->NombreDeVariablesEntieresInstanciees = NoeudAntecedent->NombreDeVariablesEntieresInstanciees; + +if( ValeurDInstanciation == 0 ) { + for ( i = 0 ; i < NombreDeVariablesAInstancier ; i++ ) { + Var = NumerosDesVariablesAInstancier[i]; + Noeud->ValeursDesVariablesEntieresInstanciees[ Noeud->NombreDeVariablesEntieresInstanciees ] = '0'; + Noeud->IndicesDesVariablesEntieresInstanciees[ Noeud->NombreDeVariablesEntieresInstanciees ] = Var; + Noeud->NombreDeVariablesEntieresInstanciees++; + } +} +else { + for ( i = 0 ; i < NombreDeVariablesAInstancier ; i++ ) { + Var = NumerosDesVariablesAInstancier[i]; + Noeud->ValeursDesVariablesEntieresInstanciees[ Noeud->NombreDeVariablesEntieresInstanciees ] = '1'; + Noeud->IndicesDesVariablesEntieresInstanciees[ Noeud->NombreDeVariablesEntieresInstanciees ] = Var; + Noeud->NombreDeVariablesEntieresInstanciees++; + } +} + +if ( FilsACreer == FILS_GAUCHE ) NoeudAntecedent->NoeudSuivantGauche = Noeud; +else if ( FilsACreer == FILS_DROIT ) NoeudAntecedent->NoeudSuivantDroit = Noeud; +else { + printf("BB_AllouerUnNoeud: type de fils a creer inconnu %d\n",FilsACreer); + exit(0); +} + +/* Pour le simplexe */ + +Noeud->BaseFournie = OUI; +/* Meme s'il y a plusieurs variables instanciees on ne met que la premiere valeur car cela ne sert + qu'a differencier le noeud racine des autres au niveau de l'appel du simplexe */ +Noeud->IndiceDeLaNouvelleVariableInstanciee = NumerosDesVariablesAInstancier[0]; + +/* Recopie de la base du pere */ +Marge = (int)(0.1 * Bb->NombreDeContraintesDuProbleme); +if ( Marge <= 0 ) Marge = 10; + +Noeud->NombreDeCoupesExaminees = Bb->NombreDeCoupesAjoutees; +if ( Bb->NombreDeCoupesAjoutees > 0 ) { + Noeud->NumeroDesCoupesExaminees = (int *) malloc( Noeud->NombreDeCoupesExaminees * sizeof(int) ); + Noeud->LaCoupeEstSaturee = (char *) malloc( Noeud->NombreDeCoupesExaminees * sizeof(char) ); + if ( Noeud->NumeroDesCoupesExaminees == NULL || Noeud->LaCoupeEstSaturee == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_AllouerUnNoeud \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } +} + +if ( Bb->BasesFilsDisponibles == NON_PNE ) { + + memcpy( (char * ) Noeud->PositionDeLaVariable , (char * ) NoeudAntecedent->PositionDeLaVariable , + ( Bb->NombreDeVariablesDuProbleme /*+ Bb->NombreDeContraintesDuProbleme*/ ) * sizeof( int ) ); + + Noeud->TailleComplementDeBase = NoeudAntecedent->NbVarDeBaseComplementaires + Marge; + /* Il faut dimensionner aux nombre de contraintes car le simplexe peut y ajouter des valeurs dans la limite du nombre + de contraintes => Noeud->TailleComplementDeBase est inutile */ + + Noeud->ComplementDeLaBase = (int *) malloc( Bb->NombreDeContraintesDuProbleme /*Noeud->TailleComplementDeBase*/ * sizeof(int) ); + if ( Noeud->ComplementDeLaBase == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_AllouerUnNoeud \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + + Noeud->NbVarDeBaseComplementaires = NoeudAntecedent->NbVarDeBaseComplementaires; + memcpy( (char * ) Noeud->ComplementDeLaBase , (char * ) NoeudAntecedent->ComplementDeLaBase , NoeudAntecedent->NbVarDeBaseComplementaires * sizeof( int ) ); + + for ( i = 0 ; i < Bb->NombreDeCoupesAjoutees ; i++ ) { + Noeud->NumeroDesCoupesExaminees[i] = Bb->NoeudRacine->NumeroDesCoupeAjouteeAuProblemeCourant[i]; + Noeud->LaCoupeEstSaturee [i] = Bb->CoupeSaturee[i]; + } + +} +/* Preparation de la base de depart */ +if ( Bb->BasesFilsDisponibles == OUI_PNE ) { + + if ( ValeurDInstanciation == 0 ) { + + memcpy( (char * ) Noeud->PositionDeLaVariable , (char * ) Bb->PositionDeLaVariableAEntierInf , + ( Bb->NombreDeVariablesDuProbleme /*+ Bb->NombreDeContraintesDuProbleme*/ ) * sizeof( int ) ); + + Noeud->TailleComplementDeBase = Bb->NbVarDeBaseComplementairesAEntierInf + Marge; + /* Il faut dimensionner aux nombre de contraintes car le simplexe peut y ajouter des valeurs dans la limite du nombre + de contraintes => Noeud->TailleComplementDeBase est inutile */ + + Noeud->ComplementDeLaBase = (int *) malloc( Bb->NombreDeContraintesDuProbleme /*Noeud->TailleComplementDeBase*/ * sizeof(int) ); + if ( Noeud->ComplementDeLaBase == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_AllouerUnNoeud \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + + Noeud->NbVarDeBaseComplementaires = Bb->NbVarDeBaseComplementairesAEntierInf; + memcpy( (char * ) Noeud->ComplementDeLaBase , (char * ) Bb->ComplementDeLaBaseAEntierInf , + Noeud->NbVarDeBaseComplementaires * sizeof( int ) ); + + for ( i = 0 ; i < Bb->NombreDeCoupesAjoutees ; i++ ) { + Noeud->NumeroDesCoupesExaminees[i] = Bb->NoeudRacine->NumeroDesCoupeAjouteeAuProblemeCourant[i]; + Noeud->LaCoupeEstSaturee [i] = Bb->CoupeSatureeAEntierInf[i]; + } + + } + else { + + memcpy( (char * ) Noeud->PositionDeLaVariable , (char * ) Bb->PositionDeLaVariableAEntierSup , + ( Bb->NombreDeVariablesDuProbleme /*+ Bb->NombreDeContraintesDuProbleme*/ ) * sizeof( int ) ); + + Noeud->TailleComplementDeBase = Bb->NbVarDeBaseComplementairesAEntierSup + Marge; + /* Il faut dimensionner aux nombre de contraintes car le simplexe peut y ajouter des valeurs dans la limite du nombre + de contraintes => Noeud->TailleComplementDeBase est inutile */ + + Noeud->ComplementDeLaBase = (int *) malloc( Bb->NombreDeContraintesDuProbleme /*Noeud->TailleComplementDeBase*/ * sizeof(int) ); + if ( Noeud->ComplementDeLaBase == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_AllouerUnNoeud \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + + Noeud->NbVarDeBaseComplementaires = Bb->NbVarDeBaseComplementairesAEntierSup; + memcpy( (char * ) Noeud->ComplementDeLaBase , (char * ) Bb->ComplementDeLaBaseAEntierSup , + Noeud->NbVarDeBaseComplementaires * sizeof( int ) ); + + for ( i = 0 ; i < Bb->NombreDeCoupesAjoutees ; i++ ) { + Noeud->NumeroDesCoupesExaminees[i] = Bb->NoeudRacine->NumeroDesCoupeAjouteeAuProblemeCourant[i]; + Noeud->LaCoupeEstSaturee [i] = Bb->CoupeSatureeAEntierSup[i]; + } + + } + +} + +/* Si les fils ont été crées on peut désallouer certaintes parties de la structure du noeud pčre */ +if ( NoeudAntecedent->NoeudSuivantGauche != 0 && NoeudAntecedent->NoeudSuivantDroit != 0 ) { + if ( NoeudAntecedent != Bb->NoeudRacine ) { + /* On ne desalloue pas partiellement le noeud racine car on peut avoir besoin de sa base */ + BB_DesallocationPartielleDUnNoeud( NoeudAntecedent ); + } +} + +return( Noeud ); +} + +/*-----------------------------------------------------------------------------------------------*/ + +void BB_DesallouerUnNoeud( BB * Bb, NOEUD * Noeud ) +{ +int i; COUPE ** Coupe; + +if( Noeud == 0 ) return; + +/* +if( Noeud == Bb->NoeudRacine ) { printf(" Elimination du noeud racine \n"); } +*/ + +/* +if( Noeud == Bb->NoeudEnExamen ) { + #if VERBOSE_BB + printf(" Tentative elimination du noeud en examen qui est %x \n",Bb->NoeudEnExamen); + #endif + return; +} +*/ + +for ( i = 0 ; i < Bb->NbNoeuds1_PNE_BalayageEnProfondeur ; i++ ) { + if( Bb->Liste1_PNE_BalayageEnProfondeur[i] == Noeud ) { + Bb->Liste1_PNE_BalayageEnProfondeur[i] = 0; + break; + } +} + +for ( i = 0 ; i < Bb->NbNoeuds1_PNE_NettoyerLArbreDeLaRechercheEnProfondeur ; i++ ) { + if( Bb->Liste1_PNE_NettoyerLArbreDeLaRechercheEnProfondeur[i] == Noeud ) { + Bb->Liste1_PNE_NettoyerLArbreDeLaRechercheEnProfondeur[i] = 0; + break; + } +} + +for ( i = 0 ; i < Bb->NbNoeuds2_PNE_NettoyerLArbreDeLaRechercheEnProfondeur ; i++ ) { + if( Bb->Liste2_PNE_NettoyerLArbreDeLaRechercheEnProfondeur[i] == Noeud ) { + Bb->Liste2_PNE_NettoyerLArbreDeLaRechercheEnProfondeur[i] = 0; + break; + } +} + +for ( i = 0 ; i < Bb->NbNoeuds1_PNE_BalayageEnLargeur ; i++ ) { + if( Bb->Liste1_PNE_BalayageEnLargeur[i] == Noeud ) { + Bb->Liste1_PNE_BalayageEnLargeur[i] = 0; + break; + } +} + +for ( i = 0 ; i < Bb->NbNoeuds2_PNE_BalayageEnLargeur ; i++ ) { + if( Bb->Liste2_PNE_BalayageEnLargeur[i] == Noeud ) { + Bb->Liste2_PNE_BalayageEnLargeur[i] = 0; + break; + } +} + +for ( i = 0 ; i < Bb->NbNoeuds1_PNE_EliminerLesNoeudsSousOptimaux ; i++ ) { + if( Bb->Liste1_PNE_EliminerLesNoeudsSousOptimaux[i] == Noeud ) { + Bb->Liste1_PNE_EliminerLesNoeudsSousOptimaux[i] = 0; + break; + } +} + +for ( i = 0 ; i < Bb->NbNoeuds2_PNE_EliminerLesNoeudsSousOptimaux ; i++ ) { + if( Bb->Liste2_PNE_EliminerLesNoeudsSousOptimaux[i] == Noeud ) { + Bb->Liste2_PNE_EliminerLesNoeudsSousOptimaux[i] = 0; + break; + } +} + +for ( i = 0 ; i < Bb->NbNoeuds1_PNE_SupprimerTousLesDescendantsDUnNoeud ; i++ ) { + if( Bb->Liste1_PNE_SupprimerTousLesDescendantsDUnNoeud[i] == Noeud ) { + Bb->Liste1_PNE_SupprimerTousLesDescendantsDUnNoeud[i] = 0; + break; + } +} + +for ( i = 0 ; i < Bb->NbNoeuds2_PNE_SupprimerTousLesDescendantsDUnNoeud ; i++ ) { + if( Bb->Liste2_PNE_SupprimerTousLesDescendantsDUnNoeud[i] == Noeud ) { + Bb->Liste2_PNE_SupprimerTousLesDescendantsDUnNoeud[i] = 0; + break; + } +} + +BB_DesallocationPartielleDUnNoeud( Noeud ); + +/* Liberation des coupes */ + +if( Noeud->NombreDeCoupesGenereesAuNoeud > 0 ) { + Coupe = Noeud->CoupesGenereesAuNoeud; /* Pointeur sur le tableau de pointeurs sur les coupes */ + for ( i = 0 ; i < Noeud->NombreDeCoupesGenereesAuNoeud; i++ ) { + free( Coupe[i]->Coefficient ); + free( Coupe[i]->IndiceDeLaVariable ); + free( Coupe[i] ); + } +} + +free( Noeud->NumeroDesCoupeAjouteeAuProblemeCourant ); +free( Noeud->CoupesGenereesAuNoeud ); +free( Noeud->NumeroDesCoupesExaminees ); +free( Noeud->LaCoupeEstSaturee ); +free( Noeud->NumeroDesCoupesViolees ); + +free( Noeud ); + +return; +} + +/*-----------------------------------------------------------------------------------------------*/ + +void BB_DesallocationPartielleDUnNoeud( NOEUD * Noeud ) +{ + +free( Noeud->ValeursDesVariablesEntieresInstanciees ); +free( Noeud->IndicesDesVariablesEntieresInstanciees ); + +Noeud->ValeursDesVariablesEntieresInstanciees = NULL; +Noeud->IndicesDesVariablesEntieresInstanciees = NULL; + +free( Noeud->PositionDeLaVariable ); +free( Noeud->ComplementDeLaBase ); + +Noeud->PositionDeLaVariable = NULL; +Noeud->ComplementDeLaBase = NULL; + +free( Noeud->PositionDeLaVariableSansCoupes ); +free( Noeud->ComplementDeLaBaseSansCoupes ); + +Noeud->PositionDeLaVariableSansCoupes = NULL; +Noeud->ComplementDeLaBaseSansCoupes = NULL; + +free( Noeud->NumeroDeLaVariableModifiee ); +free( Noeud->TypeDeBorneModifiee ); +free( Noeud->NouvelleValeurDeBorne ); + +Noeud->NumeroDeLaVariableModifiee = NULL; +Noeud->TypeDeBorneModifiee = NULL; +Noeud->NouvelleValeurDeBorne = NULL; +Noeud->NombreDeBornesModifiees = 0; + +if ( Noeud->BaseSimplexeDuNoeud != NULL ) { + free( Noeud->BaseSimplexeDuNoeud->PositionDeLaVariable ); + free( Noeud->BaseSimplexeDuNoeud->InDualFramework ); + free( Noeud->BaseSimplexeDuNoeud->ContrainteDeLaVariableEnBase ); + free( Noeud->BaseSimplexeDuNoeud->DualPoids ); + free( Noeud->BaseSimplexeDuNoeud->VariableEnBaseDeLaContrainte ); + free( Noeud->BaseSimplexeDuNoeud ); + Noeud->BaseSimplexeDuNoeud = NULL; +} + +return; +} + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_creer_les_noeuds_fils.c b/src/ext/Sirius_Solver/branchAndBound/bb_creer_les_noeuds_fils.c new file mode 100644 index 0000000000..955e02ee68 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_creer_les_noeuds_fils.c @@ -0,0 +1,110 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Creation des noeuds fis apres evaluation du pere + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" +#include "pne_fonctions.h" + +/*-----------------------------------------------------------------------------------------------*/ + +void BB_CreerLesNoeudsFils( BB * Bb, NOEUD * NoeudCourant ) +{ +NOEUD * Noeud; int CodeRetour ; int FilsACreer; +int ValeurDInstanciationAGauche; int NombreDeVariablesAInstancierAGauche; +int * NumerosDesVariablesAInstancierAGauche; +int ValeurDInstanciationADroite; int NombreDeVariablesAInstancierADroite; +int * NumerosDesVariablesAInstancierADroite; +#if VERBOSE_BB + int i; +#endif + +CodeRetour = BB_ChoixDesVariablesAInstancier( Bb, + NoeudCourant, + &ValeurDInstanciationAGauche, + &NombreDeVariablesAInstancierAGauche, + &NumerosDesVariablesAInstancierAGauche, + &ValeurDInstanciationADroite, + &NombreDeVariablesAInstancierADroite, + &NumerosDesVariablesAInstancierADroite ); + +if ( CodeRetour == PAS_DE_VARIABLES_A_INSTANCIER ) { + BB_DesallocationPartielleDUnNoeud( NoeudCourant ); + return; +} + +#if VERBOSE_BB + printf("Valeur d'instanciation a gauche -> %d\n",ValeurDInstanciationAGauche); + printf("Instanciation a gauche de la variable ->"); + for ( i = 0 ; i < NombreDeVariablesAInstancierAGauche ; i++ ) { + printf(" %d ",NumerosDesVariablesAInstancierAGauche[i]); + } + printf("\n"); + printf("Valeur d'instanciation a droite -> %d\n",ValeurDInstanciationADroite); + printf("Instanciation a droite de la variable ->",NumerosDesVariablesAInstancierADroite[i]); + for ( i = 0 ; i < NombreDeVariablesAInstancierADroite ; i++ ) { + printf(" %d ",NumerosDesVariablesAInstancierADroite[i]); + } + printf("\n"); +#endif + +/* Si le noeud courant a deja son fils NoeudSuivantGauche, on le cree pas */ +Noeud = NoeudCourant->NoeudSuivantGauche; +if ( Noeud == 0 ) { + /* Noeud gauche */ + FilsACreer = FILS_GAUCHE; + Noeud = BB_AllouerUnNoeud( Bb, + NoeudCourant, + NoeudCourant->ProfondeurDuNoeud + 1, + FilsACreer, + ValeurDInstanciationAGauche, + NombreDeVariablesAInstancierAGauche, + NumerosDesVariablesAInstancierAGauche, + Bb->MinorantEspereAEntierInf ); + NoeudCourant->NoeudSuivantGauche = Noeud; +} + +/* Si le noeud courant a deja son fils NoeudSuivantDroit, on le cree pas */ +Noeud = NoeudCourant->NoeudSuivantDroit; +if ( Noeud == 0 ) { + /* Noeud droit */ + FilsACreer = FILS_DROIT; + Noeud = BB_AllouerUnNoeud( Bb, + NoeudCourant, + NoeudCourant->ProfondeurDuNoeud + 1, + FilsACreer, + ValeurDInstanciationADroite, + NombreDeVariablesAInstancierADroite, + NumerosDesVariablesAInstancierADroite, + Bb->MinorantEspereAEntierSup ); + NoeudCourant->NoeudSuivantDroit = Noeud; +} + +return; +} + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_define.h b/src/ext/Sirius_Solver/branchAndBound/bb_define.h new file mode 100644 index 0000000000..bd3040e76b --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_define.h @@ -0,0 +1,346 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef DEFINITIONS_BB_FAITES +/*******************************************************************************************/ + +# include "bb_sys.h" + +#define VERBOSE_BB 0 + +# define BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # undef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + +#define PLUS_LINFINI 1.0e+80 + +#define OUI 1 +#define NON 0 + +#define FILS_GAUCHE 0 +#define FILS_DROIT 1 + +#define BORNE_SUP 1 +#define BORNE_INF 2 + +#define ARRET_CAR_TEMPS_MAXIMUM_ATTEINT 2 +#define BB_ERREUR_INTERNE 3 + +#define A_EVALUER 1 +#define EVALUE 2 /* Le noeud a ete evalue */ +#define A_REJETER 3 /* Le noeud a ete evalue mais il n'y a pas de solution au probleme relaxe ou bien */ + /* le noeud a ete evalue mais lui-meme et son sous-arbre sont sous-optimaux car le */ + /* cout de la solution du probleme relaxe est superieur au cout de la meilleure */ + /* solution trouvee */ + +#define PAS_DE_VARIABLES_A_INSTANCIER -1 +#define VARIABLES_A_INSTANCIER 1 + +#define RECHERCHER_LE_PLUS_PETIT 2 +#define RECHERCHER_LE_PLUS_PETIT_GAP_PROPORTIONNEL 3 + +#define PROFONDEUR_PURE 1 +#define MOINS_DE_VALEURS_FRACTIONNAIRES 2 +#define NORME_FRACTIONNAIRE_MINIMALE 3 + +#define NOMBRE_DEVALUATIONS_DU_MEILLEUR_MINORANT 10 /*5*/ + +#define TOLERANCE_OPTIMALITE 0.0000001 /*0.0001*/ /* Pour supprimer une branche il faut que le cout de la solution soit superieur + au cout de la meilleure solution + une petite marge pour tenir compte du fait + que l'optimum est toujours entache d'un petite erreur quand-meme */ + +#define PROFONDEUR_TOUT_SEUL 1 +#define LARGEUR_TOUT_SEUL 2 +#define PROFONDEUR_DANS_LARGEUR 3 + +#define COEFFICIENT_POUR_LE_CALCUL_DE_LA_PROFONDEUR_LIMITE 0.20 /*0.05*/ +#define PROFONDEUR_MIN_PENDANT_LA_RECHERCHE_EN_LARGEUR 10 /*10*/ +#define PROFONDEUR_MAX_PENDANT_LA_RECHERCHE_EN_LARGEUR 100 /* Pas de limite 1000000 */ +#define NOMBRE_MIN_DE_PROBLEMES_PROFONDEUR_DANS_LARGEUR 15 + +#define CYCLE_POUR_RECHERCHE_EN_PROFONDEUR 2/*5*/ /* Dans une recherche en largeur, a chaque fois qu'on a evalue ce + nombre de problemes, on part dans une recherche en profondeur */ + +#define MAX_COUPES_PAR_PROBLEME_RELAXE 0.5 /*0.2*/ /*0.5*/ /* Coefficient a appliquer sur le nombre de contraintes du probleme + pour calculer le nombre max. de coupes que l'on s'autorise a + ajouter dans un probleme relaxe */ +#define NOMBRE_MAX_DE_COUPES 10000 /*5000*/ +#define NOMBRE_MOYEN_MINIMUM_DE_COUPES_UTILES 5 + +#define TAILLE_MAXI_DU_POOL_DE_COUPES 500000000 /* En octets */ + +#define CYCLE_DINFORMATIONS 10 /* toutes les 10 secondes */ +#define CYCLE_DINFORMATIONS_EN_NOMBRE_DE_PROBLEMES 100 +#define CYCLE_DAFFICHAGE_LEGENDE 15 + +#define NON_INITIALISE 1000000 + +/* Donnees simplexe pour l'exploration rapide en profondeur */ +typedef struct{ +char * PositionDeLaVariable; +char * InDualFramework; +int * ContrainteDeLaVariableEnBase; +double * DualPoids; +int * VariableEnBaseDeLaContrainte; +} BASE_SIMPLEXE; + +typedef struct{ +/* Attention: toutes les coupes sont de type "inferieur ou egal" */ +char UtiliserLaCoupe ; /* Information variable qui vaut OUI ou NON selon l'arborscence du noeud en + lequel on veut ajouter une coupe */ +char CoupeRencontreeDansLArborescence; /* Information variable qui vaut OUI ou NON selon l'arborscence du noeud en + lequel on veut ajouter une coupe */ +char CoupeExamineeAuNoeudCourant; +char CoupeSaturee ; /* Information variable qui vaut OUI_PNE ou NON_PNE selon l'arborscence du noeud en + lequel on veut ajouter une coupe */ +/*int VariableCause ;*/ /* Numero de la variable pour laquelle on fait la coupe ( < 0 si c'est pour + pour une autre raison */ +char TypeDeCoupe ; /* Type de coupe: + G si coupe de Gomory + K si sac a dos ( Knapsack ) + I si coupe d intersection + L si lift and project + I si implication suite au "probing" de certains variables */ +char CoupeRacine ; /* Vaut OUI si la coupe a ete generee au noeud racine */ +int NombreDeTermes ; /* Nombre de coefficients non nuls dans la coupe */ +double * Coefficient ; /* Coefficient de la contrainte */ +int * IndiceDeLaVariable ; /* Indices des variables qui interviennent dans la coupe */ +double SecondMembre ; /* La coupe est toujours dans le sens <= SecondMembre */ +} COUPE; + +typedef struct{ +/* */ +int ProfondeurDuNoeud; /* Le noeud racine a la profondeur 0 */ +int StatutDuNoeud ; /* A_EVALUER EVALUE A_REJETER */ +int NoeudTerminal ; /* OUI ou NON */ +/* */ +int NombreDeVariablesEntieresInstanciees ; +char * ValeursDesVariablesEntieresInstanciees; /* vaut '0' ou '1' */ +int * IndicesDesVariablesEntieresInstanciees; +/* */ +double MinorantPredit; +/* */ +double MinorantDuCritereAuNoeud ; +int LaSolutionRelaxeeEstEntiere; +int NbValeursFractionnairesApresResolution; +double NormeDeFractionnalite; +/* */ +COUPE ** CoupesGenereesAuNoeud ; /* Tableau de points sur les coupes generees au noeud */ +int NombreDeCoupesGenereesAuNoeud; +int NombreDeG; +int NombreDeI; +int NombreDeK; +/* */ +int * NumeroDesCoupeAjouteeAuProblemeCourant; +/* */ +int NombreDeCoupesExaminees; +int * NumeroDesCoupesExaminees; +char * LaCoupeEstSaturee; /* C'est un resultat de la resolution du probleme relaxe */ +/* */ +int NombreDeCoupesViolees ; /* Elles n'etaient donc pas incluses dans le probleme */ +int * NumeroDesCoupesViolees; +/* */ +void * NoeudAntecedent; /* Adresse de la structure du noeud antecedent: inutilise si noeud racine */ +void * NoeudSuivantGauche; +void * NoeudSuivantDroit; +/* */ +int BaseFournie; +int IndiceDeLaNouvelleVariableInstanciee; +int * PositionDeLaVariable; +int TailleComplementDeBase; +int NbVarDeBaseComplementaires; +int * ComplementDeLaBase; +/* Pour pouvoir disposer d'une base de depart sans coupe dans le cas du nettoyage des + coupes (valable uniquement pour le noeud racine */ +int * PositionDeLaVariableSansCoupes; +int NbVarDeBaseComplementairesSansCoupes; +int * ComplementDeLaBaseSansCoupes; +/* Pour le reduced cost fixing */ +int NombreDeBornesModifiees; +int * NumeroDeLaVariableModifiee; +char * TypeDeBorneModifiee; +double * NouvelleValeurDeBorne; +/* */ +/* Pour l'exploration rapide en profondeur dans le simplexe */ +BASE_SIMPLEXE * BaseSimplexeDuNoeud; +/* */ +} NOEUD; + +typedef struct{ +/* Pour les outils de gestion memoire */ +void * Tas; + +NOEUD * NoeudRacine; +char BaseDisponibleAuNoeudRacine; + +double * ValeursOptimalesDesVariables; +double * ValeursOptimalesDesVariablesEntieres; +double CoutDeLaMeilleureSolutionEntiere; +NOEUD * NoeudDeLaMeilleureSolutionEntiere; +int ProfondeurMoyenneDesSolutionsEntieres; +int UtiliserCoutDeLaMeilleureSolutionEntiere; +int ProfondeurMaxiSiPlongeePendantUneRechercheEnLargeur; + +double ValeurDuMeilleurMinorant; +double ValeurDuMeilleurPremierMinorant; +double ValeurDuMeilleurDernierMinorant; +int NombreDEvaluationDuMeilleurMinorant; +NOEUD * NoeudDuMeilleurMinorant; + +double * ValeursCalculeesDesVariablesPourLeProblemeRelaxeCourant; +double * ValeursCalculeesDesVariablesEntieresPourLeProblemeRelaxeCourant; + +/* */ + +int * NumerosDesVariablesEntieresDuProbleme; +int NombreDeVariablesEntieresDuProbleme; +int NombreDeVariablesDuProbleme; +int NombreDeContraintesDuProbleme; + +char ArreterLesCalculs; +int TempsDexecutionMaximum; +char ForcerAffichage; +char AffichageDesTraces; +int NombreMaxDeSolutionsEntieres; +double ToleranceDOptimalite; + +char EnleverToutesLesCoupesDuPool; +char SolutionEntiereTrouveeParHeuristique; + +NOEUD * NoeudEnExamen; + +int NombreDeProblemesRelaxesResolus; +int NombreDeProblemesResolus; +int NombreDeProblemesResolusDepuisLaRAZDesCoupes; +int NombreDeSolutionsEntieresTrouvees; +int NbProbPourLaPremiereSolutionEntiere; /* Nombre de problemes resolus pour trouver la + premiere solution entiere */ +int NombreTotalDeCoupesDuPoolUtilisees; +int NombreTotalDeGDuPoolUtilisees; +int NombreTotalDeIDuPoolUtilisees; +int NombreTotalDeKDuPoolUtilisees; + +/* Variable a instancier suite a la resolution d'un probleme relaxe */ +int VariableProposeePourLInstanciation; +double MinorantEspereAEntierInf; +double MinorantEspereAEntierSup; + +int * PositionDeLaVariableAEntierInf; +int NbVarDeBaseComplementairesAEntierInf; +int * ComplementDeLaBaseAEntierInf; +int * PositionDeLaVariableAEntierSup; +int NbVarDeBaseComplementairesAEntierSup; +int * ComplementDeLaBaseAEntierSup; +int BasesFilsDisponibles; + +/* Etat de saturation des coupes */ +int NombreDeCoupesAjoutees; +char * CoupeSaturee; +char * CoupeSatureeAEntierInf; +char * CoupeSatureeAEntierSup; + +int NombreMaxDeCoupesParProblemeRelaxe; + +/* Indicateur solution ameliorante trouvee ou non (utilise pendant le balayage + en largeur) */ +int SolutionAmelioranteTrouvee; +int NumeroDeProblemeDeLaSolutionAmeliorante; + +/* Listes de noeuds a explorer */ +int NbNoeuds1_PNE_BalayageEnProfondeur; +NOEUD ** Liste1_PNE_BalayageEnProfondeur; + +int NbNoeuds1_PNE_NettoyerLArbreDeLaRechercheEnProfondeur; +NOEUD ** Liste1_PNE_NettoyerLArbreDeLaRechercheEnProfondeur; +int NbNoeuds2_PNE_NettoyerLArbreDeLaRechercheEnProfondeur; +NOEUD ** Liste2_PNE_NettoyerLArbreDeLaRechercheEnProfondeur; + +int NbNoeuds1_PNE_BalayageEnLargeur; +NOEUD ** Liste1_PNE_BalayageEnLargeur; +int NbNoeuds2_PNE_BalayageEnLargeur; +NOEUD ** Liste2_PNE_BalayageEnLargeur; + +int NbNoeuds1_PNE_EliminerLesNoeudsSousOptimaux; +NOEUD ** Liste1_PNE_EliminerLesNoeudsSousOptimaux; +int NbNoeuds2_PNE_EliminerLesNoeudsSousOptimaux; +NOEUD ** Liste2_PNE_EliminerLesNoeudsSousOptimaux; + +int NbNoeuds1_PNE_SupprimerTousLesDescendantsDUnNoeud; +NOEUD ** Liste1_PNE_SupprimerTousLesDescendantsDUnNoeud; +int NbNoeuds2_PNE_SupprimerTousLesDescendantsDUnNoeud; +NOEUD ** Liste2_PNE_SupprimerTousLesDescendantsDUnNoeud; + +NOEUD * DernierNoeudResolu; + +char ComplementDeBaseModifie; +int MajorantDuNombreDeCoupesAjouteesApresResolutionDuProblemeRelaxe; +char CalculerDesCoupesDeGomory; +char CalculerDesCoupes; +char ControlerLesCoupesNonInclusesPourUnNouvelleResolution; + +char TypeDExplorationEnCours; /* Valeurs possible: + PROFONDEUR_TOUT_SEUL + LARGEUR_TOUT_SEUL + PROFONDEUR_DANS_LARGEUR */ +char EvaluerLesFilsDuMeilleurMinorant; +double EcartBorneInf; + +int AnomalieDetectee; +jmp_buf EnvBB; + +char SortieParDepassementDuCoutMax; +int TailleTableau; +/* Un noeud est ferme lorsque ses 2 fils ont ete evalues ou bien lorsqu'il est terminal */ +int NbNoeudsOuverts; + +/* Infos pour les affichages */ +int TempsDuDernierAffichage; +int NombreDeProblemesDepuisLeDernierAffichage; +int NombreDAffichages; + +char NbMaxDeCoupesCalculeesAtteint; +int NombreDeNoeudsEvaluesSansCalculdeCoupes; +double EcartBorneInfALArretDesCoupes; +int NombreMaxDeCoupes; +int NombreMoyenMinimumDeCoupesUtiles; + +/* Pour calculer la profondeur moyenne d'elagage (pruning) */ +int NombreDeNoeudsElagues; +int AveragePruningDepth; +int SommeDesProfondeursDesSolutionsAmeliorantes; +int NombreDeSolutionsAmeliorantes; +int SommeDesProfondeursDElaguage; +int NombreDeSimplexes; +int SommeDuNombreDIterations; + +int AverageG; +int AverageI; +int AverageK; + +/* */ +void * ProblemePneDuBb; + +} BB; + +/*******************************************************************************************/ +# define DEFINITIONS_BB_FAITES +# endif +# ifdef __cplusplus + } +# endif diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_eliminer_les_noeuds_sous_optimaux.c b/src/ext/Sirius_Solver/branchAndBound/bb_eliminer_les_noeuds_sous_optimaux.c new file mode 100644 index 0000000000..8f983ed6fb --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_eliminer_les_noeuds_sous_optimaux.c @@ -0,0 +1,166 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*---------------------------------------------------------------------------------------------------------*/ +/* +Appele a chaque fois qu'on trouve une solution entiere ameliorante. +On compare son cout aux minorants relaxes, on marque les noeuds sous optimaux, on supprime les branches +sous optimales. +*/ + +void BB_EliminerLesNoeudsSousOptimaux( BB * Bb ) +{ +NOEUD ** NoeudsAExplorer; NOEUD ** NoeudsAExplorerAuProchainEtage; NOEUD * Noeud; NOEUD * NoeudCourant; +int NombreDeNoeudsAExplorer; int NombreDeNoeudsAExplorerAuProchainEtage; int ProfondeurRelative; +int AnalyserEnDessousDuNoeud; int i; double Seuil; double Seuil_1; double Marge; +/* +printf("\n Eliminer le noeuds sous optimaux "); +*/ +/* Le noeud de depart est le noeud racine, on balaye l'arborescence en largeur */ + +Seuil = fabs( Bb->CoutDeLaMeilleureSolutionEntiere * TOLERANCE_OPTIMALITE ); +if( Seuil > 0.001 ) Seuil = 0.001; +if( Seuil < 0.00001 ) Seuil = 0.00001; + +Seuil = -1.e-10; /* Sinon on risque de conserver des branches avec des solutions equivalentes en pagaille */ +Seuil = -1.e-9; +Seuil += Bb->CoutDeLaMeilleureSolutionEntiere; + +ProfondeurRelative = 0; +NoeudsAExplorer = (NOEUD **) malloc( 1 * sizeof( void * ) ); +if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_EliminerLesNoeudsSousOptimaux 1 \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} +NombreDeNoeudsAExplorer = 1; +NoeudsAExplorer[0] = Bb->NoeudRacine; + +Bb->NbNoeuds1_PNE_EliminerLesNoeudsSousOptimaux = NombreDeNoeudsAExplorer; /* Pour le nettoyage eventuel */ +Bb->Liste1_PNE_EliminerLesNoeudsSousOptimaux = NoeudsAExplorer; /* Pour le nettoyage eventuel */ + +while( 1 ) { + ProfondeurRelative++; + NoeudsAExplorerAuProchainEtage = (NOEUD **) malloc( NombreDeNoeudsAExplorer * 2 * sizeof( void * ) ); + if ( NoeudsAExplorerAuProchainEtage == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_EliminerLesNoeudsSousOptimaux 2 \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + + Bb->NbNoeuds2_PNE_EliminerLesNoeudsSousOptimaux = 0; /* Pour le nettoyage eventuel */ + Bb->Liste2_PNE_EliminerLesNoeudsSousOptimaux = NoeudsAExplorerAuProchainEtage; /* Pour le nettoyage eventuel */ + + NombreDeNoeudsAExplorerAuProchainEtage = 0; + + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + + NoeudCourant = NoeudsAExplorer[i]; + if ( NoeudCourant != 0 ) { + AnalyserEnDessousDuNoeud = OUI; + if( NoeudCourant->StatutDuNoeud == EVALUE ) { + + Marge = Bb->ToleranceDOptimalite * 0.01 * fabs( NoeudCourant->MinorantDuCritereAuNoeud ); + Seuil_1 = Bb->CoutDeLaMeilleureSolutionEntiere - Marge; + if ( Seuil_1 > Seuil ) Seuil_1 = Seuil; + + if( NoeudCourant->MinorantDuCritereAuNoeud >= Seuil_1 /*Seuil*/ ) { + /* On marque le noeud comme etant A_REJETER, mais on le garde pour etre certain de ne + plus jamais lui creer de fils. Par contre on elimine physiquement tous ses fils */ + /* + printf("\n Suppression des descendants du noeud %x car son cout est %lf et le meilleur cout est %lf ", + NoeudCourant , NoeudCourant->MinorantDuCritereAuNoeud , Bb->CoutDeLaMeilleureSolutionEntiere); + */ + Bb->NombreDeNoeudsElagues++; + Bb->SommeDesProfondeursDElaguage += NoeudCourant->ProfondeurDuNoeud; + AnalyserEnDessousDuNoeud = NON; + BB_SupprimerTousLesDescendantsDUnNoeud( Bb, NoeudCourant ); + NoeudCourant->StatutDuNoeud = A_REJETER; /* Le noeud courant n'aura plus de fils et est sous-optimal */ + } + } + } + if( AnalyserEnDessousDuNoeud == OUI ) { + /* Renseigner la table des noeuds du prochain etage */ + if ( NoeudCourant != 0 ) { + Noeud = NoeudCourant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + if( Noeud->StatutDuNoeud == EVALUE ) { + Bb->NbNoeuds2_PNE_EliminerLesNoeudsSousOptimaux++; /* Pour le nettoyage eventuel */ + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + } + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + if( Noeud->StatutDuNoeud == EVALUE ) { + Bb->NbNoeuds2_PNE_EliminerLesNoeudsSousOptimaux++; /* Pour le nettoyage eventuel */ + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + } + } + } + } + /* fin for */ + } + /* Preparations pour l'etage suivant */ + if( NombreDeNoeudsAExplorerAuProchainEtage == 0 ) break; /* Exploration de l'arbre terminee */ + free( NoeudsAExplorer ); + NoeudsAExplorer = (NOEUD **) malloc( NombreDeNoeudsAExplorerAuProchainEtage * sizeof( void * ) ); + if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_EliminerLesNoeudsSousOptimaux 3 \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorer = NombreDeNoeudsAExplorerAuProchainEtage; + + Bb->NbNoeuds1_PNE_EliminerLesNoeudsSousOptimaux = NombreDeNoeudsAExplorer; /* Pour le nettoyage eventuel */ + Bb->Liste1_PNE_EliminerLesNoeudsSousOptimaux = NoeudsAExplorer; /* Pour le nettoyage eventuel */ + + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudsAExplorer[i] = NoeudsAExplorerAuProchainEtage[i]; + } + free( NoeudsAExplorerAuProchainEtage ); +/* fin while */ +} + +free( NoeudsAExplorer ); +free( NoeudsAExplorerAuProchainEtage ); + +Bb->NbNoeuds1_PNE_EliminerLesNoeudsSousOptimaux = 0; /* Pour le nettoyage eventuel */ +Bb->NbNoeuds2_PNE_EliminerLesNoeudsSousOptimaux = 0; /* Pour le nettoyage eventuel */ + +return; + +} + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_evaluer_en_profondeur_critiques.c b/src/ext/Sirius_Solver/branchAndBound/bb_evaluer_en_profondeur_critiques.c new file mode 100644 index 0000000000..f78bfd50eb --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_evaluer_en_profondeur_critiques.c @@ -0,0 +1,147 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/************************************************************************* + + FONCTION: Si l'on dispose d'une solution entiere on evalue en profondeur + les noeuds peu prometteurs afin de fermer des arborescences + + AUTEUR: R. GONZALEZ + +**************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +# define SEUIL_DEVALUATION 0.95 + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_EvaluerEnProfondeurLesNoeudsCritiques( BB * Bb ) +{ +NOEUD ** NoeudsAExplorer ; NOEUD ** NoeudsAExplorerAuProchainEtage ; +NOEUD * Noeud ; NOEUD * NoeudCourant ; +int NombreDeNoeudsAExplorer ; int NombreDeNoeudsAExplorerAuProchainEtage; +int i ; double SeuilPourLEvaluation; + +SeuilPourLEvaluation = SEUIL_DEVALUATION * Bb->CoutDeLaMeilleureSolutionEntiere; + +NoeudsAExplorer = (NOEUD **) malloc( 1 * sizeof( void * ) ); +if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_RechercherUnNouveauNoeudDeDepart \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} +NombreDeNoeudsAExplorer = 1; +NoeudsAExplorer[0] = Bb->NoeudRacine; + +while( 1 ) { + NoeudsAExplorerAuProchainEtage = (NOEUD **) malloc( NombreDeNoeudsAExplorer * 2 * sizeof( void * ) ); + if ( NoeudsAExplorerAuProchainEtage == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_EliminerLesNoeudsSousOptimaux 2 \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorerAuProchainEtage = 0; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudCourant = NoeudsAExplorer[i]; + if ( NoeudCourant != 0 ) { + if ( NoeudCourant->StatutDuNoeud == EVALUE && NoeudCourant->NoeudTerminal != OUI ) { + /* Doit avoir au moins 1 fils a evaluer */ + Noeud = NoeudCourant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud == A_EVALUER ) { + if ( NoeudCourant->MinorantDuCritereAuNoeud > SeuilPourLEvaluation ) { + Bb->NoeudEnExamen = NoeudCourant; + # if VERBOSE_BB == 1 + printf("Evaluation en profondeur a partir de %X\n", Bb->NoeudEnExamen); + # endif + BB_BalayageEnProfondeur( Bb, Bb->NoeudEnExamen, Bb->NoeudEnExamen->ProfondeurDuNoeud ); + # if VERBOSE_BB == 1 + printf("Fin Evaluation en profondeur\n"); + # endif + goto Next; + } + } + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud == A_EVALUER ) { + if ( NoeudCourant->MinorantDuCritereAuNoeud > SeuilPourLEvaluation ) { + Bb->NoeudEnExamen = NoeudCourant; + # if VERBOSE_BB == 1 + printf("Evaluation en profondeur a partir de %X\n", Bb->NoeudEnExamen); + # endif + BB_BalayageEnProfondeur( Bb, Bb->NoeudEnExamen, Bb->NoeudEnExamen->ProfondeurDuNoeud ); + # if VERBOSE_BB == 1 + printf("Fin Evaluation en profondeur\n"); + # endif + } + } + } + } + /* Renseigner la table des noeuds du prochain etage */ + Next: + Noeud = NoeudCourant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + } + } + } + /* Preparations pour l'etage suivant */ + if( NombreDeNoeudsAExplorerAuProchainEtage == 0 ) break; /* Exploration de l'arbre terminee */ + free( NoeudsAExplorer ); + NoeudsAExplorer = (NOEUD **) malloc( NombreDeNoeudsAExplorerAuProchainEtage * sizeof( void * ) ); + if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_EliminerLesNoeudsSousOptimaux 3 \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorer = NombreDeNoeudsAExplorerAuProchainEtage; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudsAExplorer[i] = NoeudsAExplorerAuProchainEtage[i]; + } + free( NoeudsAExplorerAuProchainEtage ); +/* fin while */ +} + +/*FinRechercheNoeudsActifs:*/ + +free( NoeudsAExplorer ); +free( NoeudsAExplorerAuProchainEtage ); + +return; + +} + + + + + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_evaluer_fils_du_meilleur_minorant.c b/src/ext/Sirius_Solver/branchAndBound/bb_evaluer_fils_du_meilleur_minorant.c new file mode 100644 index 0000000000..2a216a9d57 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_evaluer_fils_du_meilleur_minorant.c @@ -0,0 +1,85 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/************************************************************************* + + FONCTION: Evaluation des 2 fils du noeud comportant le meilleur + minorant + + AUTEUR: R. GONZALEZ + +**************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_EvaluerLesDeuxFilsDuMeilleurMinorant( BB * Bb, NOEUD * NoeudDuMeilleurMinorant ) +{ +int YaUneSolution; NOEUD * NoeudCourant; int SolutionEntiereTrouvee; + +#if VERBOSE_BB + printf("Minorant du meilleur noeud %12.8e\n",NoeudDuMeilleurMinorant->MinorantDuCritereAuNoeud); +#endif + +NoeudCourant = NoeudDuMeilleurMinorant->NoeudSuivantGauche; +if ( NoeudCourant != 0 ) { + if ( NoeudCourant->StatutDuNoeud == A_EVALUER && + NoeudCourant->NoeudTerminal != OUI && + NoeudCourant->StatutDuNoeud != A_REJETER ) { + + #if VERBOSE_BB + printf("Evaluation fils gauche du meilleur minorant\n"); + #endif + + Bb->NoeudEnExamen = NoeudCourant; + YaUneSolution = BB_ResoudreLeProblemeRelaxe( Bb, NoeudCourant , &SolutionEntiereTrouvee ); + + BB_NettoyerLArbre( Bb, &YaUneSolution , NoeudCourant ); /* Fait aussi la mise a jour du statut */ + + + BB_CreerLesNoeudsFils( Bb, NoeudCourant ); + + } +} + +NoeudCourant = NoeudDuMeilleurMinorant->NoeudSuivantDroit; +if ( NoeudCourant != 0 ) { + if ( NoeudCourant->StatutDuNoeud == A_EVALUER && + NoeudCourant->NoeudTerminal != OUI && + NoeudCourant->StatutDuNoeud != A_REJETER ) { + + #if VERBOSE_BB + printf("Evaluation fils droit du meilleur minorant\n"); + #endif + + Bb->NoeudEnExamen = NoeudCourant; + YaUneSolution = BB_ResoudreLeProblemeRelaxe( Bb, NoeudCourant , &SolutionEntiereTrouvee ); + + BB_NettoyerLArbre( Bb, &YaUneSolution , NoeudCourant ); /* Fait aussi la mise a jour du statut */ + + BB_CreerLesNoeudsFils( Bb, NoeudCourant ); + + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_exploration_rapide_en_profondeur.c b/src/ext/Sirius_Solver/branchAndBound/bb_exploration_rapide_en_profondeur.c new file mode 100644 index 0000000000..1e01f0d3af --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_exploration_rapide_en_profondeur.c @@ -0,0 +1,413 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Exploration rapide en profondeur on attaquent directement + le simplexe et sans calculer de coupes. + Pour pour cela le noeud duquel on part doit etre evalue + de facon classique avant la plongee. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" +#include "pne_fonctions.h" + +#include "spx_define.h" +#include "spx_fonctions.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +void BB_RemettreLesDonneesAvantInstanciation( PROBLEME_SPX * , int * , NOEUD * ); +void BB_InstancierLaVariableDansLeSimplexe( PROBLEME_SPX * , int * , NOEUD * ); +NOEUD * BB_EvaluationRapideDUnNoeud( BB * , PROBLEME_SPX * , PROBLEME_PNE * , int * ); + +/*---------------------------------------------------------------------------------------------------------*/ +void BB_LibererLaBaseSimplexeDuNoeud( NOEUD * Noeud ) +{ +if ( Noeud->BaseSimplexeDuNoeud != NULL ) { + free( Noeud->BaseSimplexeDuNoeud->PositionDeLaVariable ); + free( Noeud->BaseSimplexeDuNoeud->InDualFramework ); + free( Noeud->BaseSimplexeDuNoeud->ContrainteDeLaVariableEnBase ); + free( Noeud->BaseSimplexeDuNoeud->DualPoids ); + free( Noeud->BaseSimplexeDuNoeud->VariableEnBaseDeLaContrainte ); + free( Noeud->BaseSimplexeDuNoeud ); + Noeud->BaseSimplexeDuNoeud = NULL; +} +return; +} +/*---------------------------------------------------------------------------------------------------------*/ +void BB_RemettreLesDonneesAvantInstanciation( PROBLEME_SPX * Spx, int * TypeInstanciation, + NOEUD * Noeud ) +{ +int VariablePneARemettre; + +VariablePneARemettre = Noeud->IndiceDeLaNouvelleVariableInstanciee; +Spx_RemettreLesDonneesAvantInstanciation( Spx , VariablePneARemettre , TypeInstanciation[VariablePneARemettre]); +TypeInstanciation[VariablePneARemettre] = SORT_PAS; + +return; +} +/*---------------------------------------------------------------------------------------------------------*/ +void BB_InstancierLaVariableDansLeSimplexe( PROBLEME_SPX * Spx, int * TypeInstanciation, + NOEUD * Noeud ) +{ +int VariablePneAInstancier; int i; + +VariablePneAInstancier = Noeud->IndiceDeLaNouvelleVariableInstanciee; +/* Determination du type de sortie */ +i = Noeud->NombreDeVariablesEntieresInstanciees - 1; +if ( Noeud->ValeursDesVariablesEntieresInstanciees[i] == '0' ) TypeInstanciation[VariablePneAInstancier] = SORT_SUR_XMIN; +else TypeInstanciation[VariablePneAInstancier] = SORT_SUR_XMAX; + +Spx_ModifierLesDonneesSurInstanciation( Spx , VariablePneAInstancier , TypeInstanciation[VariablePneAInstancier] ); + +return; +} +/*---------------------------------------------------------------------------------------------------------*/ + +NOEUD * BB_EvaluationRapideDUnNoeud( BB * Bb , PROBLEME_SPX * Spx , PROBLEME_PNE * Pne , int * TypeInstanciation ) +{ +NOEUD * NoeudEnExamen; int VariablePneAInstancier; int YaUneSolution; +NOEUD * NoeudSuivant; int SortSurXmaxOuSurXmin; + +NoeudSuivant = NULL; + +Bb->SolutionAmelioranteTrouvee = NON; +NoeudEnExamen = Bb->NoeudEnExamen; + +if ( NoeudEnExamen->StatutDuNoeud != A_EVALUER ) return( NoeudSuivant ); + +/* On instancie la variable */ +BB_InstancierLaVariableDansLeSimplexe( Spx, TypeInstanciation, NoeudEnExamen ); + +Spx->ExplorationRapideEnCours = OUI_SPX; +SPX_DualSimplexe( Spx ); +Spx->ExplorationRapideEnCours = NON_SPX; + +Bb->NombreDeProblemesResolus++; +Bb->NombreDeProblemesRelaxesResolus++; + +YaUneSolution = Spx->YaUneSolution; + +/* N'instancie pas de variable si pas de solution */ +SPX_ChoisirLaVariableAInstancier( Spx, (void *) Bb, &VariablePneAInstancier, &SortSurXmaxOuSurXmin ); + +if ( Spx->YaUneSolution == OUI_SPX ) { + if ( VariablePneAInstancier >= 0 ) { + /* Appelle aussi BB_NettoyerLArbre et fait les sauvegardes de la base de depart */ + Spx_CreationNoeudsFils( Spx, (void *) Pne, (void *) Bb, VariablePneAInstancier ); + + if ( SortSurXmaxOuSurXmin == SORT_SUR_XMAX ) NoeudSuivant = NoeudEnExamen->NoeudSuivantDroit; + else NoeudSuivant = NoeudEnExamen->NoeudSuivantGauche; + } + else { + /* La solution est entiere */ + printf("Solution entiere trouvee cout %e\n",Spx->Cout); + + SPX_RecupererLaSolutionSiExplorationRapide( Spx , Pne , Bb , (void *) NoeudEnExamen , TypeInstanciation ); + BB_NettoyerLArbre( Bb, &YaUneSolution , NoeudEnExamen ); /* Fait aussi la mise a jour du statut */ + + + /* Pour tests */ + PNE_CalculerLaValeurDuCritere( Pne ); + printf("Calcul du critere PNE %e SolutionAmelioranteTrouvee %d\n",Pne->Critere,Bb->SolutionAmelioranteTrouvee); + + } +} +else { + BB_NettoyerLArbre( Bb, &YaUneSolution , NoeudEnExamen ); /* Fait aussi la mise a jour du statut */ +} + +return( NoeudSuivant ); +} + +/*---------------------------------------------------------------------------------------------------------*/ +/* On cherche un noeud fils non encore evalue et on l'evalue */ + +NOEUD * BB_PreparerExplorationRapideEnProfondeur( BB * Bb , NOEUD * NoeudDuMeilleurMinorant ) +{ +NOEUD * Noeud; int YaUneSolution; int SolutionEntiereTrouvee; + +PreparationExploration: +Bb->SolutionAmelioranteTrouvee = NON; +Noeud = NoeudDuMeilleurMinorant->NoeudSuivantGauche; +if ( Noeud != NULL ) { + if ( Noeud->StatutDuNoeud != A_EVALUER ) { + Noeud = NoeudDuMeilleurMinorant->NoeudSuivantDroit; + if ( Noeud != NULL ) { + if ( Noeud->StatutDuNoeud != A_EVALUER ) Noeud = NULL; + } + } +} +if ( Noeud == NULL ) return( NULL ); /* Rien a faire */ + +Bb->SolutionAmelioranteTrouvee = NON; +Bb->NoeudEnExamen = Noeud; + +/* Resolution du noeud */ +/* Ne pas oublier d'exploiter " SolutionEntiereTrouvee " */ +YaUneSolution = BB_ResoudreLeProblemeRelaxe( Bb , Noeud , &SolutionEntiereTrouvee ); + +BB_NettoyerLArbre( Bb, &YaUneSolution , Noeud ); /* Fait aussi la mise a jour du statut */ + +BB_CreerLesNoeudsFils( Bb , Noeud ); + +if ( YaUneSolution != OUI ) goto PreparationExploration; +if ( Noeud->NoeudSuivantDroit == NULL || Noeud->NoeudSuivantGauche == NULL ) { + /* Cas le Noeud a une solution entiere */ + goto PreparationExploration; +} + +return( Noeud ); +} + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_ExplorationRapideEnProfondeur( BB * Bb ) +{ +PROBLEME_PNE * Pne; PROBLEME_SPX * Spx; +int * TypeInstanciation; NOEUD * NoeudEnExamen; int i; NOEUD * NoeudPere; NOEUD * NoeudEvalue; +NOEUD * NoeudSuivantDroit; NOEUD * NoeudSuivantGauche; +NOEUD * NoeudDuMeilleurMinorant; NOEUD * NoeudDeDepart; int NbProb; +char TerminerLaRecherche; int Fois; int MxProb; char TypeDeRecherche; + +clock_t debut; clock_t Fin; double Duree; + +printf(" BB_ExplorationRapideEnProfondeur\n"); + +Duree = 0.0; +debut = clock(); + +Fois = 1; + +Bb->SolutionAmelioranteTrouvee = NON; + +/* Precaution */ + +/* Attention aux longjmp faire un setjmp */ + +Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; +Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur; + +TypeInstanciation = (int *) malloc( Bb->NombreDeVariablesDuProbleme * sizeof( int ) ); +if ( TypeInstanciation == NULL ) return; +for ( i = 0 ; i < Bb->NombreDeVariablesDuProbleme ; i++ ) TypeInstanciation[i] = SORT_PAS; + +/*AAA:*/ +/* Choix d'un noeud prometteur */ +if ( Bb->NombreDeSolutionsEntieresTrouvees != 0 ) TypeDeRecherche = RECHERCHER_LE_PLUS_PETIT_GAP_PROPORTIONNEL; +else TypeDeRecherche = RECHERCHER_LE_PLUS_PETIT; + +BB_RechercherLeMeilleurMinorant( Bb, TypeDeRecherche ); +if ( Bb->NoeudDuMeilleurMinorant == NULL ) return; + +NoeudDuMeilleurMinorant = Bb->NoeudDuMeilleurMinorant; + +ChoixArborescence: +TerminerLaRecherche = NON; +NbProb = 1; + +/* On evalue un noeud fils du NoeudDuMeilleurMinorant. La fonction renvoie NoeudEvalue qui est + le noeud fils de NoeudDuMeilleurMinorant qu'elle a evalue */ + +Bb->CalculerDesCoupes = NON_PNE; +NoeudEvalue = BB_PreparerExplorationRapideEnProfondeur( Bb , NoeudDuMeilleurMinorant ); +Bb->CalculerDesCoupes = NON_PNE; + +if ( NoeudEvalue == NULL ) { + TerminerLaRecherche = OUI; + goto FinExploration; /* Attention c'est pas clair */ +} + +NoeudEnExamen = NoeudEvalue->NoeudSuivantDroit; +if ( NoeudEnExamen != NULL ) { + if ( NoeudEnExamen->StatutDuNoeud == A_EVALUER ) SPX_SauvegarderLaBaseDeDepart( Spx , (void *) NoeudEnExamen ); +} +NoeudEnExamen = NoeudEvalue->NoeudSuivantGauche; +if ( NoeudEnExamen != NULL ) { + if ( NoeudEnExamen->StatutDuNoeud == A_EVALUER ) SPX_SauvegarderLaBaseDeDepart( Spx , (void *) NoeudEnExamen ); +} + +/* Evaluation en profondeur */ +ExplorerLes2BranchesDUnFilsDeMeilleurMinorant: +Bb->NoeudEnExamen = NULL; +NoeudEnExamen = NoeudEvalue->NoeudSuivantDroit; +if ( NoeudEnExamen != NULL ) { + if ( NoeudEnExamen->StatutDuNoeud != A_EVALUER ) { + NoeudEnExamen = NoeudEvalue->NoeudSuivantGauche; + if ( NoeudEnExamen != NULL ) { + if ( NoeudEnExamen->StatutDuNoeud != A_EVALUER ) NoeudEnExamen = NULL; + } + } +} +if ( NoeudEnExamen == NULL ) goto ChoixArborescence; + +/* On recupere la base du NoeudEvalue comme base de depart */ +SPX_InitialiserLaBaseDeDepart( Spx , (void *) NoeudEnExamen ); +/* Le strong branching ne remet pas a jour le tableau des variables hors base une fois qu'il a tourne */ +SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); + +Spx->FaireScalingLU = 0; +Spx->StrongBranchingEnCours = NON_SPX; +Spx->UtiliserLaLuUpdate = OUI_SPX; + +/* Car on repart d'un noeud ou la base n'est pas forcement factorisee */ +SPX_FactoriserLaBase( Spx ); + +NoeudDeDepart = NoeudEnExamen; + +/* Evaluation en profondeur */ +EvaluationEnProfondeur: +while( NoeudEnExamen != NULL ) { + Bb->NoeudEnExamen = NoeudEnExamen; + /* BB_EvaluationRapideDUnNoeud renvoit NULL si on ne peut plus descendre */ + /* + printf("evaluation noeud %X profondeur %d variable instanciee %d nb prob resolus %d\n", + NoeudEnExamen,NoeudEnExamen->ProfondeurDuNoeud,NoeudEnExamen->IndiceDeLaNouvelleVariableInstanciee,NbProb); + */ + NoeudEnExamen = BB_EvaluationRapideDUnNoeud( Bb , Spx , Pne , TypeInstanciation ); + NbProb++; + MxProb = (int) ( 0.5 * Bb->NombreDeVariablesEntieresDuProbleme ); + if ( MxProb < 100 ) MxProb = 100; + if ( NbProb > MxProb /*&& Bb->NombreDeSolutionsEntieresTrouvees != 0*/ ) { + TerminerLaRecherche = OUI; + break; + } + + Fin = clock(); + Duree = ( (double) ( Fin - debut) ) / CLOCKS_PER_SEC; + printf("NbProb %d sur MxProb %d Duree %e\n",NbProb,MxProb,Duree); + + if ( Duree > 5.0 ) { + TerminerLaRecherche = OUI; + break; + } + +} +/* +printf("Fin de descente\n"); +*/ +/* Si on arrive la c'est qu'il faut remonter car on est tombe sur un noeud terminal */ +NoeudEnExamen = Bb->NoeudEnExamen; /* C'est le dernier noeud examine */ +NoeudPere = (NOEUD *) NoeudEnExamen->NoeudAntecedent; + +/* Si on a trouve une solution entiere on va a la fin */ +if ( NoeudEnExamen->LaSolutionRelaxeeEstEntiere == OUI && Bb->SolutionAmelioranteTrouvee == OUI ) { + /* Si on a trouve une solution entiere on remonte jusqu'au noeud de depart pour reliberer + les variables et desallouer les bases simplexe */ + TerminerLaRecherche = OUI; +} + +while ( 1 ) { + if ( NoeudEnExamen == NoeudDeDepart ) { + /* Cas d'echec au premier noeud */ + BB_RemettreLesDonneesAvantInstanciation( Spx, TypeInstanciation, NoeudDeDepart ); + NoeudEnExamen = NULL; + break; + } + NoeudSuivantDroit = (NOEUD *) NoeudPere->NoeudSuivantDroit; + NoeudSuivantGauche = (NOEUD *) NoeudPere->NoeudSuivantGauche; + /* On remet la variable */ + if ( NoeudSuivantDroit != NULL ) { + BB_RemettreLesDonneesAvantInstanciation( Spx, TypeInstanciation, NoeudSuivantDroit ); + } + else if ( NoeudSuivantGauche != NULL ) { + BB_RemettreLesDonneesAvantInstanciation( Spx, TypeInstanciation, NoeudSuivantGauche ); + } + /* NoeudPere a forcement ete evalue si un des fils n'a pas ete evalue, on repart de ce noeud la */ + if ( NoeudSuivantDroit != NULL ) { + if ( TerminerLaRecherche == NON ) { + if ( NoeudSuivantDroit->StatutDuNoeud == A_EVALUER ) { + NoeudEnExamen = NoeudSuivantDroit; + break; + } + } + else BB_LibererLaBaseSimplexeDuNoeud( NoeudSuivantDroit ); + } + if ( NoeudSuivantGauche != NULL ) { + if ( TerminerLaRecherche == NON ) { + if ( NoeudSuivantGauche->StatutDuNoeud == A_EVALUER ) { + NoeudEnExamen = NoeudSuivantGauche; + break; + } + } + else BB_LibererLaBaseSimplexeDuNoeud( NoeudSuivantGauche ); + } + if ( NoeudPere == NoeudDeDepart ) { + /* Les 2 branches qui partent du NoeudDeDepart on ete explorees */ + BB_RemettreLesDonneesAvantInstanciation( Spx, TypeInstanciation, NoeudDeDepart ); + NoeudEnExamen = NULL; + break; + } + NoeudPere = NoeudPere->NoeudAntecedent; +} +if ( NoeudEnExamen != NULL ) { + SPX_InitialiserLaBaseDeDepart( Spx , (void *) NoeudEnExamen ); + SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); + + Spx->FaireScalingLU = 0; + Spx->StrongBranchingEnCours = NON_SPX; + Spx->UtiliserLaLuUpdate = OUI_SPX; + + /* Car on repart d'un noeud ou la base n'est pas forcement factorisee */ + SPX_FactoriserLaBase( Spx ); + + goto EvaluationEnProfondeur; +} +/* Plus de noeuds a explorer ni a gauche ni a droite de NoeudDeDepart => on va chercher + a explorer un autre fils du noeud fils du meilleur minorant */ +if ( TerminerLaRecherche == NON ) goto ExplorerLes2BranchesDUnFilsDeMeilleurMinorant; + +FinExploration: + +for ( i = 0 ; i < Bb->NombreDeVariablesDuProbleme ; i++ ) { + if ( TypeInstanciation[i] != SORT_PAS ) { + printf("TypeInstanciation pas bien remis\n"); + exit(0); + } +} + +Fois++; + +if ( Bb->NombreDeSolutionsEntieresTrouvees == 0 && 0 ) { + NoeudEnExamen = BB_RechercherLeNoeudLeMoinsFractionnaire( Bb , MOINS_DE_VALEURS_FRACTIONNAIRES ); + if ( NoeudEnExamen != NULL ) { + Bb->NoeudEnExamen = NoeudEnExamen; + /* goto ChoixArborescence; *//* Non car noeud sauvegarde */ + } +} +else { + if ( Bb->SolutionAmelioranteTrouvee == NON ) { + if ( Fois < 2 && NbProb <= ceil( 0.1 * (float) Bb->NombreDeVariablesEntieresDuProbleme ) ) { + /* goto AAA; */ /* Non car noeud sauvegarde */ + } + } +} + +free( TypeInstanciation ); +TypeInstanciation = NULL; + +return; +} diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_fonctions.h b/src/ext/Sirius_Solver/branchAndBound/bb_fonctions.h new file mode 100644 index 0000000000..26df60629c --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_fonctions.h @@ -0,0 +1,120 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef FONCTIONS_BB_DEJA_DEFINIES +/*-----------------------------------------------------------------------------------------*/ + +# include "bb_define.h" + +int BB_BranchAndBound( void * , int , int , double , int , int , int , char , int * ); + +int BB_BranchAndBoundCalculs( BB * , int , int , double ,int , int , int , char , int * ); + +NOEUD * BB_AllouerUnNoeud( BB * , NOEUD * , int , int , int , int , int * , double ); + +void BB_DesallouerUnNoeud( BB * , NOEUD * ); + +void BB_DesallocationPartielleDUnNoeud( NOEUD * ); + +void BB_BranchAndBoundAllouerProbleme( BB * ); + +void BB_BranchAndBoundDesallouerProbleme( BB * ); + +int BB_ResoudreLeProblemeRelaxe( BB * , NOEUD * , int * ); + +char BB_ArchiverToutesLesCoupesLorsDuTri( BB * ); + +void BB_AfficherLesTraces( BB * , NOEUD * ); + +void BB_LeverLeFlagPourEnleverToutesLesCoupes( BB * ); + +void BB_LeverLeFlagDeSortieDuSimplexeParDepassementDuCoutMax( BB * ); + +int BB_ChoixDesVariablesAInstancier( BB * , NOEUD * , int * , int * , int ** , int * , int * , int ** ); + +void BB_EliminerLesNoeudsSousOptimaux( BB * ); + +void BB_SupprimerTousLesDescendantsDUnNoeud( BB * , NOEUD * ); + +int BB_BalayageEnProfondeur( BB * , NOEUD * , int ); + +NOEUD * BB_NoeudPereSuivantDansRechercheEnProfondeur( NOEUD ** ); + +NOEUD * BB_RemonterDansRechercheEnProfondeur( NOEUD * , int ); + +void BB_CreerLesNoeudsFils( BB * , NOEUD * ); + +void BB_BalayageEnLargeur( BB * , NOEUD * , int ); + +void BB_FaireUneRechercheEnProfondeurDansUneRechercheEnLargeur( BB * ); + +void BB_NettoyerLArbre( BB * , int * , NOEUD * ); + +void BB_NettoyerLArbreDeLaRechercheEnProfondeur( BB * , NOEUD * , NOEUD * , int ); /* Obsolete */ + +int BB_ExaminerUnNoeudEnProfondeur( BB * , NOEUD * , int * /*, int , NOEUD ** , int , NOEUD ***/ ); + +void BB_RechercherLeMeilleurMinorant( BB * , char ); + +NOEUD * BB_RechercherLeNoeudLeMoinsFractionnaire( BB * , char ); + +NOEUD * BB_RechercherLeNoeudLeAvecMeilleurRatioFractionnaire( BB * ); + +void BB_EvaluerEnProfondeurLesNoeudsCritiques( BB * ); + +/* Coupes */ + +void BB_StockerUneCoupeGenereeAuNoeud( BB * , int , double * , int * , double , /*int ,*/ char ); + +void BB_InsererLesCoupesDansLeProblemeCourant( BB * , NOEUD * ); + +void BB_RechercherLesCoupesViolees( BB * , double * ); + +void BB_NettoyerLesCoupes( BB * , char ); + +void BB_DemanderUneNouvelleResolutionDuProblemeRelaxe( BB * ); + +/* */ + +void BB_BestFirst( BB * ); + +void BB_EvaluerLesDeuxFilsDuMeilleurMinorant( BB * , NOEUD * ); + +/* */ + +void BB_ControlerLesCoupesNonInsereesInitialement( BB * , char * ); + +/*----------------- Specifique pour l'exploration rapide en profondeur --------------------*/ +void BB_LibererLaBaseSimplexeDuNoeud( NOEUD * ); +/* +void BB_RemettreLesDonneesAvantInstanciation( BB * , PROBLEME_SPX * , int * , NOEUD * ); +void BB_InstancierLaVariableDansLeSimplexe( BB * , PROBLEME_SPX * , int * , NOEUD * ); +NOEUD * BB_EvaluationRapideDUnNoeud( BB * , PROBLEME_SPX * , PROBLEME_PNE * , int * ); +*/ +NOEUD * BB_PreparerExplorationRapideEnProfondeur( BB * , NOEUD * ); +void BB_ExplorationRapideEnProfondeur( BB * ); + +/*-----------------------------------------------------------------------------------------*/ +# define FONCTIONS_BB_DEJA_DEFINIES +# endif +# ifdef __cplusplus + } +# endif + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_inserer_les_coupes.c b/src/ext/Sirius_Solver/branchAndBound/bb_inserer_les_coupes.c new file mode 100644 index 0000000000..6e0d7862de --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_inserer_les_coupes.c @@ -0,0 +1,405 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Preparation des coupes a passer a la resolution du + probleme en un noeud donne. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" +#include "pne_fonctions.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +#define NOMBRE_MAX_DE_COUPES_HORS_BRANCHE 100000 /* Pas de limite */ /*10*/ /*100*/ + +#define NOMBRE_MAX_DE_COUPES_VIOLEES_AJOUTEES 100000 /* Pas de limite */ /*100*/ /*50*/ + +#define NOMBRE_MAX_DE_TERMES_DES_COUPES_INSEREES 500000 + +#define NOMBRE_MAX_DE_COUPES_DE_CODE_MOINS_1 100000 /* Pas de limite */ /*100*/ /*50*/ + +#define NOMBRE_MAX_DE_COUPES_PAR_PROBLEME_RELAXE 500 + +void BB_EchangerViolation( double * , int * , int , int ); +int BB_PartitionTriRapideViolations( double * , int * , int , int ); +void BB_TriRapideViolations( double * , int * , int , int ); + +/*----------------------------------------------------------------------------*/ +void BB_EchangerViolation( double * Tableau1 , int * Tableau2 , int i, int j ) +{ +double X; int k; +X = Tableau1[i]; +k = Tableau2[i]; +Tableau1[i] = Tableau1[j]; +Tableau2[i] = Tableau2[j]; +Tableau1[j] = X; +Tableau2[j] = k; +return; +} +/*----------------------------------------------------------------------------*/ +int BB_PartitionTriRapideViolations( double * Tableau1 , int * Tableau2 , int Deb, int Fin ) +{ +int Compt; double Pivot; int i; double X; int k; +Compt = Deb; +Pivot = Tableau1[Deb]; +for ( i = Deb+1 ; i <= Fin ; i++) { + if ( Tableau1[i] > Pivot) { + Compt++; + /*BB_EchangerViolation( Tableau1 , Tableau2 , Compt , i);*/ + X = Tableau1[Compt]; + k = Tableau2[Compt]; + Tableau1[Compt] = Tableau1[i]; + Tableau2[Compt] = Tableau2[i]; + Tableau1[i] = X; + Tableau2[i] = k; + } +} +/*BB_EchangerViolation( Tableau1 , Tableau2 , Compt , Deb);*/ +X = Tableau1[Compt]; +k = Tableau2[Compt]; +Tableau1[Compt] = Tableau1[Deb]; +Tableau2[Compt] = Tableau2[Deb]; +Tableau1[Deb] = X; +Tableau2[Deb] = k; +return(Compt); +} +/*----------------------------------------------------------------------------*/ +void BB_TriRapideViolations( double * Tableau1 , int * Tableau2 , int Debut , int Fin ) +{ +int Pivot; +if ( Debut < Fin ) { + Pivot = BB_PartitionTriRapideViolations( Tableau1 , Tableau2 , Debut , Fin ); + BB_TriRapideViolations( Tableau1 , Tableau2 , Debut , Pivot-1 ); + BB_TriRapideViolations( Tableau1 , Tableau2 , Pivot+1 , Fin ); +} +return; +} +/*---------------------------------------------------------------------------------------------------------*/ +/* SP appele par la partie PNE pour determiner les coupes violees qui donc, n'avaient pas ete incluses + dans le probleme */ +void BB_RechercherLesCoupesViolees( BB * Bb, double * U ) +{ +COUPE ** Coupe; COUPE * Cpe; int NumeroDeCoupe; int il; double X; double Marge; NOEUD * NoeudCourant; int Pas; +int Capacite; int i; double * Violation; char OnContinue; double CumulDesViolations; int FinBoucle; +double * Coefficient; int * NumeroDesCoupeAjouteeAuProblemeCourant; int * IndiceDeLaVariable; + +if ( Bb->ControlerLesCoupesNonInclusesPourUnNouvelleResolution == OUI ) { + /* Dans ce cas la resolution du noeud est eventuellement relancee si des coupes non + incluses sont violees */ + return; +} + +NoeudCourant = Bb->NoeudEnExamen; + +Marge = 1.e-2 /*1.e-4*/; /* Il ne faut pas etre trop severe sinon on surcharge inutilement la matrice des contraintes */ +Pas = 20; +Capacite = Pas; +CumulDesViolations = 0.0; + +NumeroDesCoupeAjouteeAuProblemeCourant = Bb->NoeudRacine->NumeroDesCoupeAjouteeAuProblemeCourant; + +NoeudCourant->NumeroDesCoupesViolees = (int *) malloc( Capacite * sizeof( int ) ); +Violation = (double *) malloc( Capacite * sizeof( double ) ); +if ( NoeudCourant->NumeroDesCoupesViolees == NULL || Violation == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_RechercherLesCoupesViolees\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} + +Coupe = Bb->NoeudRacine->CoupesGenereesAuNoeud; +for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud ; NumeroDeCoupe++ ) { + Coupe[NumeroDeCoupe]->CoupeExamineeAuNoeudCourant = NON; +} +for ( i = 0 ; i < Bb->NombreDeCoupesAjoutees ; i++ ) { + Coupe[NumeroDesCoupeAjouteeAuProblemeCourant[i]]->CoupeExamineeAuNoeudCourant = OUI; +} + +/* Marquage des coupes que l'on pourra utiliser */ +for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud ; NumeroDeCoupe++ ) { + if ( Coupe[NumeroDeCoupe]->CoupeExamineeAuNoeudCourant == OUI ) continue; + X = 0.; + Cpe = Coupe[NumeroDeCoupe]; + Coefficient = Cpe->Coefficient; + IndiceDeLaVariable = Cpe->IndiceDeLaVariable; + for ( il = 0 ; il < Cpe->NombreDeTermes ; il++ ) { + X += Coefficient[il] * U[IndiceDeLaVariable[il]]; + } + if ( X > Cpe->SecondMembre + Marge ) { + if ( NoeudCourant->NombreDeCoupesViolees >= Capacite ) { + Capacite += Pas; + NoeudCourant->NumeroDesCoupesViolees = (int *) realloc( NoeudCourant->NumeroDesCoupesViolees , Capacite * sizeof( int ) ); + Violation = (double *) realloc( Violation , Capacite * sizeof( double ) ); + if ( NoeudCourant->NumeroDesCoupesViolees == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_RechercherLesCoupesViolees\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + } + Violation[NoeudCourant->NombreDeCoupesViolees] = X - Cpe->SecondMembre; + CumulDesViolations += Violation[NoeudCourant->NombreDeCoupesViolees]; + NoeudCourant->NumeroDesCoupesViolees[NoeudCourant->NombreDeCoupesViolees] = NumeroDeCoupe; + NoeudCourant->NombreDeCoupesViolees++; + } +} + +/* On Classe dans l'ordre decroissant des violation */ +/* +if ( NoeudCourant->NombreDeCoupesViolees > 1 ) { + BB_TriRapideViolations( Violation , NoeudCourant->NumeroDesCoupesViolees , + 0 , NoeudCourant->NombreDeCoupesViolees - 1 ); +} +*/ +/* De façon inattendue, le tri rapide ci-dessus est generalement plus long que le tri bulle + ci-dessous. L'explication reside dans le fait qu'il y a le plus souvent un petit nombre + de coupes violees, et que l'on refait donc peu de fois la boucle de classement. */ + +/* Comme on prend toutes les coupes violees, le classement est inutile */ +OnContinue = OUI; +FinBoucle = NoeudCourant->NombreDeCoupesViolees - 1; +/* +while ( OnContinue == OUI ) { + OnContinue = NON; + for ( i = 0 ; i < FinBoucle ; i++ ) { + if ( Violation[i] < Violation[i+1] ) { + OnContinue = OUI; + il = NoeudCourant->NumeroDesCoupesViolees[i+1]; + X = Violation[i+1]; + NoeudCourant->NumeroDesCoupesViolees[i+1] = NoeudCourant->NumeroDesCoupesViolees[i]; + NoeudCourant->NumeroDesCoupesViolees[i] = il; + Violation[i+1] = Violation[i]; + Violation[i] = X; + } + } + FinBoucle--; +} +*/ +/* +printf("############## NombreDeCoupes Violees: %d cumul des violations %f #################\n", + NoeudCourant->NombreDeCoupesViolees, CumulDesViolations); +*/ +free( Violation ); + +return; +} + +/*---------------------------------------------------------------------------------------------------------*/ +void BB_DemanderUneNouvelleResolutionDuProblemeRelaxe( BB * Bb ) +{ +Bb->ComplementDeBaseModifie = OUI; +Bb->MajorantDuNombreDeCoupesAjouteesApresResolutionDuProblemeRelaxe++; +return; +} + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_InsererLesCoupesDansLeProblemeCourant( BB * Bb, NOEUD * NoeudDeDepart /* C'est toujours le noeud du probleme relaxe */ ) +{ +NOEUD * NoeudCourant ; COUPE ** Coupe; int i; int NumeroDeCoupe; NOEUD * NoeudPere; +int Nb ; int NombreMaxDeCoupesAjouteesHorsBranche ; int Count; int NbMax; +int NbLift; int NbGom; int NbLiftTot; int NbGomTot; int NbI; int NombreMaxDeTermesDesCoupesInserees; +int NbLiftSat; int NbK; int NbKTot; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; + +Bb->NombreMaxDeCoupesParProblemeRelaxe = NOMBRE_MAX_DE_COUPES_PAR_PROBLEME_RELAXE; + +i = Pne->MdebTrav[Pne->NombreDeContraintesTrav-1] + Pne->NbTermTrav[Pne->NombreDeContraintesTrav-1]; +NombreMaxDeTermesDesCoupesInserees = 10 * i; +if ( NombreMaxDeTermesDesCoupesInserees > NOMBRE_MAX_DE_TERMES_DES_COUPES_INSEREES ) { + NombreMaxDeTermesDesCoupesInserees = NOMBRE_MAX_DE_TERMES_DES_COUPES_INSEREES; +} + +NbLift = 0; +NbGom = 0; +NbLiftTot = 0; +NbGomTot = 0; +NbLiftSat = 0; +NbK = 0; +NbKTot = 0; +NbI = 0; + +#if VERBOSE_BB + printf("-> Ajout des coupes avant resolution du probleme relaxe\n"); +#endif + +Bb->NombreDeCoupesAjoutees = 0; + +if ( Bb->EcartBorneInf > 100. ) NombreMaxDeCoupesAjouteesHorsBranche = NOMBRE_MAX_DE_COUPES_HORS_BRANCHE; +else NombreMaxDeCoupesAjouteesHorsBranche = (int) ceil( 0.5 * Bb->NombreMaxDeCoupesParProblemeRelaxe ); + +/* Recuperation du probleme initial , c'est a dire le probleme sans les coupes ajoutees + pendant le branch and bound */ +PNE_RecupererLeProblemeInitial( Pne ); + +NoeudPere = NoeudDeDepart->NoeudAntecedent; + +#if VERBOSE_BB + printf("-> Nombre de coupes disponibles dans le pool: %d\n",Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud); +#endif + +/* Marquage initial des coupes */ +Coupe = Bb->NoeudRacine->CoupesGenereesAuNoeud; +for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud ; NumeroDeCoupe++ ) { + + if ( Coupe[NumeroDeCoupe]->TypeDeCoupe == 'L' ) NbLiftTot++; + if ( Coupe[NumeroDeCoupe]->TypeDeCoupe == 'G' ) NbGomTot++; + if ( Coupe[NumeroDeCoupe]->TypeDeCoupe == 'K' ) NbKTot++; + + Coupe[NumeroDeCoupe]->UtiliserLaCoupe = NON; + Coupe[NumeroDeCoupe]->CoupeExamineeAuNoeudCourant = NON; + Coupe[NumeroDeCoupe]->CoupeRencontreeDansLArborescence = NON; + +} + +Nb = 0; +NoeudCourant = NoeudDeDepart; +for ( i = 0 ; i < NoeudCourant->NombreDeCoupesExaminees ; i++ ) { + NumeroDeCoupe = NoeudCourant->NumeroDesCoupesExaminees[i]; + Coupe[NumeroDeCoupe]->CoupeExamineeAuNoeudCourant = OUI; + if ( NoeudCourant->LaCoupeEstSaturee[i] == OUI ) { + Coupe[NumeroDeCoupe]->UtiliserLaCoupe = OUI; + Coupe[NumeroDeCoupe]->CoupeSaturee = OUI_PNE; + } + /* Si la coupe a un code saturation de -1 on la prend en compte et on la met non saturee pour que la variable + d'ecart soit basique, ceci a condition qu'elle n'ait pas ete rencontree dans un fils */ + if ( NoeudCourant->LaCoupeEstSaturee[i] == -1 && Coupe[NumeroDeCoupe]->UtiliserLaCoupe == NON && + Nb < NOMBRE_MAX_DE_COUPES_DE_CODE_MOINS_1 ) { + Coupe[NumeroDeCoupe]->UtiliserLaCoupe = OUI; + Coupe[NumeroDeCoupe]->CoupeSaturee = NON_PNE; + Nb++; + } +} + +/* On ajoute les coupes qui n'avaient pas ete ajoutees au noeud pere mais qui se sont retrouvees violees + quand-meme */ +Nb = 0; +NoeudCourant = NoeudDeDepart->NoeudAntecedent; +if ( NoeudCourant != 0 ) { + for ( i = 0 ; i < NoeudCourant->NombreDeCoupesViolees ; i++ ) { + if ( Nb > NOMBRE_MAX_DE_COUPES_VIOLEES_AJOUTEES ) break; + if ( Nb > Bb->NombreMaxDeCoupesParProblemeRelaxe ) break; + NumeroDeCoupe = NoeudCourant->NumeroDesCoupesViolees[i]; + /*if ( Coupe[NumeroDeCoupe]->TypeDeCoupe == 'L' ) continue;*/ + if ( Coupe[NumeroDeCoupe]->UtiliserLaCoupe == OUI ) continue; + + Coupe[NumeroDeCoupe]->UtiliserLaCoupe = OUI; + Coupe[NumeroDeCoupe]->CoupeSaturee = NON_PNE; + Nb++; + } +} +/* +printf("Nombre de coupes non saturees violees ajoutees: %d\n",Nb); +*/ +/* On prepare les informations qui contiendront la liste des coupes saturees apres la resolution du noeud */ +for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud; NumeroDeCoupe++ ) { + if ( Coupe[NumeroDeCoupe]->UtiliserLaCoupe == OUI ) { + Bb->NoeudRacine->NumeroDesCoupeAjouteeAuProblemeCourant[Bb->NombreDeCoupesAjoutees] = NumeroDeCoupe; + Bb->NombreDeCoupesAjoutees++; + } +} + +/* Si une coupe a ete creee dans une autre arborescence et qu'elle n'a pas encore ete testee dans l'arborescence + qui part du noeud en examen, on la teste. Mais il faut la declarer comme non saturee afin d'avoir une + base de depart. Ceci, dans la limite du nombre max de coupes que l'on s'autorise a integrer dans un probleme + relaxe */ +NoeudCourant = NoeudDeDepart; +while ( 1 ) { + if ( NoeudCourant == 0 ) break; + for ( i = 0 ; i < NoeudCourant->NombreDeCoupesExaminees ; i++ ) { + NumeroDeCoupe = NoeudCourant->NumeroDesCoupesExaminees[i]; + Coupe[NumeroDeCoupe]->CoupeRencontreeDansLArborescence = OUI; + } + NoeudCourant = NoeudCourant->NoeudAntecedent; +} + +for ( NumeroDeCoupe = 0 , Nb = 0 ; + NumeroDeCoupe < Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud && + Bb->NombreDeCoupesAjoutees < Bb->NombreMaxDeCoupesParProblemeRelaxe && + Nb < NombreMaxDeCoupesAjouteesHorsBranche ; + NumeroDeCoupe++ ) { + if ( Coupe[NumeroDeCoupe]->UtiliserLaCoupe == NON && Coupe[NumeroDeCoupe]->CoupeRencontreeDansLArborescence == NON ) { + Coupe[NumeroDeCoupe]->CoupeSaturee = NON_PNE; + Nb++; + Bb->NoeudRacine->NumeroDesCoupeAjouteeAuProblemeCourant[Bb->NombreDeCoupesAjoutees] = NumeroDeCoupe; + Bb->NombreDeCoupesAjoutees++; + } +} + +if ( Bb->NombreDeCoupesAjoutees == 0 ) goto FinInsertionCoupes; + +/* On ajoute les coupes */ +Count = 0; +NbMax = Bb->NombreDeCoupesAjoutees; +Bb->NombreDeCoupesAjoutees = 0; +for ( Nb = 0 ; Nb < NbMax ; Nb++ ) { + NumeroDeCoupe = Bb->NoeudRacine->NumeroDesCoupeAjouteeAuProblemeCourant[Nb]; + + Count+= Coupe[NumeroDeCoupe]->NombreDeTermes; + + /* Attention, on ne peut pas mettre de limitation ici car il se peut qu'en le faisant on enleve + une coupe saturee et donc on se retrouve avec une base non inversible */ + /* if ( Count > NombreMaxDeTermesDesCoupesInserees ) break; */ + + Bb->NombreDeCoupesAjoutees++; + + if ( Coupe[NumeroDeCoupe]->TypeDeCoupe == 'L' ) { + NbLift++; + if ( Coupe[NumeroDeCoupe]->CoupeSaturee == OUI_PNE ) NbLiftSat++; + } + else if ( Coupe[NumeroDeCoupe]->TypeDeCoupe == 'G' ) NbGom++; + else if ( Coupe[NumeroDeCoupe]->TypeDeCoupe == 'K' ) NbK++; + else if ( Coupe[NumeroDeCoupe]->TypeDeCoupe == 'I' ) NbI++; + + PNE_InsererUneContrainte( Pne, + Coupe[NumeroDeCoupe]->NombreDeTermes, + Coupe[NumeroDeCoupe]->Coefficient, + Coupe[NumeroDeCoupe]->IndiceDeLaVariable, + Coupe[NumeroDeCoupe]->SecondMembre, + Coupe[NumeroDeCoupe]->CoupeSaturee, + Coupe[NumeroDeCoupe]->TypeDeCoupe + ); +} + +FinInsertionCoupes: +/* +printf(" Nombre de Gomory ajoutees : %d sur % d\n",NbGom,NbGomTot); +printf(" Nombre de Knapsack ajoutees : %d sur % d\n",NbK,NbKTot); +*/ +#if VERBOSE_BB + printf("-> Nombre de coupes ajoutees avant resolution du probleme relaxe: %d Profondeur du noeud: %d\n", + Bb->NombreDeCoupesAjoutees, NoeudDeDepart->ProfondeurDuNoeud); +#endif + +Bb->NombreTotalDeCoupesDuPoolUtilisees += Bb->NombreDeCoupesAjoutees; + +Bb->NombreTotalDeGDuPoolUtilisees += NbGom; +Bb->NombreTotalDeIDuPoolUtilisees += NbI;; +Bb->NombreTotalDeKDuPoolUtilisees += NbK; + +return; +} + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_memoire.h b/src/ext/Sirius_Solver/branchAndBound/bb_memoire.h new file mode 100644 index 0000000000..bd5dc4aea7 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_memoire.h @@ -0,0 +1,41 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef BB_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# include "mem_fonctions.h" +/***************************************************************** + + + Macros pour redefinir les primitives de gestion memoire lorsqu'on + ne veut pas utiliser celles de lib de l'OS + + +*****************************************************************/ + +# define malloc(Taille) MEM_Malloc(Bb->Tas,Taille) +# define free(Pointeur) MEM_Free(Pointeur) +# define realloc(Pointeur,Taille) MEM_Realloc(Bb->Tas,Pointeur,Taille) + +/*****************************************************************/ +# define BB_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# endif +# ifdef __cplusplus + } +# endif diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_nettoyer_arbre.c b/src/ext/Sirius_Solver/branchAndBound/bb_nettoyer_arbre.c new file mode 100644 index 0000000000..1cd7f3cdc4 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_nettoyer_arbre.c @@ -0,0 +1,187 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: + + Appele pour nettoyer l'arbre apres chaque resolution du probleme relaxe. + Si la solution du probleme relaxe n'est pas entiere, on compare son cout au cout de la meilleure solution + entiere trouvee: + 1- S'il est superieur ou egal, alors le noeud est marque A_REJETER + 2- S'il est inferieur, alors on ne peut pas trancher et le statut du noeud reste a EVALUE + Si la solution du probleme relaxe est entiere, on compare son cout au cout de la meilleure solution + entiere trouvee: + 1- S'il est superieur, alors le noeud est marque A_REJETER + 2- S'il est inferieur alors: + a- Son cout remplace celui de la meilleure solution entiere trouvee + b- L'arbre est reparcouru et tous les noeuds dont le cout est superieur au nouveau cout sont + supprimes + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_define.h" +#include "pne_fonctions.h" + +# define MARGE 1.e-6 /* 1.e-9 */ + +# define COEFF_PROFONDEUR_LIMITE 1.25 + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_NettoyerLArbre( BB * Bb, int * YaUneSolution, NOEUD * NoeudCourant ) +{ +PROBLEME_PNE * Pne; NOEUD * NoeudPere; NOEUD * NoeudFils; double Marge; + +Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; + +NoeudCourant->StatutDuNoeud = EVALUE; +NoeudCourant->NbValeursFractionnairesApresResolution = Pne->NombreDeVariablesAValeurFractionnaire; +NoeudCourant->NormeDeFractionnalite = Pne->NormeDeFractionnalite; + +/* Mise a jour du nombre de noeuds ouverts en regardant le pere */ +NoeudPere = NoeudCourant->NoeudAntecedent; +if ( NoeudPere != NULL ) { + NoeudFils = NoeudPere->NoeudSuivantGauche; + if ( NoeudFils != NULL ) { + if ( NoeudFils->StatutDuNoeud != A_EVALUER || NoeudFils == NoeudCourant ) { + NoeudFils = NoeudPere->NoeudSuivantDroit; + if ( NoeudFils != NULL ) { + if ( NoeudFils->StatutDuNoeud != A_EVALUER || NoeudFils == NoeudCourant ) { + Bb->NbNoeudsOuverts--; + } + } + } + } +} + +if ( *YaUneSolution != OUI ) { + NoeudCourant->StatutDuNoeud = A_REJETER; + NoeudCourant->NoeudTerminal = OUI; + NoeudCourant->NoeudSuivantGauche = 0; + NoeudCourant->NoeudSuivantDroit = 0; + NoeudCourant->NbValeursFractionnairesApresResolution = Bb->NombreDeVariablesEntieresDuProbleme; + NoeudCourant->NormeDeFractionnalite = PLUS_LINFINI; + + /* On peut recuperer de la place */ + BB_DesallocationPartielleDUnNoeud( NoeudCourant ); + + Bb->NbNoeudsOuverts--; + + return; +} + +if ( NoeudCourant->LaSolutionRelaxeeEstEntiere == NON ) { /* Cas ou la solution du probleme relaxe n'est pas entiere */ + + /* On elimine le noeud si la solution entiere disponible est optimale par rapport au sous arbre */ + Marge = Bb->ToleranceDOptimalite * 0.01 * fabs( NoeudCourant->MinorantDuCritereAuNoeud ); + if ( Marge < MARGE ) Marge = MARGE; + + if ( NoeudCourant->MinorantDuCritereAuNoeud >= Bb->CoutDeLaMeilleureSolutionEntiere - Marge /*MARGE*/ ) { + /* Le cout de la solution du probleme relaxe est superieur a celui de la meilleure solution entiere => noeud a rejeter */ + NoeudCourant->StatutDuNoeud = A_REJETER; + NoeudCourant->NoeudTerminal = OUI; + NoeudCourant->NoeudSuivantGauche = 0; + NoeudCourant->NoeudSuivantDroit = 0; + /* On peut recuperer de la place */ + BB_DesallocationPartielleDUnNoeud( NoeudCourant ); + + Bb->NbNoeudsOuverts--; + + } + return; /* rq: dans le cas ou on ne peut pas trancher, le statut du noeud reste a EVALUE */ +} + +/* La solution est entiere, on demande l'evaluation des fils du noeud du meilleur minorant */ +Bb->NbNoeudsOuverts--; /* Car on ne regardera pas sous le noeud vu que la solution est entiere */ +Bb->EvaluerLesFilsDuMeilleurMinorant = OUI; + +/* Le solution est entiere, le noeud est marque terminal et on essaie de nettoyer l'arbre */ +NoeudCourant->NoeudTerminal = OUI; +NoeudCourant->NoeudSuivantGauche = 0; +NoeudCourant->NoeudSuivantDroit = 0; + +if ( NoeudCourant->MinorantDuCritereAuNoeud >= Bb->CoutDeLaMeilleureSolutionEntiere ) { + /* Le cout de la solution est superieur a celui de la meilleure solution entiere => noeud a rejeter */ + #if VERBOSE_BB + printf(" Solution entiere trouvee mais elle est plus chere que la solution entiere courante: le noeud est terminal a rejeter \n"); + #endif + NoeudCourant->StatutDuNoeud = A_REJETER; + return; +} + +/* Si c'est la premiere solution entiere on relance le calcul des coupes */ +if ( Bb->NoeudDeLaMeilleureSolutionEntiere == 0 ) { + Bb->NbMaxDeCoupesCalculeesAtteint = NON; + Bb->NombreMaxDeCoupes = Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud + NOMBRE_MAX_DE_COUPES; + Bb->NombreMoyenMinimumDeCoupesUtiles = NOMBRE_MOYEN_MINIMUM_DE_COUPES_UTILES; +} + +/* La solution est entiere et il s'agit du meilleur cout rencontre */ +Bb->SommeDesProfondeursDesSolutionsAmeliorantes += NoeudCourant->ProfondeurDuNoeud; +Bb->NombreDeSolutionsAmeliorantes++; + +Bb->SolutionAmelioranteTrouvee = OUI; +Bb->NumeroDeProblemeDeLaSolutionAmeliorante = Bb->NombreDeProblemesResolus; +Bb->NoeudDeLaMeilleureSolutionEntiere = NoeudCourant; +Bb->CoutDeLaMeilleureSolutionEntiere = NoeudCourant->MinorantDuCritereAuNoeud; +if ( (int) (COEFF_PROFONDEUR_LIMITE * Bb->NoeudDeLaMeilleureSolutionEntiere->ProfondeurDuNoeud) > + Bb->ProfondeurMaxiSiPlongeePendantUneRechercheEnLargeur ) { + Bb->ProfondeurMaxiSiPlongeePendantUneRechercheEnLargeur = (int) (COEFF_PROFONDEUR_LIMITE * Bb->NoeudDeLaMeilleureSolutionEntiere->ProfondeurDuNoeud); +} + +/* +if ( Bb->NombreDeVariablesEntieresDuProbleme > 0 ) { + Bb->ForcerAffichage = OUI; +} +*/ + +if ( Bb->NombreDeVariablesEntieresDuProbleme > 0 ) { + Bb->ForcerAffichage = OUI; + BB_AfficherLesTraces( Bb, NoeudCourant ); +} +Bb->ForcerAffichage = NON; + +/* +for ( i= 0 ; i < Bb->NombreDeVariablesEntieresDuProbleme ; i++ ) { + Bb->ValeursOptimalesDesVariablesEntieres[i] = Bb->ValeursCalculeesDesVariablesEntieresPourLeProblemeRelaxeCourant[i]; +} +*/ +/* +for ( i= 0 ; i < Bb->NombreDeVariablesDuProbleme ; i++ ) { + Bb->ValeursOptimalesDesVariables[i] = Bb->ValeursCalculeesDesVariablesPourLeProblemeRelaxeCourant[i]; +} +*/ + +/* On demande ŕ la PNE de stocker la solution */ + +PNE_ArchiverLaSolutionCourante( Pne ); + +/* Nettoyage de l'arbre: tout l'arbre est explore a partir de la racine */ +BB_EliminerLesNoeudsSousOptimaux( Bb ); + +Bb->NombreDEvaluationDuMeilleurMinorant = NOMBRE_DEVALUATIONS_DU_MEILLEUR_MINORANT; + +return; +} + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_nettoyer_les_coupes.c b/src/ext/Sirius_Solver/branchAndBound/bb_nettoyer_les_coupes.c new file mode 100644 index 0000000000..7623571bf9 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_nettoyer_les_coupes.c @@ -0,0 +1,360 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Nettoyage des coupes si l'on en a trop cree. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "pne_fonctions.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_NettoyerLesCoupes( BB * Bb, char DemandeExpresse ) +{ +NOEUD ** NoeudsAExplorer ; NOEUD ** NoeudsAExplorerAuProchainEtage ; +NOEUD * Noeud ; NOEUD * NoeudCourant ; +int NombreDeNoeudsAExplorer ; int NombreDeNoeudsAExplorerAuProchainEtage; +int i; int j; int NumeroDeCoupe ; int NombreDeCoupesEnlevees ; +char UtiliserLaCoupe ; int NumeroDeLaPremiereCoupeSupprimee ; + +COUPE ** Coupe; +char TypeDeCoupe; double * Coefficient; int * IndiceDeLaVariable; char OnInverse; int NbLiftAndProject; + +/* Remarque: lorsqu'il faut nettoyer les coupes a cause d'instabilités numeriques, il faut vraiment +le faire sinon ca plante. Donc il ne faut pas shunter le test sur DemandeExpresse */ + +if ( DemandeExpresse != OUI ) { + /* Plutot que de nettoyer on arrete d'en calculer */ + Bb->NbMaxDeCoupesCalculeesAtteint = OUI; + goto FinNettoyage; +} + +#if VERBOSE_BB + printf("-> Nettoyage des coupes\n"); +#endif + +Bb->EvaluerLesFilsDuMeilleurMinorant = OUI; + +/* Marquage initial des coupes */ +Coupe = Bb->NoeudRacine->CoupesGenereesAuNoeud; +for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud ; NumeroDeCoupe++ ) { + Coupe[NumeroDeCoupe]->UtiliserLaCoupe = NON; + /* On veut conserver les coupes du noeud racine */ + if ( Coupe[NumeroDeCoupe]->CoupeRacine == OUI ) Coupe[NumeroDeCoupe]->UtiliserLaCoupe = OUI; +} + +NoeudsAExplorer = (NOEUD **) malloc( 1 * sizeof( void * ) ); +if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_NettoyerLesCoupes 1\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} +NombreDeNoeudsAExplorer = 1; +NoeudsAExplorer[0] = Bb->NoeudRacine; + +/* Marquage de coupes saturees qui sont presentes dans les noeuds qui restent a evaluer */ +while( 1 ) { + NoeudsAExplorerAuProchainEtage = (NOEUD **) malloc( NombreDeNoeudsAExplorer * 2 * sizeof( void * ) ); + if ( NoeudsAExplorerAuProchainEtage == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_ NettoyerLesCoupes 2\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorerAuProchainEtage = 0; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudCourant = NoeudsAExplorer[i]; + if ( NoeudCourant != 0 ) { + if ( NoeudCourant->StatutDuNoeud == EVALUE && NoeudCourant->NoeudTerminal != OUI ) { + Noeud = NoeudCourant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud == A_EVALUER ) { + /* On recherche les coupes saturees */ + for ( j = 0 ; j < Noeud->NombreDeCoupesExaminees ; j++ ) { + NumeroDeCoupe = Noeud->NumeroDesCoupesExaminees[j]; + Coupe[NumeroDeCoupe]->CoupeExamineeAuNoeudCourant = OUI; + if ( Noeud->LaCoupeEstSaturee[j] == OUI ) Coupe[NumeroDeCoupe]->UtiliserLaCoupe = OUI; + /* Si la coupe a un code saturation de -1 on la prend en compte */ + if ( Noeud->LaCoupeEstSaturee[j] == -1 ) Coupe[NumeroDeCoupe]->UtiliserLaCoupe = OUI; + } + } + else { + /* Le fils gauche a ete evalue, il faut descendre d'un cran */ + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + } + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud == A_EVALUER ) { + /* On recherche les coupes saturees */ + for ( j = 0 ; j < Noeud->NombreDeCoupesExaminees ; j++ ) { + NumeroDeCoupe = Noeud->NumeroDesCoupesExaminees[j]; + Coupe[NumeroDeCoupe]->CoupeExamineeAuNoeudCourant = OUI; + if ( Noeud->LaCoupeEstSaturee[j] == OUI ) Coupe[NumeroDeCoupe]->UtiliserLaCoupe = OUI; + /* Si la coupe a un code saturation de -1 on la prend en compte */ + if ( Noeud->LaCoupeEstSaturee[j] == -1 ) Coupe[NumeroDeCoupe]->UtiliserLaCoupe = OUI; + } + } + else { + /* Le fils droit a ete evalue, il faut descendre d'un cran */ + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + } + } + } + } + } + /* Preparations pour l'etage suivant */ + if( NombreDeNoeudsAExplorerAuProchainEtage == 0 ) break; /* 1- Exploration de l'arbre terminee */ + free( NoeudsAExplorer ); + NoeudsAExplorer = (NOEUD **) malloc( NombreDeNoeudsAExplorerAuProchainEtage * sizeof( void * ) ); + if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_NettoyerLesCoupes 3\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorer = NombreDeNoeudsAExplorerAuProchainEtage; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudsAExplorer[i] = NoeudsAExplorerAuProchainEtage[i]; + } + free( NoeudsAExplorerAuProchainEtage ); +} + +free( NoeudsAExplorerAuProchainEtage ); + +/* On enleve toutes les coupes qui ne sont pas saturees ou qui ne sont pas des lift and project */ +NombreDeNoeudsAExplorer = 1; +NoeudsAExplorer[0] = Bb->NoeudRacine; + +NombreDeCoupesEnlevees = 0; +while( 1 ) { + NoeudsAExplorerAuProchainEtage = (NOEUD **) malloc( NombreDeNoeudsAExplorer * 2 * sizeof( void * ) ); + if ( NoeudsAExplorerAuProchainEtage == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_NettoyerLesCoupes \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorerAuProchainEtage = 0; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudCourant = NoeudsAExplorer[i]; + if ( NoeudCourant != 0 ) { + /* On enleve tout ce qui concerne les coupes mais on conserve les lift and project, les coupes saturees + ainsi que celles qui ont ete generees au noeud racine */ + NbLiftAndProject = 0; + NumeroDeLaPremiereCoupeSupprimee = 0; + if( NoeudCourant->NombreDeCoupesGenereesAuNoeud > 0 ) { + Coupe = NoeudCourant->CoupesGenereesAuNoeud; /* Pointeur sur le tableau de pointeurs sur les coupes */ + + /* On met toutes les lift and project en premier */ + OnInverse = OUI; + while ( OnInverse == OUI ) { + OnInverse = NON; + for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < NoeudCourant->NombreDeCoupesGenereesAuNoeud-1 ; NumeroDeCoupe++ ) { + if ( Coupe[NumeroDeCoupe]->TypeDeCoupe != 'L' && Coupe[NumeroDeCoupe+1]->TypeDeCoupe == 'L' ) { + OnInverse = OUI; + TypeDeCoupe = Coupe[NumeroDeCoupe]->TypeDeCoupe; + Coefficient = Coupe[NumeroDeCoupe]->Coefficient; + IndiceDeLaVariable = Coupe[NumeroDeCoupe]->IndiceDeLaVariable; + UtiliserLaCoupe = Coupe[NumeroDeCoupe]->UtiliserLaCoupe; + /* La coupe NumeroDeCoupe devient de type L */ + /*Coupe[NumeroDeCoupe]->VariableCause = Coupe[NumeroDeCoupe+1]->VariableCause;*/ + Coupe[NumeroDeCoupe]->TypeDeCoupe = Coupe[NumeroDeCoupe+1]->TypeDeCoupe; + Coupe[NumeroDeCoupe]->NombreDeTermes = Coupe[NumeroDeCoupe+1]->NombreDeTermes; + Coupe[NumeroDeCoupe]->Coefficient = Coupe[NumeroDeCoupe+1]->Coefficient; + Coupe[NumeroDeCoupe]->IndiceDeLaVariable = Coupe[NumeroDeCoupe+1]->IndiceDeLaVariable; + Coupe[NumeroDeCoupe]->SecondMembre = Coupe[NumeroDeCoupe+1]->SecondMembre; + Coupe[NumeroDeCoupe]->UtiliserLaCoupe = Coupe[NumeroDeCoupe+1]->UtiliserLaCoupe; + /* La coupe NumeroDeCoupe + 1 devient de type autre que L */ + Coupe[NumeroDeCoupe+1]->TypeDeCoupe = TypeDeCoupe; + Coupe[NumeroDeCoupe+1]->Coefficient = Coefficient; + Coupe[NumeroDeCoupe+1]->IndiceDeLaVariable = IndiceDeLaVariable; + Coupe[NumeroDeCoupe+1]->UtiliserLaCoupe = UtiliserLaCoupe; + } + } + } + for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < NoeudCourant->NombreDeCoupesGenereesAuNoeud; NumeroDeCoupe++ ) { + if ( Coupe[NumeroDeCoupe]->TypeDeCoupe == 'L' ) NbLiftAndProject++; + } + + /* On met maintenant toutes les autres coupes a conserver */ + /* On met toutes les lift and project en premier */ + OnInverse = OUI; + while ( OnInverse == OUI ) { + OnInverse = NON; + for ( NumeroDeCoupe = NbLiftAndProject ; NumeroDeCoupe < NoeudCourant->NombreDeCoupesGenereesAuNoeud-1; NumeroDeCoupe++ ) { + if ( Coupe[NumeroDeCoupe]->UtiliserLaCoupe != OUI && Coupe[NumeroDeCoupe+1]->UtiliserLaCoupe == OUI ) { + OnInverse = OUI; + TypeDeCoupe = Coupe[NumeroDeCoupe]->TypeDeCoupe; + Coefficient = Coupe[NumeroDeCoupe]->Coefficient; + IndiceDeLaVariable = Coupe[NumeroDeCoupe]->IndiceDeLaVariable; + UtiliserLaCoupe = Coupe[NumeroDeCoupe]->UtiliserLaCoupe; + /* La coupe NumeroDeCoupe devient de type L */ + /*Coupe[NumeroDeCoupe]->VariableCause = Coupe[NumeroDeCoupe+1]->VariableCause;*/ + Coupe[NumeroDeCoupe]->TypeDeCoupe = Coupe[NumeroDeCoupe+1]->TypeDeCoupe; + Coupe[NumeroDeCoupe]->NombreDeTermes = Coupe[NumeroDeCoupe+1]->NombreDeTermes; + Coupe[NumeroDeCoupe]->Coefficient = Coupe[NumeroDeCoupe+1]->Coefficient; + Coupe[NumeroDeCoupe]->IndiceDeLaVariable = Coupe[NumeroDeCoupe+1]->IndiceDeLaVariable; + Coupe[NumeroDeCoupe]->SecondMembre = Coupe[NumeroDeCoupe+1]->SecondMembre; + Coupe[NumeroDeCoupe]->UtiliserLaCoupe = Coupe[NumeroDeCoupe+1]->UtiliserLaCoupe; + /* La coupe NumeroDeCoupe + 1 devient de type autre que L */ + Coupe[NumeroDeCoupe+1]->TypeDeCoupe = TypeDeCoupe; + Coupe[NumeroDeCoupe+1]->Coefficient = Coefficient; + Coupe[NumeroDeCoupe+1]->IndiceDeLaVariable = IndiceDeLaVariable; + Coupe[NumeroDeCoupe+1]->UtiliserLaCoupe = UtiliserLaCoupe; + } + } + } + for ( NumeroDeCoupe = NbLiftAndProject ; NumeroDeCoupe < NoeudCourant->NombreDeCoupesGenereesAuNoeud; NumeroDeCoupe++ ) { + if ( Coupe[NumeroDeCoupe]->UtiliserLaCoupe != OUI ) break; + } + + NumeroDeLaPremiereCoupeSupprimee = NumeroDeCoupe; + for ( NumeroDeCoupe = NumeroDeLaPremiereCoupeSupprimee; + NumeroDeCoupe < NoeudCourant->NombreDeCoupesGenereesAuNoeud; + NumeroDeCoupe++ ) { + free( Coupe[NumeroDeCoupe]->Coefficient ); + Coupe[NumeroDeCoupe]->Coefficient = NULL; + free( Coupe[NumeroDeCoupe]->IndiceDeLaVariable ); + Coupe[NumeroDeCoupe]->IndiceDeLaVariable = NULL; + free( Coupe[NumeroDeCoupe] ); + Coupe[NumeroDeCoupe] = NULL; + NombreDeCoupesEnlevees++; + } + if ( NumeroDeLaPremiereCoupeSupprimee <= 0 ) { + free( NoeudCourant->CoupesGenereesAuNoeud ); + NoeudCourant->CoupesGenereesAuNoeud = NULL; + } + else { + NoeudCourant->CoupesGenereesAuNoeud = + (COUPE **) realloc( NoeudCourant->CoupesGenereesAuNoeud , NumeroDeLaPremiereCoupeSupprimee * sizeof( void * ) ); + } + } + + NoeudCourant->NombreDeCoupesGenereesAuNoeud = NumeroDeLaPremiereCoupeSupprimee; /* Et ca sert aussi pour le noeud racine */ + if ( NumeroDeLaPremiereCoupeSupprimee <= 0 ) { + free( NoeudCourant->NumeroDesCoupeAjouteeAuProblemeCourant ); + NoeudCourant->NumeroDesCoupeAjouteeAuProblemeCourant = NULL; + } + else { + NoeudCourant->NumeroDesCoupeAjouteeAuProblemeCourant = + (int *) realloc( NoeudCourant->NumeroDesCoupeAjouteeAuProblemeCourant , NumeroDeLaPremiereCoupeSupprimee * sizeof( int ) ); + } + /* Decompte des types de coupes */ + NoeudCourant->NombreDeG = 0; + NoeudCourant->NombreDeK = 0; + NoeudCourant->NombreDeI = 0; + for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < NoeudCourant->NombreDeCoupesGenereesAuNoeud ; NumeroDeCoupe++ ) { + if ( NoeudCourant->CoupesGenereesAuNoeud[NumeroDeCoupe]->TypeDeCoupe == 'G' ) NoeudCourant->NombreDeG++; + else if ( NoeudCourant->CoupesGenereesAuNoeud[NumeroDeCoupe]->TypeDeCoupe == 'K' ) NoeudCourant->NombreDeK++; + else if ( NoeudCourant->CoupesGenereesAuNoeud[NumeroDeCoupe]->TypeDeCoupe == 'I' ) NoeudCourant->NombreDeI++; + } + + if ( NoeudCourant->NombreDeCoupesExaminees > 0 ) { + free( NoeudCourant->NumeroDesCoupesExaminees ); + NoeudCourant->NumeroDesCoupesExaminees = NULL; + free( NoeudCourant->LaCoupeEstSaturee ); + NoeudCourant->LaCoupeEstSaturee = NULL; + NoeudCourant->NombreDeCoupesExaminees = 0; + } + + if ( NoeudCourant->NombreDeCoupesViolees > 0 ) { + free( NoeudCourant->NumeroDesCoupesViolees ); + NoeudCourant->NumeroDesCoupesViolees = NULL; + NoeudCourant->NombreDeCoupesViolees = 0; + } + + if ( NoeudCourant->StatutDuNoeud == A_EVALUER ) { + /* Du coup, il faut revoir la base de depart de tous les noeuds a evaluer car elle + peut etre singuliere. On dispose d'une base inversible, c'est la base optimale + du noeud racine ou il n'y avait pas de coupes. C'est celle qu'on va mettre dans + tous les noeuds a evaluer */ + memcpy( (char * ) NoeudCourant->PositionDeLaVariable , (char * ) Bb->NoeudRacine->PositionDeLaVariableSansCoupes , + Bb->NombreDeVariablesDuProbleme * sizeof( int ) ); + NoeudCourant->NbVarDeBaseComplementaires = Bb->NoeudRacine->NbVarDeBaseComplementairesSansCoupes; + memcpy( (char * ) NoeudCourant->ComplementDeLaBase , (char * ) Bb->NoeudRacine->ComplementDeLaBaseSansCoupes , + Bb->NoeudRacine->NbVarDeBaseComplementairesSansCoupes * sizeof( int ) ); + } + + /* Renseigner la table des noeuds du prochain etage */ + if ( NoeudCourant != 0 ) { + Noeud = NoeudCourant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage] = Noeud; + NombreDeNoeudsAExplorerAuProchainEtage++; + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage] = Noeud; + NombreDeNoeudsAExplorerAuProchainEtage++; + } + } + } + } + /* Preparations pour l'etage suivant */ + if( NombreDeNoeudsAExplorerAuProchainEtage == 0 ) break; /* 2- Exploration de l'arbre terminee */ + free( NoeudsAExplorer ); + NoeudsAExplorer = (NOEUD **) malloc( NombreDeNoeudsAExplorerAuProchainEtage * sizeof( void * ) ); + if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_NettoyerLesCoupes \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorer = NombreDeNoeudsAExplorerAuProchainEtage; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudsAExplorer[i] = NoeudsAExplorerAuProchainEtage[i]; + } + free( NoeudsAExplorerAuProchainEtage ); +/* fin while */ +} + +free( NoeudsAExplorer ); +free( NoeudsAExplorerAuProchainEtage ); + +#if VERBOSE_BB + printf(" Nombre de coupes enlevees %d \n", NombreDeCoupesEnlevees); +#endif + +/* Si on nettoie vraiment, on recalcule des coupes */ +Bb->NbMaxDeCoupesCalculeesAtteint = NON; + +/*FinNettoyage:*/ + +Bb->NombreTotalDeCoupesDuPoolUtilisees = 0; +Bb->NombreTotalDeGDuPoolUtilisees = 0; +Bb->NombreTotalDeIDuPoolUtilisees = 0; +Bb->NombreTotalDeKDuPoolUtilisees = 0; + +Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes = 0; + +FinNettoyage: + +Bb->EnleverToutesLesCoupesDuPool = NON; + +return; +} + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_rechercher_le_meilleur_minorant.c b/src/ext/Sirius_Solver/branchAndBound/bb_rechercher_le_meilleur_minorant.c new file mode 100644 index 0000000000..1a0a7b6675 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_rechercher_le_meilleur_minorant.c @@ -0,0 +1,177 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/************************************************************************* + + FONCTION: Recherche du meilleur minorant parmi les noeuds evalues + et non elimines. + + AUTEUR: R. GONZALEZ + +**************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_RechercherLeMeilleurMinorant( BB * Bb, char TypeDeRecherche ) +{ +NOEUD ** NoeudsAExplorer; NOEUD ** NoeudsAExplorerAuProchainEtage; NOEUD * Noeud; NOEUD * NoeudCourant; +int NombreDeNoeudsAExplorer; int NombreDeNoeudsAExplorerAuProchainEtage; int i; NOEUD * NoeudDuMeilleurMinorant; +char Continuer; double X; double Xmin; double ValeurDuMeilleurMinorant; double MinorantDuCritereAuNoeud; +double CoutDeLaMeilleureSolutionEntiere; + +NoeudsAExplorer = (NOEUD **) malloc( 1 * sizeof( void * ) ); +if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_RechercherLeMeilleurMinorant \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} +NombreDeNoeudsAExplorer = 1; +NoeudsAExplorer[0] = Bb->NoeudRacine; + +NoeudDuMeilleurMinorant = 0; +Bb->NoeudDuMeilleurMinorant = 0; +CoutDeLaMeilleureSolutionEntiere = Bb->CoutDeLaMeilleureSolutionEntiere; + +ValeurDuMeilleurMinorant = PLUS_LINFINI; /* Pour ne pas avoir de warning a la compilation */ +if ( TypeDeRecherche == RECHERCHER_LE_PLUS_PETIT ) ValeurDuMeilleurMinorant = PLUS_LINFINI; +else if ( TypeDeRecherche == RECHERCHER_LE_PLUS_PETIT_GAP_PROPORTIONNEL ) Xmin = -PLUS_LINFINI; +else { + printf("Bug BB_RechercherLeMeilleurMinorant argument TypeDeRecherche mal iniutialise\n"); + return; +} + +while( 1 ) { + NoeudsAExplorerAuProchainEtage = (NOEUD **) malloc( NombreDeNoeudsAExplorer * 2 * sizeof( void * ) ); + if ( NoeudsAExplorerAuProchainEtage == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_RechercherLeMeilleurMinorant \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorerAuProchainEtage = 0; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudCourant = NoeudsAExplorer[i]; + Continuer = OUI; + if ( NoeudCourant != 0 ) { + if ( NoeudCourant->StatutDuNoeud == EVALUE && NoeudCourant->NoeudTerminal != OUI ) { + MinorantDuCritereAuNoeud = NoeudCourant->MinorantDuCritereAuNoeud; + /* Doit avoir au moins 1 fils a evaluer */ + Noeud = NoeudCourant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud == A_EVALUER ) { + Continuer = NON; + if ( TypeDeRecherche == RECHERCHER_LE_PLUS_PETIT ) { + if ( MinorantDuCritereAuNoeud < ValeurDuMeilleurMinorant && MinorantDuCritereAuNoeud <= CoutDeLaMeilleureSolutionEntiere ) { + ValeurDuMeilleurMinorant = MinorantDuCritereAuNoeud; + NoeudDuMeilleurMinorant = NoeudCourant; + goto Next; + } + } + else { + /* TypeDeRecherche est egaa a RECHERCHER_LE_PLUS_PETIT_GAP_PROPORTIONNEL */ + X = CoutDeLaMeilleureSolutionEntiere - MinorantDuCritereAuNoeud; + X/= NoeudCourant->NbValeursFractionnairesApresResolution; + if ( X > Xmin && MinorantDuCritereAuNoeud <= CoutDeLaMeilleureSolutionEntiere ) { + Xmin = X; + NoeudDuMeilleurMinorant = NoeudCourant; + goto Next; + } + } + } + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud == A_EVALUER ) { + Continuer = NON; + if ( TypeDeRecherche == RECHERCHER_LE_PLUS_PETIT ) { + if ( MinorantDuCritereAuNoeud < ValeurDuMeilleurMinorant && MinorantDuCritereAuNoeud <= CoutDeLaMeilleureSolutionEntiere ) { + ValeurDuMeilleurMinorant = MinorantDuCritereAuNoeud; + NoeudDuMeilleurMinorant = NoeudCourant; + goto Next; + } + } + else { + /* TypeDeRecherche est egaa a RECHERCHER_LE_PLUS_PETIT_GAP_PROPORTIONNEL */ + X = CoutDeLaMeilleureSolutionEntiere - MinorantDuCritereAuNoeud; + X/= NoeudCourant->NbValeursFractionnairesApresResolution; + if ( X > Xmin && MinorantDuCritereAuNoeud <= CoutDeLaMeilleureSolutionEntiere ) { + Xmin = X; + NoeudDuMeilleurMinorant = NoeudCourant; + goto Next; + } + } + } + } + } + /* Renseigner la table des noeuds du prochain etage. Pour descendre d'un cran il faut que les + 2 fils aient ete evalues */ + Next: + if ( Continuer == OUI ) { + Noeud = NoeudCourant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + } + } + } + } + + /* Preparations pour l'etage suivant */ + if( NombreDeNoeudsAExplorerAuProchainEtage == 0 ) break; /* Exploration de l'arbre terminee */ + free( NoeudsAExplorer ); + NoeudsAExplorer = (NOEUD **) malloc( NombreDeNoeudsAExplorerAuProchainEtage * sizeof( void * ) ); + if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_RechercherLeMeilleurMinorant\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorer = NombreDeNoeudsAExplorerAuProchainEtage; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudsAExplorer[i] = NoeudsAExplorerAuProchainEtage[i]; + } + free( NoeudsAExplorerAuProchainEtage ); +/* fin while */ +} + +free( NoeudsAExplorer ); +free( NoeudsAExplorerAuProchainEtage ); + +Bb->NoeudDuMeilleurMinorant = NoeudDuMeilleurMinorant; +if ( Bb->NoeudDuMeilleurMinorant != 0 ) { + if ( TypeDeRecherche == RECHERCHER_LE_PLUS_PETIT ) Bb->ValeurDuMeilleurMinorant = ValeurDuMeilleurMinorant; +} + +return; +} + + + + + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_rechercher_le_noeud_avec_meilleur_ratio_fractionnaire.c b/src/ext/Sirius_Solver/branchAndBound/bb_rechercher_le_noeud_avec_meilleur_ratio_fractionnaire.c new file mode 100644 index 0000000000..9ebbac07a9 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_rechercher_le_noeud_avec_meilleur_ratio_fractionnaire.c @@ -0,0 +1,136 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/************************************************************************* + + FONCTION: Recherche du noeud avec le plus grand ratio : + Nombre de variables a valeur entiere / profondeur du noeud + + AUTEUR: R. GONZALEZ + +**************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*---------------------------------------------------------------------------------------------------------*/ +/* TypeDeRecherche pour choisir le noeud le plus profond ou le noeud avec le moins de variables +fractionnaires */ + +NOEUD * BB_RechercherLeNoeudLeAvecMeilleurRatioFractionnaire( BB * Bb ) +{ +NOEUD ** NoeudsAExplorer; NOEUD ** NoeudsAExplorerAuProchainEtage; NOEUD * Noeud; +NOEUD * NoeudCourant; int NombreDeNoeudsAExplorer; int NombreDeNoeudsAExplorerAuProchainEtage; +int i; NOEUD * NoeudChoisi; char OnPrend; double X; double MeilleurRatio; + +NoeudChoisi = 0; +MeilleurRatio = 1.e+80; + +NoeudsAExplorer = (NOEUD **) malloc( 1 * sizeof( void * ) ); +if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_RechercherUnNouveauNoeudDeDepart \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} +NombreDeNoeudsAExplorer = 1; +NoeudsAExplorer[0] = Bb->NoeudRacine; + +while( 1 ) { + NoeudsAExplorerAuProchainEtage = (NOEUD **) malloc( NombreDeNoeudsAExplorer * 2 * sizeof( void * ) ); + if ( NoeudsAExplorerAuProchainEtage == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_EliminerLesNoeudsSousOptimaux 2 \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorerAuProchainEtage = 0; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudCourant = NoeudsAExplorer[i]; + if ( NoeudCourant != 0 ) { + OnPrend = NON; + if ( NoeudCourant == Bb->NoeudRacine ) goto Next; + X = (double) (Bb->NombreDeVariablesEntieresDuProbleme - NoeudCourant->NbValeursFractionnairesApresResolution); + X/= (double) NoeudCourant->ProfondeurDuNoeud; + if ( NoeudCourant->StatutDuNoeud == EVALUE && NoeudCourant->NoeudTerminal != OUI ) { + /* Doit avoir au moins 1 fils a evaluer */ + Noeud = NoeudCourant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud == A_EVALUER ) { + if ( NoeudChoisi == 0 ) { OnPrend = OUI; goto FinTest; } + else if ( X > MeilleurRatio ) { OnPrend = OUI; goto FinTest; } + } + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud == A_EVALUER ) { + if ( NoeudChoisi == 0 ) { OnPrend = OUI; goto FinTest; } + else if ( X > MeilleurRatio ) { OnPrend = OUI; goto FinTest; } + } + } + FinTest: + if ( OnPrend == OUI ) { + NoeudChoisi = NoeudCourant; + MeilleurRatio = X; + } + } + /* Renseigner la table des noeuds du prochain etage */ + Next: + Noeud = NoeudCourant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + } + } + } + /* Preparations pour l'etage suivant */ + if( NombreDeNoeudsAExplorerAuProchainEtage == 0 ) break; /* Exploration de l'arbre terminee */ + free( NoeudsAExplorer ); + NoeudsAExplorer = (NOEUD **) malloc( NombreDeNoeudsAExplorerAuProchainEtage * sizeof( void * ) ); + if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_EliminerLesNoeudsSousOptimaux 3 \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorer = NombreDeNoeudsAExplorerAuProchainEtage; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudsAExplorer[i] = NoeudsAExplorerAuProchainEtage[i]; + } + free( NoeudsAExplorerAuProchainEtage ); +/* fin while */ +} + +free( NoeudsAExplorer ); +free( NoeudsAExplorerAuProchainEtage ); + +return( NoeudChoisi ); + +} + + + + + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_rechercher_le_noeud_le_moins_fractionnaire.c b/src/ext/Sirius_Solver/branchAndBound/bb_rechercher_le_noeud_le_moins_fractionnaire.c new file mode 100644 index 0000000000..a968dd61d7 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_rechercher_le_noeud_le_moins_fractionnaire.c @@ -0,0 +1,161 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/************************************************************************* + + FONCTION: Recherche du noeud le moins fractionnaire. + + AUTEUR: R. GONZALEZ + +**************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*---------------------------------------------------------------------------------------------------------*/ +/* TypeDeRecherche pour choisir le noeud le plus profond ou le noeud avec le moins de variables +fractionnaires */ + +NOEUD * BB_RechercherLeNoeudLeMoinsFractionnaire( BB * Bb, char TypeDeRecherche ) +{ +NOEUD ** NoeudsAExplorer ; NOEUD ** NoeudsAExplorerAuProchainEtage ; +NOEUD * Noeud ; NOEUD * NoeudCourant ; +int NombreDeNoeudsAExplorer ; int NombreDeNoeudsAExplorerAuProchainEtage; +int i ; +NOEUD * NoeudChoisi; int Profondeur ; int ProfondeurMaxAtteinte; char OnPrend ; +double MinorantDuCritere; double X; + +/* printf("TypeDeRecherche %d\n",TypeDeRecherche); */ + +NoeudChoisi = 0; +ProfondeurMaxAtteinte = -1; +MinorantDuCritere = PLUS_LINFINI; + +NoeudsAExplorer = (NOEUD **) malloc( 1 * sizeof( void * ) ); +if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_RechercherUnNouveauNoeudDeDepart \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} +NombreDeNoeudsAExplorer = 1; +NoeudsAExplorer[0] = Bb->NoeudRacine; + +while( 1 ) { + NoeudsAExplorerAuProchainEtage = (NOEUD **) malloc( NombreDeNoeudsAExplorer * 2 * sizeof( void * ) ); + if ( NoeudsAExplorerAuProchainEtage == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_EliminerLesNoeudsSousOptimaux 2 \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorerAuProchainEtage = 0; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudCourant = NoeudsAExplorer[i]; + if ( NoeudCourant != 0 ) { + OnPrend = NON; + if ( TypeDeRecherche == PROFONDEUR_PURE ) Profondeur = NoeudCourant->ProfondeurDuNoeud; + else if ( TypeDeRecherche == MOINS_DE_VALEURS_FRACTIONNAIRES ) { + Profondeur = Bb->NombreDeVariablesEntieresDuProbleme - NoeudCourant->NbValeursFractionnairesApresResolution; + } + else { + X = (float) Bb->NombreDeVariablesEntieresDuProbleme - NoeudCourant->NormeDeFractionnalite; + X*= (float) Bb->NombreDeVariablesEntieresDuProbleme; + Profondeur = (int) floor( X ); + } + if ( NoeudCourant->StatutDuNoeud == EVALUE && NoeudCourant->NoeudTerminal != OUI ) { + /* Doit avoir au moins 1 fils a evaluer */ + Noeud = NoeudCourant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud == A_EVALUER ) { + if ( Profondeur > ProfondeurMaxAtteinte ) { OnPrend = OUI; goto FinTest; } + else if ( Profondeur == ProfondeurMaxAtteinte ) { + if ( NoeudCourant->MinorantDuCritereAuNoeud < MinorantDuCritere ) { OnPrend = OUI; goto FinTest; } + } + } + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + if ( Noeud->StatutDuNoeud == A_EVALUER ) { + if ( Profondeur > ProfondeurMaxAtteinte ) { OnPrend = OUI; goto FinTest; } + else if (Profondeur == ProfondeurMaxAtteinte ) { + if ( NoeudCourant->MinorantDuCritereAuNoeud < MinorantDuCritere ) { OnPrend = OUI; goto FinTest; } + } + } + } + FinTest: + if ( OnPrend == OUI ) { + NoeudChoisi = NoeudCourant; + ProfondeurMaxAtteinte = NoeudCourant->ProfondeurDuNoeud; + MinorantDuCritere = NoeudCourant->MinorantDuCritereAuNoeud; + } + } + /* Renseigner la table des noeuds du prochain etage */ + /*Next:*/ + Noeud = NoeudCourant->NoeudSuivantGauche; + if ( Noeud != 0 ) { + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if ( Noeud != 0 ) { + NombreDeNoeudsAExplorerAuProchainEtage++; + NoeudsAExplorerAuProchainEtage[NombreDeNoeudsAExplorerAuProchainEtage-1] = Noeud; + } + } + } + /* Preparations pour l'etage suivant */ + if( NombreDeNoeudsAExplorerAuProchainEtage == 0 ) break; /* Exploration de l'arbre terminee */ + free( NoeudsAExplorer ); + NoeudsAExplorer = (NOEUD **) malloc( NombreDeNoeudsAExplorerAuProchainEtage * sizeof( void * ) ); + if ( NoeudsAExplorer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_EliminerLesNoeudsSousOptimaux 3 \n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsAExplorer = NombreDeNoeudsAExplorerAuProchainEtage; + for( i = 0 ; i < NombreDeNoeudsAExplorer ; i++ ) { + NoeudsAExplorer[i] = NoeudsAExplorerAuProchainEtage[i]; + } + free( NoeudsAExplorerAuProchainEtage ); +/* fin while */ +} + +/*FinRechercheNoeudsActifs:*/ + +free( NoeudsAExplorer ); +free( NoeudsAExplorerAuProchainEtage ); + +if ( NoeudChoisi != 0 ) { + /* printf("NbVarFrac du NoeudChoisi = %d\n", NoeudChoisi->NbValeursFractionnairesApresResolution); fflush(stdout); */ +} +else { + /* printf(" Pas de noeud trouve dans la recherche de type %d\n",TypeDeRecherche); */ +} + +return( NoeudChoisi ); + +} + + + + + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_resoudre_le_probleme_relaxe.c b/src/ext/Sirius_Solver/branchAndBound/bb_resoudre_le_probleme_relaxe.c new file mode 100644 index 0000000000..66c7be44af --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_resoudre_le_probleme_relaxe.c @@ -0,0 +1,837 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution d'un probleme relaxe + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +#include "spx_define.h" +#include "spx_fonctions.h" + +#include "pne_define.h" +#include "pne_fonctions.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +#define MISE_EN_SERVICE_DES_COUPES OUI /*OUI*/ +/* En dessous de cette profondeur du noeud on ne calcule plus de coupes */ +/* En pourcentage de la profondeur limite */ +#define PROFONDEUR_LIMITE_POUR_CALCUL_DE_COUPES 0.1 /*0.05*/ /* negatif si profondeur infinie */ +#define SEUIL_PROFONDEUR_LIMITE_1 30 /*30*/ /* Profondeur limite de calcul de coupes tant qu'on n'a pas de solution entiere */ +#define SEUIL_PROFONDEUR_LIMITE_2 10 /*10*/ /* Profondeur limite de calcul de coupes quand on a une solution entiere */ +#define REOPTIMISATION_DU_NOEUD_APRES_COUPES OUI + +#define DERNIER_ROUND_DE_COUPES_AU_NOEUD_RACINE 20 /*20*/ +#define DERNIER_ROUND_DE_COUPES_AUX_AUTRES_NOEUDS 2 + +# define NB_MAX_NOEUDS_ARRET_COUPES 1000 + +# define CYCLE_CALCUL_COUPES 100 +# define CYCLE_CALCUL_COUPES_RAPIDE_1 5 +# define CYCLE_CALCUL_COUPES_RAPIDE_2 2 +# define PROFONDEUR_AUGMENTATION_FREQUENCE_COUPES_1 20 +# define PROFONDEUR_AUGMENTATION_FREQUENCE_COUPES_2 50 + +# define PROFONDEUR_LIMITE_PRUNING_COUPES 100 + +/* Pilotage additionnel du nombre de round de coupes */ +#define POURCENTAGE_VARIATION_CRITERE 0.0001 /*0.0001*/ /* Seuil de variation en pourcentage pour autoriser le rebouclage */ +#define MAX_SI_POURCENTAGE_VARIATION_CRITERE 1 /*10*/ /* Valeur max qui s'applique au pourcentage ci-dessus */ +#define VALEUR_ABSOLUE_VARIATION_CRITERE 0.001 /*0.001*/ /* Seuil de variation en valeur absolue pour autoriser le rebouclage */ + +# define MULTIPLICATEUR_TEMPS 3.0 /*2.0*/ +# define LIMITE_TEMPS 60.0 + +# define FIN_COUPES_NOEUD_RACINE_SUR_TEMPS_MAX NON_PNE /* Si NON_PNE on sort en nombre max d'iterations de simplexe pendant le calcul des coupes */ + +# define MULTIPLICATEUR_NB_ITERATIONS_COUPES_NOEUD_RACINE 1 + +# define MIN_ITERATION_COUPES_NOEUD_RACINE 1000 + +/*---------------------------------------------------------------------------------------------------------*/ +/* Ca retourne OUI_PNE ou NON_Pne-> Si OUI_PNE on archive toutes les coupes y compris celles qui ne sont + pas saturees. Si NON_PNE on n'archive pas les coupes qui ne sont pas saturees */ + +char BB_ArchiverToutesLesCoupesLorsDuTri( BB * Bb ) +{ +char ArchiverToutesLesCoupes; + +if ( MISE_EN_SERVICE_DES_COUPES == NON ) { + ArchiverToutesLesCoupes = NON_PNE; + return( ArchiverToutesLesCoupes ); +} +/* Donc on calcule des coupes */ +if ( REOPTIMISATION_DU_NOEUD_APRES_COUPES == NON ) { + /* Comme on ne reoptimise pas apres le calcul des coupes, on les conserve toutes */ + ArchiverToutesLesCoupes = OUI_PNE; + return( ArchiverToutesLesCoupes ); +} +/* Comme on reoptimise le noeud apres le calcul des coupes, on n'archive que les coupes saturees */ +/* Sauf eventuelle au noeud racine (c'est pas encore tranche) */ + +if ( Bb->NoeudEnExamen == Bb->NoeudRacine ) { + ArchiverToutesLesCoupes = OUI_PNE; + return( ArchiverToutesLesCoupes ); +} +ArchiverToutesLesCoupes = NON_PNE; +if ( Bb->NoeudEnExamen->ProfondeurDuNoeud <= 2 ) ArchiverToutesLesCoupes = OUI_PNE; +return( ArchiverToutesLesCoupes ); +} + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_LeverLeFlagPourEnleverToutesLesCoupes( BB * Bb ) +{ + Bb->EnleverToutesLesCoupesDuPool = OUI; + return; +} + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_LeverLeFlagDeSortieDuSimplexeParDepassementDuCoutMax( BB * Bb ) +{ + Bb->SortieParDepassementDuCoutMax = OUI; + Bb->NombreDeNoeudsElagues++; + Bb->SommeDesProfondeursDElaguage += Bb->NoeudEnExamen->ProfondeurDuNoeud; + return; +} + +/*---------------------------------------------------------------------------------------------------------*/ + +int BB_ResoudreLeProblemeRelaxe( BB * Bb, + NOEUD * NoeudCourant, + int * SolutionEntiereTrouvee + ) +{ +int i; int YaUneSolution; double ValeurOptimale; double Marge; char CalculerDesCoupes; char NumeroDePasse; +int NbCoupesAlloc; char ReFaireUnCalculSansCalculerDesCoupes; int NbVarDeBaseComplementairesSv; int * ComplementDeLaBaseSv; +int * PositionDeLaVariableSv; int YaUneSolutionSv; int MargeAlloc; char RebouclageApresNettoyageDesCoupesFait; +char ChoisirLaVariableAInstancier; char MiseEnServiceDesCoupes; int ProfondeurLimite; char DemandeExpresse; +int DernierRoundDeCoupes; char PremiereResolutionAuNoeudRacine; char ReoptimisationDuNoeudApresCoupes; double AncienneValeurDuCritere; +char YaDesCoupesAjoutees; PROBLEME_PNE * Pne; double TempsEcoule; double X; int CycleCalculCoupes; double LimiteTemps; +double Temps; char PasDeSolutionEntiereDansSousArbre; time_t HeureDeCalendrierDebut; time_t HeureDeCalendrierCourant; +int NbSat; int j; double m; PROBLEME_SPX * Spx; int NbIterationSimplexeCoupes; int MxIterationsSimplexeCoupesNoeudRacine; + +Pne = (PROBLEME_PNE *) Bb->ProblemePneDuBb; + +ReoptimisationDuNoeudApresCoupes = REOPTIMISATION_DU_NOEUD_APRES_COUPES; + +MiseEnServiceDesCoupes = MISE_EN_SERVICE_DES_COUPES; + +CycleCalculCoupes = CYCLE_CALCUL_COUPES; +if ( Bb->NombreDeNoeudsElagues != 0 ) { + if ( (int) ceil( Bb->SommeDesProfondeursDElaguage / Bb->NombreDeNoeudsElagues ) > PROFONDEUR_AUGMENTATION_FREQUENCE_COUPES_2 ) { + CycleCalculCoupes = CYCLE_CALCUL_COUPES_RAPIDE_2; + } + else if ( (int) ceil( Bb->SommeDesProfondeursDElaguage / Bb->NombreDeNoeudsElagues ) > PROFONDEUR_AUGMENTATION_FREQUENCE_COUPES_1 ) { + CycleCalculCoupes = CYCLE_CALCUL_COUPES_RAPIDE_1; + } +} + +/* On force le calcul des coupes au noeud racine */ +if ( NoeudCourant == Bb->NoeudRacine ) MiseEnServiceDesCoupes = OUI; + +if ( PROFONDEUR_LIMITE_POUR_CALCUL_DE_COUPES >= 0.0 ) { + ProfondeurLimite = (int) ceil( PROFONDEUR_LIMITE_POUR_CALCUL_DE_COUPES * Bb->NombreDeVariablesEntieresDuProbleme ); + /* + printf("Bb->NombreDeVariablesEntieresDuProbleme %d ProfondeurLimite %d\n",Bb->NombreDeVariablesEntieresDuProbleme,ProfondeurLimite); + */ + if ( Bb->NoeudDeLaMeilleureSolutionEntiere == 0 ) { + /* On n'a pas encore trouve de solution entiere */ + if ( ProfondeurLimite > SEUIL_PROFONDEUR_LIMITE_1 ) ProfondeurLimite = SEUIL_PROFONDEUR_LIMITE_1; + } + else { + if ( ProfondeurLimite > SEUIL_PROFONDEUR_LIMITE_2 ) ProfondeurLimite = SEUIL_PROFONDEUR_LIMITE_2; + } + if ( NoeudCourant->ProfondeurDuNoeud > ProfondeurLimite ) { + MiseEnServiceDesCoupes = NON; + } +} + +/* Si on a depasse la profondeur limite on calcule des coupes lorsque le nombre de noeuds evalues est multiple + d'un certain nombre */ +if ( Bb->NombreDeSolutionsEntieresTrouvees > 0 || 1 ) { + if ( (Bb->NombreDeProblemesResolus % CycleCalculCoupes) == 0 ) { + MiseEnServiceDesCoupes = OUI; + Bb->CalculerDesCoupes = OUI_PNE; + Bb->CalculerDesCoupesDeGomory = OUI_PNE; + } +} + +/* Test: on calcule des coupes si on est au dessus de l'average pruning depth */ +/* Il faut que le nombre de noeuds elagues soit significatif pour calculer une moyenne */ +if ( Bb->NombreDeNoeudsElagues > 10 && NoeudCourant->ProfondeurDuNoeud < PROFONDEUR_LIMITE_PRUNING_COUPES && 0 ) { + if ( NoeudCourant->ProfondeurDuNoeud < (int) ceil( Bb->SommeDesProfondeursDElaguage / Bb->NombreDeNoeudsElagues ) ) { + MiseEnServiceDesCoupes = OUI; + Bb->CalculerDesCoupes = OUI_PNE; + Bb->CalculerDesCoupesDeGomory = OUI_PNE; + } +} +/* Fin test */ + +DernierRoundDeCoupes = DERNIER_ROUND_DE_COUPES_AU_NOEUD_RACINE; +if ( NoeudCourant != Bb->NoeudRacine ) { + DernierRoundDeCoupes = 1; + if ( REOPTIMISATION_DU_NOEUD_APRES_COUPES == OUI && MiseEnServiceDesCoupes == OUI ) { + DernierRoundDeCoupes = DERNIER_ROUND_DE_COUPES_AUX_AUTRES_NOEUDS; + if ( NoeudCourant->ProfondeurDuNoeud <= 2 ) DernierRoundDeCoupes+= 2; + } +} + +/* Test */ +/* Si le noeud a un minorant a moins de 1% de la meilleure solution, on active le calcul des coupes */ +if ( Bb->NoeudDeLaMeilleureSolutionEntiere != 0 && NoeudCourant != Bb->NoeudRacine && MiseEnServiceDesCoupes == NON ) { + if( fabs( NoeudCourant->MinorantPredit - Bb->CoutDeLaMeilleureSolutionEntiere ) < 0.01 * fabs( Bb->CoutDeLaMeilleureSolutionEntiere ) ) { + MiseEnServiceDesCoupes = OUI; + DernierRoundDeCoupes = 3; + Bb->CalculerDesCoupes = OUI_PNE; + Bb->CalculerDesCoupesDeGomory = OUI_PNE; + } +} +/* Fin test */ + +/* Pas de coupes si pas de variables entieres */ +if ( Bb->NombreDeVariablesEntieresDuProbleme <= 0 ) { + MiseEnServiceDesCoupes = NON; + ReoptimisationDuNoeudApresCoupes = NON; +} + +BB_AfficherLesTraces( Bb, NoeudCourant ); + +if ( Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud >= Bb->NombreMaxDeCoupes ) { + /* Si le nombre moyen de coupes utilisees est trop petit par rapport au nombre de coupes et que le + nombre de coupes est trop grand, on nettoie */ + if ( Bb->AffichageDesTraces == OUI ) { + /*printf("-> Demande de nettoyage des coupes car trop de coupes\n");*/ + } + DemandeExpresse = NON; /* Il vaut mieux mettre NON car ca destabilise la recherche. Le + OUI se justifie dans le cas d'instabilites numeriques ou les coupes + foutent le bordel dans le simplexe */ + + BB_NettoyerLesCoupes( Bb, DemandeExpresse ); +} + +/* Si on utilise trop peu de coupes du pool on nettoie vraiment toutes les coupes a condition qu'il y ait quand-meme + quelques coupes dedans */ +/* Lorsque le pool est plein, il n'est pas judicieux de le nettoyer car cela peut faire baiser des minorants + et bien que l'on puisse calculer de nouvelles coupes, elles sont moins bonnes car ce sont les premieres + qui sont les meilleurs etant donne qu'elles ont ete calculees au sommet de l'arbre */ +if ( Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud > 10 ) { + if ( Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes > 100 ) { + i = (int)(Bb->NombreTotalDeCoupesDuPoolUtilisees/Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes); + /* Si moins de x% des coupes est utilise on nettoie */ + X = 0.01; + if ( ( i * 100. ) / Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud < X /*&& i < 10*/ ) { + if ( Bb->AffichageDesTraces == OUI ) { + printf("Cleaning the pool cuts because too much cuts were flagged as useless\n"); + /* Pour forcer le reaffichage de la legende */ + Bb->NombreDAffichages = CYCLE_DAFFICHAGE_LEGENDE; + } + DemandeExpresse = OUI; + BB_NettoyerLesCoupes( Bb, DemandeExpresse ); + } + } + + /* Si on a arrete le calcul des coupes depuis trop longtemps */ + if ( Bb->NbMaxDeCoupesCalculeesAtteint == OUI ) { + if ( Bb->NombreDeNoeudsEvaluesSansCalculdeCoupes > NB_MAX_NOEUDS_ARRET_COUPES ) { + if ( fabs( Bb->EcartBorneInfALArretDesCoupes - Bb->EcartBorneInf ) < 0.01 * Bb->EcartBorneInfALArretDesCoupes ) { + /*if ( fabs( Bb->EcartBorneInfALArretDesCoupes - Bb->EcartBorneInf ) < 0.5 * Bb->EcartBorneInfALArretDesCoupes ) {*/ + if ( Bb->AffichageDesTraces == OUI ) { + printf("Cleaning the pool cuts to make room for new cuts\n"); + /* Pour forcer le reaffichage de la legende */ + Bb->NombreDAffichages = CYCLE_DAFFICHAGE_LEGENDE; + } + DemandeExpresse = OUI; + BB_NettoyerLesCoupes( Bb, DemandeExpresse ); + Bb->NombreDeNoeudsEvaluesSansCalculdeCoupes = 0; + } + } + } +} + +if ( Bb->NbMaxDeCoupesCalculeesAtteint == OUI ) { + if ( Bb->NombreDeNoeudsEvaluesSansCalculdeCoupes == 0 && Bb->NoeudDeLaMeilleureSolutionEntiere != NULL ) { + Bb->EcartBorneInfALArretDesCoupes = Bb->EcartBorneInf; + } + Bb->NombreDeNoeudsEvaluesSansCalculdeCoupes++; +} + +NbVarDeBaseComplementairesSv = 0; +AncienneValeurDuCritere = 0.0; + +RebouclageApresNettoyageDesCoupesFait = NON; +Bb->SolutionEntiereTrouveeParHeuristique = NON; + +/* Si noeud racine on enclenche un chronometre pour eviter de perde trop de temps dans le + rebouclage */ + +LimiteTemps = 3.0; /* 2.0 */ +if ( Bb->NombreDeVariablesEntieresDuProbleme > 0 ) { + if ( NoeudCourant == Bb->NoeudRacine ) time( &HeureDeCalendrierDebut ); +} + +NbIterationSimplexeCoupes = 0; +MxIterationsSimplexeCoupesNoeudRacine= MIN_ITERATION_COUPES_NOEUD_RACINE; + +DebutGeneral: + +ReFaireUnCalculSansCalculerDesCoupes = NON; +ComplementDeLaBaseSv = NULL; +PositionDeLaVariableSv = NULL; + +Debut: + +if ( Bb->NbMaxDeCoupesCalculeesAtteint == OUI ) { + MiseEnServiceDesCoupes = NON; +} + +Bb->VariableProposeePourLInstanciation = -1; + +/* Ajout des coupes */ +Bb->NombreDeCoupesAjoutees = 0; +BB_InsererLesCoupesDansLeProblemeCourant( Bb, NoeudCourant ); + +free( Bb->CoupeSaturee ); +free( Bb->CoupeSatureeAEntierInf ); +free( Bb->CoupeSatureeAEntierSup ); + +Bb->CoupeSaturee = NULL; +Bb->CoupeSatureeAEntierInf = NULL; +Bb->CoupeSatureeAEntierSup = NULL; + +Bb->MajorantDuNombreDeCoupesAjouteesApresResolutionDuProblemeRelaxe = 0; + +/* Appel du solveur pour la resolution du probleme relaxe */ + +Marge = 0.; +if ( Bb->UtiliserCoutDeLaMeilleureSolutionEntiere == OUI_SPX ) { + Marge = 1.e-6 * fabs ( Bb->CoutDeLaMeilleureSolutionEntiere ); + if ( Marge < 1.e-6 ) Marge = 1.e-6; + if ( Marge > 1.e+1 ) Marge = 1.e+1; +} + +if ( + Bb->UtiliserCoutDeLaMeilleureSolutionEntiere == NON_SPX || + ( + Bb->UtiliserCoutDeLaMeilleureSolutionEntiere == OUI_SPX && + ( NoeudCourant->MinorantPredit < Bb->CoutDeLaMeilleureSolutionEntiere + Marge ) + ) + + ) { + + #if VERBOSE_BB + printf(" Nombre de problemes resolus: %d\n",Bb->NombreDeProblemesResolus); + #endif + + CalculerDesCoupes = Bb->CalculerDesCoupes; + + if ( ReFaireUnCalculSansCalculerDesCoupes == OUI ) { + CalculerDesCoupes = NON_PNE; + } + + /* Inhibition eventuelle */ + if ( MiseEnServiceDesCoupes == NON ) CalculerDesCoupes = NON_PNE; + + Bb->ComplementDeBaseModifie = NON; + NumeroDePasse = 1; + + Bb->NombreDeProblemesDepuisLeDernierAffichage++; + + Bb->ControlerLesCoupesNonInclusesPourUnNouvelleResolution = NON; + if ( MiseEnServiceDesCoupes == NON ) Bb->ControlerLesCoupesNonInclusesPourUnNouvelleResolution = OUI; + + /* Finalement, d'apres les tests, c'etait pas judicuex de mettre OUI */ + Bb->ControlerLesCoupesNonInclusesPourUnNouvelleResolution = NON; + + ResolutionDuNoeud: + + Bb->DernierNoeudResolu = NoeudCourant; + + /* Sauvegarde la base complementaire pour le cas ou on ajouterai des coupes et que ca + convergerait pas ou mal. On ne peut malheureusement pas recuperer le resultat de la + premiere resolution car il ne correspond pas a l'etat de saturation des coupes */ + if ( ReFaireUnCalculSansCalculerDesCoupes == NON && + NumeroDePasse == 1 && + Bb->NombreDeVariablesEntieresDuProbleme > 0 ) { + + ComplementDeLaBaseSv = (int *) malloc( NoeudCourant->NbVarDeBaseComplementaires * sizeof(int) ); + PositionDeLaVariableSv = (int *) malloc( (Bb->NombreDeVariablesDuProbleme /*+ Bb->NombreDeContraintesDuProbleme*/) * sizeof(int) ); + if ( ComplementDeLaBaseSv == NULL || PositionDeLaVariableSv == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_ResoudreLeProblemeRelaxe\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + for ( i = 0 ; i < Bb->NombreDeVariablesDuProbleme /*+ Bb->NombreDeContraintesDuProbleme*/ ; i++ ) { + PositionDeLaVariableSv[i] = NoeudCourant->PositionDeLaVariable[i]; + } + for ( i = 0 ; i < NoeudCourant->NbVarDeBaseComplementaires ; i++ ) { + ComplementDeLaBaseSv[i] = NoeudCourant->ComplementDeLaBase[i]; + } + NbVarDeBaseComplementairesSv = NoeudCourant->NbVarDeBaseComplementaires; + + } + + Bb->SortieParDepassementDuCoutMax = NON; + Bb->NombreDeProblemesRelaxesResolus++; + + ChoisirLaVariableAInstancier = OUI_PNE; + if ( MiseEnServiceDesCoupes == OUI && ReFaireUnCalculSansCalculerDesCoupes == NON ) { + if ( ReoptimisationDuNoeudApresCoupes == OUI ) { + if ( NumeroDePasse != DernierRoundDeCoupes ) ChoisirLaVariableAInstancier = NON_PNE; + } + } + + /* Car ChoisirLaVariableAInstancier a pu etre mis a non juste au dessus */ + if ( CalculerDesCoupes == NON_PNE && Bb->NombreDeVariablesEntieresDuProbleme > 0 ) ChoisirLaVariableAInstancier = OUI_PNE; + + PremiereResolutionAuNoeudRacine = NON_PNE; + if ( Bb->NoeudEnExamen == Bb->NoeudRacine ) { + if ( NumeroDePasse == 1 ) PremiereResolutionAuNoeudRacine = OUI_PNE; + } + + if ( Bb->AffichageDesTraces == OUI_PNE ) { + if ( Bb->NoeudEnExamen == Bb->NoeudRacine ) { + if ( NumeroDePasse > 1 && NumeroDePasse != DernierRoundDeCoupes ) printf("Root node: new round of cuts\n"); + } + } + + PNE_BranchAndBoundSolvePbRlx( Pne, + PremiereResolutionAuNoeudRacine, + NumeroDePasse, + &CalculerDesCoupes, + ChoisirLaVariableAInstancier, + &NoeudCourant->NombreDeVariablesEntieresInstanciees, + NoeudCourant->IndicesDesVariablesEntieresInstanciees, + NoeudCourant->ValeursDesVariablesEntieresInstanciees, + /* Specifique simplexe */ + &Bb->CoutDeLaMeilleureSolutionEntiere, + &Bb->UtiliserCoutDeLaMeilleureSolutionEntiere, + &NoeudCourant->BaseFournie, + NoeudCourant->PositionDeLaVariable, + &NoeudCourant->NbVarDeBaseComplementaires, + NoeudCourant->ComplementDeLaBase, + /* */ + &ValeurOptimale, + &YaUneSolution, + SolutionEntiereTrouvee, + &Bb->VariableProposeePourLInstanciation, + &Bb->MinorantEspereAEntierInf, + &Bb->MinorantEspereAEntierSup, + Bb->ValeursCalculeesDesVariablesEntieresPourLeProblemeRelaxeCourant, + Bb->ValeursCalculeesDesVariablesPourLeProblemeRelaxeCourant, + /* Bases de depart associees ŕ la variable proposée pour l'instanciation */ + Bb->PositionDeLaVariableAEntierInf , + &Bb->NbVarDeBaseComplementairesAEntierInf, + Bb->ComplementDeLaBaseAEntierInf , + Bb->PositionDeLaVariableAEntierSup , + &Bb->NbVarDeBaseComplementairesAEntierSup, + Bb->ComplementDeLaBaseAEntierSup , + /* Indicateur de disponibilite des bases pour les fils */ + &Bb->BasesFilsDisponibles + ); + if ( Bb->NombreDeVariablesEntieresDuProbleme <= 0 ) goto FinResolutionDuProblemeRelaxe; + + /* S'il s'agit du noeud racine et que c'est la premiere optimisation ( sans coupes ) on stocke la base */ + if ( Bb->NoeudEnExamen == Bb->NoeudRacine && NumeroDePasse == 1 && YaUneSolution == OUI ) { + + Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur; + if ( MULTIPLICATEUR_NB_ITERATIONS_COUPES_NOEUD_RACINE * Spx->Iteration > MxIterationsSimplexeCoupesNoeudRacine ) { + MxIterationsSimplexeCoupesNoeudRacine = MULTIPLICATEUR_NB_ITERATIONS_COUPES_NOEUD_RACINE * Spx->Iteration; + } + + time( &HeureDeCalendrierCourant ); + Temps = difftime( HeureDeCalendrierCourant, HeureDeCalendrierDebut ); + if ( Temps <= 1.0 ) Temps = 1.0; + LimiteTemps = Temps * MULTIPLICATEUR_TEMPS; + if ( LimiteTemps > Temps + LIMITE_TEMPS ) LimiteTemps = Temps + LIMITE_TEMPS; + + /* Autre methode car celle-ci ne donne pas satisfaction */ + if ( Temps > LIMITE_TEMPS ) LimiteTemps = Temps; + else LimiteTemps = LIMITE_TEMPS; + /* On reinitialise le compteur */ + time( &HeureDeCalendrierDebut ); + + Bb->BaseDisponibleAuNoeudRacine = OUI; + memcpy( (char * ) Bb->NoeudRacine->PositionDeLaVariableSansCoupes , (char * ) Bb->NoeudRacine->PositionDeLaVariable , + Bb->NombreDeVariablesDuProbleme * sizeof( int ) ); + Bb->NoeudRacine->NbVarDeBaseComplementairesSansCoupes = Bb->NoeudRacine->NbVarDeBaseComplementaires; + memcpy( (char * ) Bb->NoeudRacine->ComplementDeLaBaseSansCoupes , (char * ) Bb->NoeudRacine->ComplementDeLaBase , + Bb->NoeudRacine->NbVarDeBaseComplementaires * sizeof( int ) ); + } + + if ( Bb->NoeudEnExamen == Bb->NoeudRacine && NumeroDePasse > 1 && YaUneSolution == OUI ) { + + NbSat = 0; + for ( j = 0 ; j < Pne->Coupes.NombreDeContraintes ; j++ ) { + if ( Pne->Coupes.PositionDeLaVariableDEcart[j] != EN_BASE ) NbSat++; + } + + Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur; + NbIterationSimplexeCoupes += Spx->Iteration; + + # if FIN_COUPES_NOEUD_RACINE_SUR_TEMPS_MAX != OUI_PNE + if ( Bb->AffichageDesTraces == OUI_PNE && CalculerDesCoupes == OUI_PNE ) { + printf("..Root cutting: simplexe iterations count %d max. is %d\n",NbIterationSimplexeCoupes,MxIterationsSimplexeCoupesNoeudRacine); + } + # endif + + if ( Bb->AffichageDesTraces == OUI_PNE && CalculerDesCoupes == OUI_PNE ) { + if ( fabs( AncienneValeurDuCritere ) > 1.e-9 ) { + printf("..Root cutting increases lower bound by: %e (relative is %e %%)\n",fabs( Pne->Critere - AncienneValeurDuCritere ), + fabs( (Pne->Critere - AncienneValeurDuCritere) / (0.01 * AncienneValeurDuCritere) ) ); + } + else { + printf("..Root cutting increases lower bound by: %e\n",fabs( Pne->Critere - AncienneValeurDuCritere ) ); + } + printf("..Found %d cuts of which %d are tight\n",Pne->Coupes.NombreDeContraintes,NbSat); + } + } + + /* Si on n'a pas calcule de coupes, on controle la violation des coupes du pool. Si des coupes + sont violees, on les ajoute dans le probleme et on reoptimise */ + if ( Bb->ControlerLesCoupesNonInclusesPourUnNouvelleResolution == OUI && YaUneSolution == OUI ) { + BB_ControlerLesCoupesNonInsereesInitialement( Bb, &YaDesCoupesAjoutees ); + if ( YaDesCoupesAjoutees == OUI ) { + printf("Rebouclage vers une nouvelle resolution du noeud car des coupes du pool ont ete ajoutees\n"); + NumeroDePasse++; + goto ResolutionDuNoeud; + } + } + + /* Si on a calcule des coupes, on reoptimise le meme noeud */ + if ( ReoptimisationDuNoeudApresCoupes == OUI ) { + if ( CalculerDesCoupes == OUI_PNE && YaUneSolution == OUI ) { + NumeroDePasse++; + if ( NumeroDePasse == DernierRoundDeCoupes ) CalculerDesCoupes = NON_PNE; + Bb->ComplementDeBaseModifie = NON; + NoeudCourant->BaseFournie = OUI_SPX; + /* NumeroDePasse vaut 2 apres la premiere resolution du noeud */ + if ( NumeroDePasse > 2 ) { + /* Si le critere n'a pas beaucoup bouge, on arrete le calcul des coupes, on evalue le noeud une derniere fois + pour choisir la variable a instancier */ + /* 1- Calcul en pourcentage */ + if ( fabs( Pne->Critere - AncienneValeurDuCritere ) < fabs( POURCENTAGE_VARIATION_CRITERE * Pne->Critere ) && Bb->NoeudEnExamen != Bb->NoeudRacine && 0 ) { + /* Le critere n'a pas assez varie en relatif => on arrete le calcul des coupes */ + /* + printf("Le critere n'a pas assez varie en relatif => on arrete le calcul des coupes Pne->Critere - AncienneValeurDuCritere %e\n", + Pne->Critere - AncienneValeurDuCritere); + */ + if ( fabs( Pne->Critere - AncienneValeurDuCritere ) < MAX_SI_POURCENTAGE_VARIATION_CRITERE ) { + CalculerDesCoupes = NON_PNE; + /* Et pour pouvoir faire le strong branching */ + NumeroDePasse = DernierRoundDeCoupes; + } + } + /* 2- Calcul en valeur absolue pour le cas des petites valeurs de criteres */ + if ( CalculerDesCoupes == OUI_PNE ) { + if ( fabs( Pne->Critere - AncienneValeurDuCritere ) < VALEUR_ABSOLUE_VARIATION_CRITERE ) { + /* Le critere n'a pas assez varie en valeur absolue => on arrete le calcul des coupes */ + /* + printf("Le critere n'a pas assez varie en valeur absolue => on arrete le calcul des coupes Pne->Critere - AncienneValeurDuCritere %e\n", + Pne->Critere - AncienneValeurDuCritere); + */ + CalculerDesCoupes = NON_PNE; + /* Et pour pouvoir faire le strong branching */ + NumeroDePasse = DernierRoundDeCoupes; + } + } + + /* Sortie si on a deja passe trop de temps ou Nb max d'iterations */ + if ( Bb->NombreDeVariablesEntieresDuProbleme > 0 ) { + if ( NoeudCourant == Bb->NoeudRacine && NumeroDePasse >= 2 ) { + # if FIN_COUPES_NOEUD_RACINE_SUR_TEMPS_MAX == OUI_PNE + time( &HeureDeCalendrierCourant ); + Temps = difftime( HeureDeCalendrierCourant, HeureDeCalendrierDebut ); + + m = Bb->ToleranceDOptimalite * 0.01 * fabs( Pne->Critere ); + if ( m < VALEUR_ABSOLUE_VARIATION_CRITERE ) m = VALEUR_ABSOLUE_VARIATION_CRITERE; + /* On continue si le critere decroit */ + if ( fabs( Pne->Critere - AncienneValeurDuCritere ) > m ) { + if ( Bb->AffichageDesTraces == OUI_PNE ) { + if ( Temps > LimiteTemps ) printf("..time limit for root cutting was reached but continuing because lower bound still increasing\n"); + } + Temps = LimiteTemps - 1; + } + if ( Temps > LimiteTemps ) { + CalculerDesCoupes = NON_PNE; + /* Et pour pouvoir faire le strong branching */ + NumeroDePasse = DernierRoundDeCoupes; + if ( Bb->AffichageDesTraces == OUI_PNE ) { + printf("Root node cutting planes stopped because time limit was reached: computing time is %e , limit is %e\n",Temps,LimiteTemps); + } + } + # else + /* On sort sur nombre max d'iterations */ + if ( NbIterationSimplexeCoupes > MxIterationsSimplexeCoupesNoeudRacine ) { + m = Bb->ToleranceDOptimalite * 0.01 * fabs( Pne->Critere ); + if ( m < VALEUR_ABSOLUE_VARIATION_CRITERE ) m = VALEUR_ABSOLUE_VARIATION_CRITERE; + /* On continue si le critere decroit */ + if ( fabs( Pne->Critere - AncienneValeurDuCritere ) > m ) { + if ( Bb->AffichageDesTraces == OUI_PNE ) { + printf("..iteration limit for root cutting was reached but continuing because lower bound still increasing\n"); + } + } + else { + CalculerDesCoupes = NON_PNE; + /* Et pour pouvoir faire le strong branching */ + NumeroDePasse = DernierRoundDeCoupes; + if ( Bb->AffichageDesTraces == OUI_PNE ) { + printf("Root node cutting planes stopped because iteration limit was reached: iteration count is %d, limit is %d\n", + NbIterationSimplexeCoupes,MxIterationsSimplexeCoupesNoeudRacine); + } + } + } + + # endif + } + } + + } + AncienneValeurDuCritere = Pne->Critere; + /* On annule la prise en compte des coupes non saturees */ + if ( Bb->NoeudEnExamen == Bb->NoeudRacine ) PNE_ActualiserLesCoupesAPrendreEnCompte( Pne ); + + goto ResolutionDuNoeud; + } + } + + /* Tri des coupes (celles d'avant et celles qui ont ete creees) */ + ReFaireUnCalculSansCalculerDesCoupes = NON; + YaUneSolutionSv = YaUneSolution; + if ( YaUneSolution == NON && NumeroDePasse > 1 ) { + /* Cela signifie que les coupes ajoutees on fait diverger le simplexe car elles etaient mal + fichues => on peut utiliser le resultat de la premiere passe */ + /* Ce qui aura pour effet de simplement de liberer les tableaux de coupes dans la pne, mais on n'en + stockera pas */ + YaUneSolution = OUI; + YaUneSolutionSv = OUI; + /* Si on est a une resolution qui a "echoue" apres l'ajout de coupes, on relance + le calcul en interdisant absolument le calcul des coupes. Ainsi on pourra beneficier du + strong branching pour le choix de la variable a instancier */ + if( Bb->SortieParDepassementDuCoutMax != OUI ) ReFaireUnCalculSansCalculerDesCoupes = OUI; + else YaUneSolutionSv = NON; + } + + NbCoupesAlloc = Bb->NombreDeCoupesAjoutees + Bb->MajorantDuNombreDeCoupesAjouteesApresResolutionDuProblemeRelaxe; + MargeAlloc = NbCoupesAlloc + 1 /*1*/; + NbCoupesAlloc+= MargeAlloc; + + Bb->CoupeSaturee = (char *) malloc( NbCoupesAlloc * sizeof(char) ); + Bb->CoupeSatureeAEntierInf = (char *) malloc( NbCoupesAlloc * sizeof(char) ); + Bb->CoupeSatureeAEntierSup = (char *) malloc( NbCoupesAlloc * sizeof(char) ); + if ( Bb->CoupeSaturee == NULL || Bb->CoupeSatureeAEntierInf == NULL || Bb->CoupeSatureeAEntierSup == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_ResoudreLeProblemeRelaxe\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + + PNE_TrierLesCoupesCalculees( Pne, + YaUneSolution, + Bb->BasesFilsDisponibles, + ReoptimisationDuNoeudApresCoupes, + Bb->CoupeSaturee, + Bb->CoupeSatureeAEntierInf, + Bb->CoupeSatureeAEntierSup + ); + + YaUneSolution = YaUneSolutionSv; +} +else { + Bb->NombreDeProblemesRelaxesResolus++; + Bb->DernierNoeudResolu = 0; + YaUneSolution = NON; +} + +if ( ReFaireUnCalculSansCalculerDesCoupes == OUI ) { + /* Il faut recuperer les informations sur les variables basiques complementaires du probleme + avant l'ajout des nouvelles coupes: attention les tables de sauvegarde ne sont pas valables + s'il s'agit du noeud racine */ + if ( Bb->NoeudEnExamen != Bb->NoeudRacine ) { + for ( i = 0 ; i < Bb->NombreDeVariablesDuProbleme /*+ Bb->NombreDeContraintesDuProbleme*/ ; i++ ) { + NoeudCourant->PositionDeLaVariable[i] = PositionDeLaVariableSv[i]; + } + for ( i = 0 ; i < NbVarDeBaseComplementairesSv ; i++ ) { + NoeudCourant->ComplementDeLaBase[i] = ComplementDeLaBaseSv[i]; + } + NoeudCourant->NbVarDeBaseComplementaires = NbVarDeBaseComplementairesSv; + } + else { + if ( Bb->BaseDisponibleAuNoeudRacine == OUI ) { + NoeudCourant->BaseFournie = OUI_SPX; + for ( i = 0 ; i < Bb->NombreDeVariablesDuProbleme ; i++ ) { + NoeudCourant->PositionDeLaVariable[i] = Bb->NoeudRacine->PositionDeLaVariableSansCoupes[i]; + } + for ( i = 0 ; i < Bb->NoeudRacine->NbVarDeBaseComplementairesSansCoupes ; i++ ) { + NoeudCourant->ComplementDeLaBase[i] = Bb->NoeudRacine->ComplementDeLaBaseSansCoupes[i]; + } + NoeudCourant->NbVarDeBaseComplementaires = Bb->NoeudRacine->NbVarDeBaseComplementairesSansCoupes; + } + else { + NoeudCourant->BaseFournie = NON_SPX; + } + } + goto Debut; /* Juste pour pouvoir faire du strong branching */ +} + +#if VERBOSE_BB + if ( Bb->NombreDeVariablesEntieresDuProbleme > 0 ) { + printf(" BasesFilsDisponibles %d \n",Bb->BasesFilsDisponibles); + printf(" MinorantEspereAEntierInf %e \n",Bb->MinorantEspereAEntierInf); + printf(" MinorantEspereAEntierSup %e \n",Bb->MinorantEspereAEntierSup); + } +#endif + +FinResolutionDuProblemeRelaxe: + +Bb->NombreDeProblemesResolus++; +Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes++; + +if(YaUneSolution == OUI) { + NoeudCourant->NbValeursFractionnairesApresResolution = Pne->NombreDeVariablesAValeurFractionnaire; +} +else { + *SolutionEntiereTrouvee = NON; + ValeurOptimale = PLUS_LINFINI; + #if VERBOSE_BB + printf("Pas de solution au probleme relaxe du noeud \n"); + #endif +} + +NoeudCourant->MinorantDuCritereAuNoeud = ValeurOptimale; +NoeudCourant->LaSolutionRelaxeeEstEntiere = *SolutionEntiereTrouvee; + +/* +printf("Nombre de variables entieres relaxees se trouvant sur une borne: %d \n",Bb->NombreDeVariablesFixeesEnSortie); +*/ + +time( &(Pne->HeureDeCalendrierCourant) ); +TempsEcoule = difftime( Pne->HeureDeCalendrierCourant , Pne->HeureDeCalendrierDebut ); +if ( TempsEcoule <= 0.0 ) TempsEcoule = 0.0; + +if ( Bb->NombreDeVariablesEntieresDuProbleme > 0 ) { + if ( NoeudCourant->LaSolutionRelaxeeEstEntiere == OUI ) { + X = 0.; + if ( Bb->ProfondeurMoyenneDesSolutionsEntieres >= 0 ) { + X = Bb->ProfondeurMoyenneDesSolutionsEntieres * Bb->NombreDeSolutionsEntieresTrouvees; + } + X += NoeudCourant->ProfondeurDuNoeud; + Bb->NombreDeSolutionsEntieresTrouvees++; + X /= Bb->NombreDeSolutionsEntieresTrouvees; + Bb->ProfondeurMoyenneDesSolutionsEntieres = (int) ceil( X ); + } + if ( NoeudCourant == Bb->NoeudRacine && Bb->AffichageDesTraces == OUI ) { + if ( YaUneSolution == OUI ) { + printf("\n"); + printf("** Root node, internal cost: %16.9e , elapsed time: %7d seconds\n", + NoeudCourant->MinorantDuCritereAuNoeud, (int) TempsEcoule); + printf("\n"); + printf("** Starting the tree search **\n"); + } + else { + printf("\n"); + printf("** No solution found, elapsed time: %7d seconds\n", (int) TempsEcoule); + printf("\n"); + } + } +} +else if ( Bb->AffichageDesTraces == OUI) { + if ( YaUneSolution == OUI ) { + printf("\n"); + printf("** Solution found, internal cost: %16.9e , elapsed time: %7d seconds\n", + NoeudCourant->MinorantDuCritereAuNoeud, (int) TempsEcoule); + printf("\n"); + } + else { + printf("\n"); + printf("** No solution found, elapsed time: %7d seconds\n", (int) TempsEcoule); + printf("\n"); + } +} + +free( ComplementDeLaBaseSv ); +free( PositionDeLaVariableSv ); +ComplementDeLaBaseSv = NULL; +PositionDeLaVariableSv = NULL; + +/* Si on doit nettoyer toutes les coupes c'est qu'elles sont devenues merdiques et donc on relance sans les coupes */ +if ( Bb->EnleverToutesLesCoupesDuPool == OUI ) { + if ( Bb->AffichageDesTraces == OUI ) { + printf("Trying to clean the pool cuts for numerical stability reasons\n"); + /* Pour forcer le reaffichage de la legende */ + Bb->NombreDAffichages = CYCLE_DAFFICHAGE_LEGENDE; + } + DemandeExpresse = OUI; + BB_NettoyerLesCoupes( Bb, DemandeExpresse ); + if ( RebouclageApresNettoyageDesCoupesFait == NON ) { + RebouclageApresNettoyageDesCoupesFait = OUI; + goto DebutGeneral; + } +} + +/* Calcul de la taille du pool. S'il est trop grand on arrete le calcul des coupes */ +if ( Bb->NbMaxDeCoupesCalculeesAtteint != OUI ) { + { + COUPE ** Coupe; int NumeroDeCoupe; int TailleDuPool; + TailleDuPool = 0; + Coupe = Bb->NoeudRacine->CoupesGenereesAuNoeud; + for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < Bb->NoeudRacine->NombreDeCoupesGenereesAuNoeud ; NumeroDeCoupe++ ) { + TailleDuPool+= Coupe[NumeroDeCoupe]->NombreDeTermes * sizeof( int ); + TailleDuPool+= Coupe[NumeroDeCoupe]->NombreDeTermes * sizeof( double ); + } + if ( TailleDuPool >= TAILLE_MAXI_DU_POOL_DE_COUPES ) { + if ( Bb->AffichageDesTraces == OUI ) { + printf("Pool cuts is full\n"); + } + Bb->NbMaxDeCoupesCalculeesAtteint = OUI; + } + } +} + +if ( YaUneSolution == OUI && ChoisirLaVariableAInstancier == 0 ) { + if ( *SolutionEntiereTrouvee == NON ) { + printf("!!!!!!!! Attention Bug dans la partie Branche and Bound (ResoudreLeProblemeRelaxe) ChoisirLaVariableAInstancier = 0 et on va continuer !!!\n"); + /*exit(0);*/ + } +} + +/* S'il y a une solution on tente l'heuristique */ +if ( YaUneSolution == OUI && *SolutionEntiereTrouvee == NON ) { + PasDeSolutionEntiereDansSousArbre = NON; + PNE_HeuristiquePilotage( Pne, &PasDeSolutionEntiereDansSousArbre ); + if ( PasDeSolutionEntiereDansSousArbre == OUI_PNE ) YaUneSolution = NON; +} + +return( YaUneSolution ); /* OUI s'il y a une solution, NON sinon */ +} + + + + + + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_stocker_les_coupes_du_noeud.c b/src/ext/Sirius_Solver/branchAndBound/bb_stocker_les_coupes_du_noeud.c new file mode 100644 index 0000000000..fb12d7a4f1 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_stocker_les_coupes_du_noeud.c @@ -0,0 +1,119 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Stockage des coupes generees en un noeud, ce module est + appele par le calcul des coupes a chaque fois qu'une coupe + est disponible + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*---------------------------------------------------------------------------------------------------------*/ + +void BB_StockerUneCoupeGenereeAuNoeud( BB * Bb, + int NombreDeTermes, + double * Coefficient, + int * IndiceDeLaVariable, + double SecondMembre, + char TypeDeCoupe ) +{ +int i; int IndiceDeCoupe; NOEUD * NoeudCourant; +/* +printf("Partie BRANCH AND BOUND, STOCKAGE de la coupe \n"); +*/ +NoeudCourant = Bb->NoeudEnExamen; + +/* On Stocke toutes les coupes au noeud racine */ +NoeudCourant = Bb->NoeudRacine; + +IndiceDeCoupe = NoeudCourant->NombreDeCoupesGenereesAuNoeud; + + /* Premiere allocation de structure */ +if ( IndiceDeCoupe == 0 ) { + NoeudCourant->CoupesGenereesAuNoeud = (COUPE **) malloc( ( IndiceDeCoupe + 1 ) * sizeof( void * ) ); + NoeudCourant->NumeroDesCoupeAjouteeAuProblemeCourant = (int *) malloc( ( IndiceDeCoupe + 1 ) * sizeof( int ) ); +} +else { + NoeudCourant->CoupesGenereesAuNoeud = (COUPE **) realloc( NoeudCourant->CoupesGenereesAuNoeud , + ( IndiceDeCoupe + 1 ) * sizeof( void * ) ); + NoeudCourant->NumeroDesCoupeAjouteeAuProblemeCourant = (int *) realloc( NoeudCourant->NumeroDesCoupeAjouteeAuProblemeCourant , + ( IndiceDeCoupe + 1 ) * sizeof( int ) ); +} +if ( NoeudCourant->CoupesGenereesAuNoeud == NULL || NoeudCourant->NumeroDesCoupeAjouteeAuProblemeCourant == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_StockerUneCoupeGenereeAuNoeud 1\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} + +/* Stockage de la coupe */ +NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe] = (COUPE *) malloc( sizeof( COUPE ) ); +if ( NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe] == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_StockerUneCoupeGenereeAuNoeud 2\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} + +/*NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->VariableCause = VariableCause;*/ +NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->TypeDeCoupe = TypeDeCoupe; +if ( Bb->NoeudEnExamen == Bb->NoeudRacine ) { + NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->CoupeRacine = OUI; +} +else { + NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->CoupeRacine = NON; +} +NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->NombreDeTermes = NombreDeTermes; +NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->SecondMembre = SecondMembre; + +NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->Coefficient = (double *) malloc( NombreDeTermes * sizeof( double ) ); +NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->IndiceDeLaVariable = (int *) malloc( NombreDeTermes * sizeof( int ) ); +if ( NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->Coefficient == NULL || + NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->IndiceDeLaVariable == NULL) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_StockerUneCoupeGenereeAuNoeud\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} + +for ( i = 0 ; i < NombreDeTermes ; i++ ) { + NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->Coefficient[i] = Coefficient[i]; + NoeudCourant->CoupesGenereesAuNoeud[IndiceDeCoupe]->IndiceDeLaVariable[i] = IndiceDeLaVariable[i]; +} + +NoeudCourant->NumeroDesCoupeAjouteeAuProblemeCourant[Bb->NombreDeCoupesAjoutees] = NoeudCourant->NombreDeCoupesGenereesAuNoeud; + +/* Mise a jour du nombre de coupes */ +NoeudCourant->NombreDeCoupesGenereesAuNoeud++; +if ( TypeDeCoupe == 'G' ) NoeudCourant->NombreDeG++; +else if ( TypeDeCoupe == 'K' ) NoeudCourant->NombreDeK++; +else if ( TypeDeCoupe == 'I' ) NoeudCourant->NombreDeI++; + +Bb->NombreDeCoupesAjoutees++; + +return; +} + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_supprimer_les_descendants_dun_noeud.c b/src/ext/Sirius_Solver/branchAndBound/bb_supprimer_les_descendants_dun_noeud.c new file mode 100644 index 0000000000..d2bb566095 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_supprimer_les_descendants_dun_noeud.c @@ -0,0 +1,167 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +#include "bb_sys.h" +#include "bb_define.h" +#include "bb_fonctions.h" + +# ifdef BB_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "bb_memoire.h" +# endif + +/*-----------------------------------------------------------------------------------------------------------------*/ +/* + Suppression physique d'un sous-arbre a partir de NoeudDeDepart. Le noeud NoeudDeDepart n'est + pas supprime, il est marque comme noeud terminal. +*/ + +void BB_SupprimerTousLesDescendantsDUnNoeud( BB * Bb, NOEUD * NoeudDeDepart ) +{ +int i ; int ProfondeurRelative ; +NOEUD ** NoeudsASupprimer ; NOEUD ** NoeudsASupprimerAuProchainEtage ; +int NombreDeNoeudsASupprimer ; int NombreDeNoeudsASupprimerAuProchainEtage; +NOEUD * NoeudCourant ; NOEUD * Noeud ; +int Fois ; int OnSupprime ; + +Fois = 1; +OnSupprime = OUI; + +Debut: + +if ( Fois == 2 ) NoeudDeDepart->NoeudTerminal = OUI; + +ProfondeurRelative = 1; +NoeudsASupprimer = (NOEUD **) malloc( 2 * sizeof( void * ) ); +if ( NoeudsASupprimer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_SupprimerTousLesDescendantsDUnNoeud 1\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); +} +NombreDeNoeudsASupprimer = 2; +NoeudsASupprimer[0] = NoeudDeDepart->NoeudSuivantGauche; +NoeudsASupprimer[1] = NoeudDeDepart->NoeudSuivantDroit; +/* Pour indiquer que NoeudDeDepart n'a plus de fils apres suppression de ses fils */ + +if ( Fois == 2 ) { + NoeudDeDepart->NoeudSuivantGauche = 0; + NoeudDeDepart->NoeudSuivantDroit = 0; +} + +Bb->NbNoeuds1_PNE_SupprimerTousLesDescendantsDUnNoeud = NombreDeNoeudsASupprimer; /* Pour le nettoyage eventuel */ +Bb->Liste1_PNE_SupprimerTousLesDescendantsDUnNoeud = NoeudsASupprimer; /* Pour le nettoyage eventuel */ + +while( 1 ) { + ProfondeurRelative++; + NoeudsASupprimerAuProchainEtage = (NOEUD **) malloc( NombreDeNoeudsASupprimer * 2 * sizeof( void * ) ); + if ( NoeudsASupprimerAuProchainEtage == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_SupprimerTousLesDescendantsDUnNoeud 2\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsASupprimerAuProchainEtage = 0; + + Bb->NbNoeuds2_PNE_SupprimerTousLesDescendantsDUnNoeud = 0; /* Pour le nettoyage eventuel */ + Bb->Liste2_PNE_SupprimerTousLesDescendantsDUnNoeud = NoeudsASupprimerAuProchainEtage; /* Pour le nettoyage eventuel */ + + for( i = 0 ; i < NombreDeNoeudsASupprimer ; i++ ) { + NoeudCourant = NoeudsASupprimer[i]; + if( NoeudCourant != 0 ) { + if ( Fois == 1 ) { + if ( NoeudCourant == Bb->NoeudEnExamen ) { OnSupprime = NON; goto FinSuppression; } + } + /* Renseigner la table des noeuds du prochain etage */ + Noeud = NoeudCourant->NoeudSuivantGauche; + if( Noeud != 0 ) { + if ( Fois == 1 ) { + if ( Noeud == Bb->NoeudEnExamen ) { OnSupprime = NON; goto FinSuppression; } + } + Bb->NbNoeuds2_PNE_SupprimerTousLesDescendantsDUnNoeud++; /* Pour le nettoyage eventuel */ + NombreDeNoeudsASupprimerAuProchainEtage++; + NoeudsASupprimerAuProchainEtage[NombreDeNoeudsASupprimerAuProchainEtage-1] = Noeud; + } + Noeud = NoeudCourant->NoeudSuivantDroit; + if( Noeud != 0 ) { + if ( Fois == 1 ) { + if ( Noeud == Bb->NoeudEnExamen ) { OnSupprime = NON; goto FinSuppression; } + } + Bb->NbNoeuds2_PNE_SupprimerTousLesDescendantsDUnNoeud++; /* Pour le nettoyage eventuel */ + NombreDeNoeudsASupprimerAuProchainEtage++; + NoeudsASupprimerAuProchainEtage[NombreDeNoeudsASupprimerAuProchainEtage-1] = Noeud; + } + /* Liberation de la structure du noeud pere */ + if ( Fois == 2 ) { + NoeudCourant->NoeudSuivantGauche = 0; + NoeudCourant->NoeudSuivantDroit = 0; + BB_DesallouerUnNoeud( Bb, NoeudCourant ); + } + } + /* fin for */ + } + /* Preparations pour l'etage suivant */ + if( NombreDeNoeudsASupprimerAuProchainEtage == 0 ) break; /* Exploration de l'arbre terminee */ + + free( NoeudsASupprimer ); + + NoeudsASupprimer = (NOEUD **) malloc( NombreDeNoeudsASupprimerAuProchainEtage * sizeof( void * ) ); + if ( NoeudsASupprimer == NULL ) { + printf("\n Saturation memoire dans la partie branch & bound, fonction: BB_SupprimerTousLesDescendantsDUnNoeud 3\n"); + Bb->AnomalieDetectee = OUI; + longjmp( Bb->EnvBB , Bb->AnomalieDetectee ); + } + NombreDeNoeudsASupprimer = NombreDeNoeudsASupprimerAuProchainEtage; + + Bb->NbNoeuds1_PNE_SupprimerTousLesDescendantsDUnNoeud = NombreDeNoeudsASupprimer; /* Pour le nettoyage eventuel */ + Bb->Liste1_PNE_SupprimerTousLesDescendantsDUnNoeud = NoeudsASupprimer; /* Pour le nettoyage eventuel */ + + for( i = 0 ; i < NombreDeNoeudsASupprimer ; i++ ) { + NoeudsASupprimer[i] = NoeudsASupprimerAuProchainEtage[i]; + } + + free( NoeudsASupprimerAuProchainEtage ); + +/* fin while */ +} + +FinSuppression: + +free( NoeudsASupprimer ); +free( NoeudsASupprimerAuProchainEtage ); + +Bb->NbNoeuds1_PNE_SupprimerTousLesDescendantsDUnNoeud = 0; /* Pour le nettoyage eventuel */ +Bb->NbNoeuds2_PNE_SupprimerTousLesDescendantsDUnNoeud = 0; /* Pour le nettoyage eventuel */ + +if ( Fois == 1 ) { + if ( OnSupprime == NON ) { + /* Alors on part du noeud en examen */ + NoeudDeDepart = Bb->NoeudEnExamen; + } + Fois = 2; + goto Debut; +} + +return; +} + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/branchAndBound/bb_sys.h b/src/ext/Sirius_Solver/branchAndBound/bb_sys.h new file mode 100644 index 0000000000..a2af83abe6 --- /dev/null +++ b/src/ext/Sirius_Solver/branchAndBound/bb_sys.h @@ -0,0 +1,28 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# include +# include +# include +# include +# include +/* # include */ +# include +# include +# include +# include + + diff --git a/src/ext/Sirius_Solver/pne/mps_define.h b/src/ext/Sirius_Solver/pne/mps_define.h new file mode 100644 index 0000000000..9c12c4a0c6 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/mps_define.h @@ -0,0 +1,70 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# define OUI_MPS 1 +# define NON_MPS 0 + +# define REEL 1 +# define ENTIER 2 + +# define NON_DEFINI 128 + +typedef struct { + +int NentreesVar; +int NentreesCnt; + +int NbVar; +int NbCnt; + +int NbCntRange; + +int CoeffHaschCodeContraintes; +int SeuilHaschCodeContraintes; +int CoeffHaschCodeVariables; +int SeuilHaschCodeVariables; + +int * Mdeb; +double * A; +int * Nuvar; +int * Msui; +int * Mder; +int * NbTerm; +double * B; +char * SensDeLaContrainte; +double * BRange; /* Pas nul si contrainte range */ +double * VariablesDualesDesContraintes; + +char ** LabelDeLaContrainte; +char ** LabelDuSecondMembre; +char * LabelDeLObjectif; + +char ** LabelDeLaVariable; + +int * TypeDeVariable; +int * TypeDeBorneDeLaVariable; +double * U; +double * L; +double * Umin; +double * Umax; + +int * FirstNomCnt; +int * NomCntSuivant; + +int * FirstNomVar; +int * NomVarSuivant; + +} PROBLEME_MPS; diff --git a/src/ext/Sirius_Solver/pne/mps_extern_global.h b/src/ext/Sirius_Solver/pne/mps_extern_global.h new file mode 100644 index 0000000000..384ec03690 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/mps_extern_global.h @@ -0,0 +1,18 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +extern PROBLEME_MPS Mps; + diff --git a/src/ext/Sirius_Solver/pne/mps_global.h b/src/ext/Sirius_Solver/pne/mps_global.h new file mode 100644 index 0000000000..d8371b4937 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/mps_global.h @@ -0,0 +1,17 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +PROBLEME_MPS Mps; diff --git a/src/ext/Sirius_Solver/pne/pne_MIR_agregation.c b/src/ext/Sirius_Solver/pne/pne_MIR_agregation.c new file mode 100644 index 0000000000..0a097d7857 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_MIR_agregation.c @@ -0,0 +1,1453 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Heuristique Marchand-Wolsey pour faire des MIR sur des + contraintes natives agregees. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TROP_DE_VARIABLES_ENTIERES 100 + +# define MAX_FOIS_SUCCESS_MIR 2 + +# define Z0 1.e-7 +# define Z1 0.9999999 + +# define VALEUR_NULLE_DUN_COEFF 1.e-15 /*1.e-12*/ + +# define MAX_AGREG 3 /*5*/ /*3*/ + +# define MAX_CYCLES_SUR_CONTRAINTES 5 /*10*/ +# define MAX_CYCLES_SUR_VARIABLES 5 /*10*/ + +# define LOW_VARBIN 1 +# define HIGH_VARBIN 2 +# define LOW 3 +# define HIGH 4 + +/*----------------------------------------------------------------------------*/ +double PNE_G_de_D( double d, double f ) +{ double X; double fd; +X = floor( d ); +/*fd = d - floor( d );*/ +fd = d - X; +if ( fd > f ) { + X += ( fd - f ) / ( 1. - f ) ; +} +return( X ); +} +/*----------------------------------------------------------------------------*/ +double PNE_TesterUneMIR( int NombreDeVariablesBinaires, int * NumeroDeLaVariableBinaire, + double * CoeffDeLaVariableBinaire, double * UTrav, + double SecondMembreDeLaMIR, double Delta, double f, double SeuilPourC, + double * bMIR, char ModeTest ) +{ +int i; int Var; double ViolationMIR; double MembreDeGauche; double CoeffMir; double U; + +MembreDeGauche = 0.0; +/* Calcul de chaque coeff de la MIR et de la violation */ +goto NouveauCode; +for ( i = 0 ; i < NombreDeVariablesBinaires ; i++ ) { + Var = NumeroDeLaVariableBinaire[i]; + if ( UTrav[Var] > SeuilPourC ) { + /* La variable est dans C */ + CoeffMir = PNE_G_de_D( -CoeffDeLaVariableBinaire[i] / Delta, f ); + MembreDeGauche += CoeffMir * ( 1. - UTrav[Var] ); + if ( ModeTest == NON_PNE ) { + CoeffDeLaVariableBinaire[i] = -CoeffMir; + *bMIR -= CoeffMir; + } + } + else { + CoeffMir = PNE_G_de_D( CoeffDeLaVariableBinaire[i] / Delta, f ); + MembreDeGauche += CoeffMir * UTrav[Var]; + if ( ModeTest == NON_PNE ) CoeffDeLaVariableBinaire[i] = CoeffMir; + } +} +NouveauCode: +if ( ModeTest == NON_PNE ) { + for ( i = 0 ; i < NombreDeVariablesBinaires ; i++ ) { + Var = NumeroDeLaVariableBinaire[i]; + U = UTrav[Var]; + if ( U > SeuilPourC ) { + /* La variable est dans C */ + CoeffMir = PNE_G_de_D( -CoeffDeLaVariableBinaire[i] / Delta, f ); + MembreDeGauche += CoeffMir * ( 1. - U ); + CoeffDeLaVariableBinaire[i] = -CoeffMir; + *bMIR -= CoeffMir; + } + else { + CoeffMir = PNE_G_de_D( CoeffDeLaVariableBinaire[i] / Delta, f ); + MembreDeGauche += CoeffMir * U; + CoeffDeLaVariableBinaire[i] = CoeffMir; + } + } +} +else { + for ( i = 0 ; i < NombreDeVariablesBinaires ; i++ ) { + Var = NumeroDeLaVariableBinaire[i]; + U = UTrav[Var]; + if ( U > SeuilPourC ) { + /* La variable est dans C */ + CoeffMir = PNE_G_de_D( -CoeffDeLaVariableBinaire[i] / Delta, f ); + MembreDeGauche += CoeffMir * ( 1. - U ); + } + else { + CoeffMir = PNE_G_de_D( CoeffDeLaVariableBinaire[i] / Delta, f ); + MembreDeGauche += CoeffMir * U; + } + } +} + +ViolationMIR = MembreDeGauche - SecondMembreDeLaMIR; + +if ( ViolationMIR > 0 && 0 ) { + printf("Pendant tests ViolationMIR = %e MembreDeGauche %e SecondMembreDeLaMIR %e ",ViolationMIR,MembreDeGauche,SecondMembreDeLaMIR); + if ( ModeTest == NON_PNE ) printf("Final bMIR %e\n",*bMIR); + printf("\n"); +} + +return( ViolationMIR ); +} +/*----------------------------------------------------------------------------*/ +void PNE_TesterUneMIRpourUneValeurDeDelta( PROBLEME_PNE * Pne, + double Delta, int NombreDeVariablesBinaires, + double SeuilPourC, int * NumeroDeLaVariableBinaire, + double * CoeffDeLaVariableBinaire, double b, + double * CoeffDeLaVariableContinue, + double ValeurDeLaVariableContinue, + double * UTrav, double * ViolationMaxMIR, + double * DeltaOpt, char * MIRviolee, + double * bMIR, char ModeTest ) +{ +double CoeffVarCont; double Beta; double f; double SecondMembreDeLaMIR; +double ViolationMIR; double Seuil; + +if ( Delta < Z0 ) return; +Beta = b / Delta; +f = Beta - floor( Beta ); + +if ( f > Z1 ) return; + +/* On fait une MIR sur la contrainte divisee par Delta */ +CoeffVarCont = 1 / ( Delta * ( 1. - f ) ); +SecondMembreDeLaMIR = floor( Beta ) + ( CoeffVarCont * ValeurDeLaVariableContinue ); + +if ( ModeTest == NON_PNE ) { + *CoeffDeLaVariableContinue = CoeffVarCont; + *bMIR = floor( Beta ); +} + +ViolationMIR = PNE_TesterUneMIR( NombreDeVariablesBinaires, NumeroDeLaVariableBinaire, + CoeffDeLaVariableBinaire, UTrav, SecondMembreDeLaMIR, + Delta, f, SeuilPourC, bMIR ,ModeTest ); + +PNE_MiseAJourSeuilCoupes( Pne, COUPE_MIR_MARCHAND_WOLSEY, &Seuil ); + +if ( ViolationMIR > Seuil ) { + Pne->SommeViolationsMIR_MARCHAND_WOLSEY += ViolationMIR; + Pne->NombreDeMIR_MARCHAND_WOLSEY++; +} + +if ( ViolationMIR > Pne->SeuilDeViolationMIR_MARCHAND_WOLSEY && ViolationMIR > *ViolationMaxMIR ) { + *MIRviolee = OUI_PNE; + *ViolationMaxMIR = ViolationMIR; + *DeltaOpt = Delta; + /*printf("Violation MIR ViolationMIR = %e\n",ViolationMIR); */ +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* La contrainte mixte recue est du type Somme ai * yi <= b + s ou les yi + sont des variables binaires et s est une variable continue >= 0 */ +/* On suppose que les variables entieres sont des binaires donc leur borne + sup est 1. */ + +char PNE_C_MIR( PROBLEME_PNE * Pne, int NombreDeVariablesBinaires, int * NumeroDeLaVariableBinaire, + double * CoeffDeLaVariableBinaire, double * b, double * CoeffDeLaVariableContinue, + double ValeurDeLaVariableContinue ) +{ +int i; int Var; double * UTrav; double Delta; double SeuilPourC; char MIRviolee; +double ViolationMaxMIR; double DeltaOpt; double Delta0; char ModeTest; double bTest; +double bMIR; double SeuilPourCRetenu; double Beta; double f; double S; + +SeuilPourC = 0.5; +MIRviolee = NON_PNE; +ViolationMaxMIR = -1.0; +UTrav = Pne->UTrav; + +/* Au depart, on a toujours CoeffDeLaVariableContinue = 1 */ +/* Recherche de l'ensemble C que l'on va complementer */ +bTest = *b; +for ( i = 0 ; i < NombreDeVariablesBinaires ; i++ ) { + if ( UTrav[NumeroDeLaVariableBinaire[i]] > SeuilPourC ) { + /* On complemente la variable */ + bTest -= CoeffDeLaVariableBinaire[i]; /* Borne sur des variables binaires = 1 */ + } +} + +/* Choix des valeurs de Delta */ +ModeTest = OUI_PNE; + +for ( i = 0 ; i < NombreDeVariablesBinaires ; i++ ) { + Var = NumeroDeLaVariableBinaire[i]; + if ( UTrav[Var] < Z0 || UTrav[Var] > Z1 ) continue; + Delta = fabs( CoeffDeLaVariableBinaire[i] ); + + Beta = bTest / Delta; + f = Beta - floor( Beta ); + + if ( f < Z0 ) { + Delta *= 0.9 /*1.5*/; + } + + PNE_TesterUneMIRpourUneValeurDeDelta( Pne, Delta, NombreDeVariablesBinaires, SeuilPourC, + NumeroDeLaVariableBinaire, CoeffDeLaVariableBinaire, + bTest, CoeffDeLaVariableContinue, + ValeurDeLaVariableContinue, UTrav, &ViolationMaxMIR, + &DeltaOpt, &MIRviolee, &bMIR, ModeTest ); +} +if ( MIRviolee == OUI_PNE ) { + + Delta0 = DeltaOpt; + /* On essaie d'ameliorer la violation */ + Delta = Delta0 / 2; + PNE_TesterUneMIRpourUneValeurDeDelta( Pne, Delta, NombreDeVariablesBinaires, SeuilPourC, + NumeroDeLaVariableBinaire, CoeffDeLaVariableBinaire, + bTest, CoeffDeLaVariableContinue, + ValeurDeLaVariableContinue, UTrav, &ViolationMaxMIR, + &DeltaOpt, &MIRviolee, &bMIR, ModeTest ); + Delta = Delta0 / 4; + PNE_TesterUneMIRpourUneValeurDeDelta( Pne, Delta, NombreDeVariablesBinaires, SeuilPourC, + NumeroDeLaVariableBinaire, CoeffDeLaVariableBinaire, + bTest, CoeffDeLaVariableContinue, + ValeurDeLaVariableContinue, UTrav, &ViolationMaxMIR, + &DeltaOpt, &MIRviolee, &bMIR, ModeTest ); + Delta = Delta0 / 8; + PNE_TesterUneMIRpourUneValeurDeDelta( Pne, Delta, NombreDeVariablesBinaires, SeuilPourC, + NumeroDeLaVariableBinaire, CoeffDeLaVariableBinaire, + bTest, CoeffDeLaVariableContinue, + ValeurDeLaVariableContinue, UTrav, &ViolationMaxMIR, + &DeltaOpt, &MIRviolee, &bMIR, ModeTest ); +} + +/* Il manque la derniere etape d'amelioration de la mir decrite dans l'article */ + +if ( MIRviolee == OUI_PNE ) { + SeuilPourCRetenu = SeuilPourC; + /* On a trouve un DeltaOpt */ + /* On essaie d'augmenter la violation de la MIR en essayant SeuilPourC a 0.4 puis SeuilPourC 0.6 */ + Delta = DeltaOpt; + SeuilPourC = 0.4; + BaisseSeuilC: + bTest = *b; + for ( i = 0 ; i < NombreDeVariablesBinaires ; i++ ) { + if ( UTrav[NumeroDeLaVariableBinaire[i]] > SeuilPourC ) { + /* On complemente la variable */ + bTest -= CoeffDeLaVariableBinaire[i]; + } + } + MIRviolee = NON_PNE; + PNE_TesterUneMIRpourUneValeurDeDelta( Pne, Delta, NombreDeVariablesBinaires, SeuilPourC, + NumeroDeLaVariableBinaire, CoeffDeLaVariableBinaire, + bTest, CoeffDeLaVariableContinue, + ValeurDeLaVariableContinue, UTrav, &ViolationMaxMIR, + &DeltaOpt, &MIRviolee, &bMIR, ModeTest ); + if ( MIRviolee == OUI_PNE ) { + /*printf("MIR amelioree en modifiant SeuilPourC a la baisse\n");*/ + SeuilPourCRetenu = SeuilPourC; + SeuilPourC = SeuilPourC - 0.1; + if ( SeuilPourC > 0.0 && 0 ) goto BaisseSeuilC; + } + + Delta = DeltaOpt; + SeuilPourC = 0.6; + HausseeSeuilC: + bTest = *b; + for ( i = 0 ; i < NombreDeVariablesBinaires ; i++ ) { + if ( UTrav[NumeroDeLaVariableBinaire[i]] > SeuilPourC ) { + /* On complemente la variable */ + bTest -= CoeffDeLaVariableBinaire[i]; + } + } + MIRviolee = NON_PNE; + PNE_TesterUneMIRpourUneValeurDeDelta( Pne, Delta, NombreDeVariablesBinaires, SeuilPourC, + NumeroDeLaVariableBinaire, CoeffDeLaVariableBinaire, + bTest, CoeffDeLaVariableContinue, + ValeurDeLaVariableContinue, UTrav, &ViolationMaxMIR, + &DeltaOpt, &MIRviolee, &bMIR, ModeTest ); + if ( MIRviolee == OUI_PNE ) { + /*printf("MIR amelioree en modifiant SeuilPourC a la hausse\n");*/ + SeuilPourCRetenu = SeuilPourC; + SeuilPourC = SeuilPourC + 0.1; + if ( SeuilPourC < 1.0 && 0 ) goto HausseeSeuilC; + } + + /* Stockage de la MIR */ + Delta = DeltaOpt; + SeuilPourC = SeuilPourCRetenu; + bTest = *b; + for ( i = 0 ; i < NombreDeVariablesBinaires ; i++ ) { + if ( UTrav[NumeroDeLaVariableBinaire[i]] > SeuilPourC ) { + /* On complemente la variable */ + bTest -= CoeffDeLaVariableBinaire[i]; + } + } + ModeTest = NON_PNE; + PNE_TesterUneMIRpourUneValeurDeDelta( Pne, Delta, NombreDeVariablesBinaires, SeuilPourC, + NumeroDeLaVariableBinaire, CoeffDeLaVariableBinaire, + bTest, CoeffDeLaVariableContinue, + ValeurDeLaVariableContinue, UTrav, &ViolationMaxMIR, + &DeltaOpt, &MIRviolee, b, ModeTest ); + MIRviolee = OUI_PNE; + /* + printf("b de la MIR %e CoeffDeLaVariableContinue %e ValeurDeLaVariableContinue %e\n",*b,*CoeffDeLaVariableContinue,ValeurDeLaVariableContinue); + */ + S = -(*CoeffDeLaVariableContinue) * ValeurDeLaVariableContinue; + /*printf("La MIR avant reconstitution de S\n");*/ + for ( i = 0 ; i < NombreDeVariablesBinaires ; i++ ) { + S += CoeffDeLaVariableBinaire[i] * Pne->UTrav[NumeroDeLaVariableBinaire[i]]; + /*printf(" %e (%d) ",CoeffDeLaVariableBinaire[i],NumeroDeLaVariableBinaire[i]);*/ + } + /*printf("\n");*/ + if ( S < *b ) { + /*printf("Erreur des la fin de la MIR S = %e < b = %e\n",S,*b);*/ + } + else { + /*printf("violation de cette mir S %e b %e violation %e\n",S,*b,S-*b);*/ + } + /*printf("On va maintenant revenir aux variables qui constituent S\n");*/ + +} + +return( MIRviolee ); +} +/*----------------------------------------------------------------------------*/ +void PNE_SyntheseEtStockageMIR( PROBLEME_PNE * Pne, int NombreDeVariablesBinaires, int * NumeroDeLaVariableBinaire, + double * CoeffDeLaVariableBinaire, double b, double CoeffDeLaVariableContinue, + int NombreDeVariablesSubstituees, int * NumeroDesVariablesSubstituees, + char * TypeDeSubsitution, double * CoefficientDeLaVariableSubstituee ) +{ +int i; int Var; int il; int VarBin; int * NuVarCoupe; double * CoeffCoupe; int NbTermes; char TypeSubst; +double Violation; double * Umax; double * Umin; int * Mdeb; double * A; int * Nuvar; double l; double u; +int * CntDeBorneInfVariable; int * CntDeBorneSupVariable; double * U; double bBorne; double S; double * B; +int * TypeDeBorne; + +/* +printf(" Synthese de la MIR \n"); +printf(" b = %e CoeffDeLaVariableContinue = %e\n",b,CoeffDeLaVariableContinue); +*/ + +Mdeb = Pne->MdebTrav; +B = Pne->BTrav; +A = Pne->ATrav; +Nuvar = Pne->NuvarTrav; +Umax = Pne->UmaxTravSv; +Umin = Pne->UminTravSv; +U = Pne->UTrav; +CntDeBorneInfVariable = Pne->CntDeBorneInfVariable; +CntDeBorneSupVariable = Pne->CntDeBorneSupVariable; +TypeDeBorne = Pne->TypeDeBorneTrav; + +NuVarCoupe = Pne->IndiceDeLaVariable_CG; +CoeffCoupe = Pne->Coefficient_CG; + +NbTermes = 0; +memset( (char *) CoeffCoupe, 0, Pne->NombreDeVariablesTrav * sizeof( double) ); +for ( i = 0 ; i < NombreDeVariablesBinaires ; i++ ) { + CoeffCoupe[NumeroDeLaVariableBinaire[i]] = CoeffDeLaVariableBinaire[i]; +} +for ( i = 0 ; i < NombreDeVariablesSubstituees ; i++ ) { + Var = NumeroDesVariablesSubstituees[i]; + /* On reconstitue Umin Umax */ + TypeSubst = TypeDeSubsitution[i]; + if ( TypeDeSubsitution[i] == LOW ) { + CoeffCoupe[Var] = CoeffDeLaVariableContinue * CoefficientDeLaVariableSubstituee[i]; + b += CoeffDeLaVariableContinue * CoefficientDeLaVariableSubstituee[i] * Umin[Var]; + } + else if ( TypeDeSubsitution[i] == LOW_VARBIN ) { + CoeffCoupe[Var] = CoeffDeLaVariableContinue * CoefficientDeLaVariableSubstituee[i]; + il = Mdeb[CntDeBorneInfVariable[Var]]; + VarBin = Nuvar[il]; + l = A[il]; + CoeffCoupe[VarBin] -= CoeffDeLaVariableContinue * CoefficientDeLaVariableSubstituee[i] * l; + + bBorne = -B[CntDeBorneInfVariable[Var]]; + b += CoeffDeLaVariableContinue * CoefficientDeLaVariableSubstituee[i] * bBorne; + + } + + else if ( TypeDeSubsitution[i] == HIGH ) { + CoeffCoupe[Var] = -CoeffDeLaVariableContinue * CoefficientDeLaVariableSubstituee[i]; + b -= CoeffDeLaVariableContinue * CoefficientDeLaVariableSubstituee[i] * Umax[Var]; + } + else if ( TypeDeSubsitution[i] == HIGH_VARBIN ) { + CoeffCoupe[Var] = -CoeffDeLaVariableContinue * CoefficientDeLaVariableSubstituee[i]; + il = Mdeb[CntDeBorneSupVariable[Var]]; + VarBin = Nuvar[il]; + u = -A[il]; + CoeffCoupe[VarBin] += CoeffDeLaVariableContinue * CoefficientDeLaVariableSubstituee[i] * u; + + bBorne = B[CntDeBorneSupVariable[Var]]; + b -= CoeffDeLaVariableContinue * CoefficientDeLaVariableSubstituee[i] * bBorne; + + } + else { + printf("BUG: TypeDeSubsitution %d inconnu i %d\n",TypeDeSubsitution[i],i); + exit(0); + } +} + +S = 0.; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( CoeffCoupe[Var] != 0.0 ) { + + S+= CoeffCoupe[Var] * U[Var]; + + NuVarCoupe[NbTermes] = Var; + CoeffCoupe[NbTermes] = CoeffCoupe[Var]; + NbTermes++; + /*printf(" %e (%d) ",CoeffCoupe[Var],Var);*/ + } +} +/*printf(" < %e NbTermes %d\n",b,NbTermes);*/ + +/* +if ( S < b ) { + printf("MIR Marchand Wolsey la coupe respecte la contrainte ... bizarre ... S = %e respecte inferieur b = %e\n",S,b); +} +else { + printf("Apres synthese de la coupe Violation = %e S = %e b = %e\n\n\n\n",S-b,S,b); +} +*/ + +Violation = S-b; + +if ( Violation < Pne->SeuilDeViolationMIR_MARCHAND_WOLSEY ) { + goto FinSyntheseEtStockageMIR; +} + +/* printf("MIR Marchand Wolsey apres synthese de la coupe Violation = %e NbTermes = %d\n",Violation,NbTermes); */ + +PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'K', NbTermes, b, Violation, CoeffCoupe, NuVarCoupe ); + +FinSyntheseEtStockageMIR: + +memset( (char *) CoeffCoupe, 0, Pne->NombreDeVariablesTrav * sizeof( double ) ); +memset( (char *) NuVarCoupe, 0, Pne->NombreDeVariablesTrav * sizeof( int ) ); + +return; +} +/*----------------------------------------------------------------------------*/ +char PNE_BoundSubstitution( PROBLEME_PNE * Pne,int NbVarContinues, int NbVarEntieres, + int * NumeroDesVariables, double * CoeffDesVariables, + double SecondMembreContrainteAgregee, + /* En sortie, la contrainte pour y faire une MIR */ + int * NombreDeVariablesBinaires, int * NumeroDeLaVariableBinaire, + double * CoeffDeLaVariableBinaire, double * b, double * CoeffDeLaVariableContinue, + double * ValeurDeLaVariableContinue, + int * NombreDeVariablesSubstituees, int * NumeroDesVariablesSubstituees, + char * TypeDeSubsitution, double * CoefficientDeLaVariableSubstituee, + char * YaUneVariableS ) +{ +int i; int Var; int il; double Beta; int * CntDeBorneInfVariable; int * CntDeBorneSupVariable; +char l_valide; char u_valide; char VarEstSurBorneInf; char VarEstSurBorneSup; int VarBin; + double AlphaJ; int * Mdeb; int * Nuvar; int Nb; int * T; double bBorne; char CodeRet; +double * A; double * U; double * Umin; double * Umax; double l; double u; + int TypeBorne; int * TypeDeBorne; int Index; int IndexFin; double ValeurDeS; double * B; +double DeltaJ; double ValeurDeTJ; int NbVarB; int NbVarBinaires; int NombreDeVariables; + +CntDeBorneInfVariable = Pne->CntDeBorneInfVariable; +CntDeBorneSupVariable = Pne->CntDeBorneSupVariable; +Mdeb = Pne->MdebTrav; +B = Pne->BTrav; +A = Pne->ATrav; +Nuvar = Pne->NuvarTrav; +U = Pne->UTrav; +Umin = Pne->UminTravSv; +Umax = Pne->UmaxTravSv; +TypeDeBorne = Pne->TypeDeBorneTrav; +ValeurDeS = 0.0; +*NombreDeVariablesSubstituees = 0; +*YaUneVariableS = NON_PNE; + +NombreDeVariables = Pne->NombreDeVariablesTrav; + +/* A ce stade Coefficient_CG est nul et IndiceDeLaVariable_CG est nul */ +T = Pne->IndiceDeLaVariable_CG; + +/* Si la variable n'a pas de borne sup ou est sur sa borne inf on remplace par l'expression de sa borne inf */ +/* Si la variable est sur sa borne sup on remplace par l'expression de sa borne sup */ +/* Si AlphJ < 0 on remplace par l'expression de sa borne sup */ +/* Si AlphJ > 0 on remplace par l'expression de sa borne inf */ + +Beta = SecondMembreContrainteAgregee; +NbVarB = 0; +CodeRet = NON_PNE; +l = 0.0; +u = 0.0; + +NbVarBinaires = 0; +for ( i = 0 ; i < NbVarContinues ; i++ ) { + Var = NumeroDesVariables[i]; + AlphaJ = CoeffDesVariables[i]; + TypeBorne = TypeDeBorne[Var]; + + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) { + /* La variable continue est fixe: on la passe dans le second membre */ + Beta -= CoeffDesVariables[i] * U[Var]; + continue; + } + + /* A ce stade on n'a jamais de variables bornees superieurement */ + if ( TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT) { + printf("Attention BUG: a ce stade du calcul (les MIR) il ne doit pas exister de VARIABLE_BORNEE_SUPERIEUREMENT\n"); + } + if ( TypeBorne == VARIABLE_NON_BORNEE ) { + /* Substitution impossible et on ne peut pas non plus la passer dans s */ + /*printf("Bound substitution impossible car variable non bornee\n");*/ + goto FinBoundSubstitution; + } + + /* Presence d'une borne inf ou sup variable */ + l_valide = NON_PNE; + u_valide = NON_PNE; + VarEstSurBorneInf = NON_PNE; + VarEstSurBorneSup = NON_PNE; + VarBin = -1; + bBorne = 0.0; + if ( CntDeBorneInfVariable != NULL ) { + if ( CntDeBorneInfVariable[Var] >= 0 ) { + il = Mdeb[CntDeBorneInfVariable[Var]]; + bBorne = -B[CntDeBorneInfVariable[Var]]; + VarBin = Nuvar[il]; + l = A[il]; + l_valide = OUI_PNE; + if ( fabs( U[Var] - ( l * U[VarBin] ) ) < 1.e-9 ) VarEstSurBorneInf = OUI_PNE; + if ( TypeDeBorne[VarBin] == VARIABLE_FIXE ) { + l_valide = NON_PNE; + l = bBorne + ( l * U[VarBin] ); + } + } + } + else if ( fabs( U[Var] - Umin[Var] ) < 1.e-9 ) VarEstSurBorneInf = OUI_PNE; + + if ( CntDeBorneSupVariable != NULL ) { + if ( CntDeBorneSupVariable[Var] >= 0 ) { + il = Mdeb[CntDeBorneSupVariable[Var]]; + bBorne = B[CntDeBorneSupVariable[Var]]; + VarBin = Nuvar[il]; + u = -A[il]; + u_valide = OUI_PNE; + if ( fabs( U[Var] - ( u * U[VarBin] ) ) < 1.e-9 ) VarEstSurBorneSup = OUI_PNE; + if ( TypeDeBorne[VarBin] == VARIABLE_FIXE ) { + u_valide = NON_PNE; + u = bBorne + ( u * U[VarBin] ); + } + } + } + else if ( fabs( U[Var] - Umax[Var] ) < 1.e-9 ) VarEstSurBorneSup = OUI_PNE; + + /* Attention aux variables binaires de substitution qui sont fixes */ + + /* Si la variable n'a pas de borne sup ou est sur sa borne inf on remplace par l'expression de sa borne inf */ + if ( (TypeDeBorne[Var] == VARIABLE_BORNEE_INFERIEUREMENT && u_valide == NON_PNE ) || VarEstSurBorneInf == OUI_PNE ) { + if ( l_valide == OUI_PNE ) { + /* On fait x = l * y + t */ + + if ( T[VarBin] == 0 ) { + NumeroDeLaVariableBinaire[NbVarBinaires] = VarBin; + CoeffDeLaVariableBinaire[NbVarBinaires] = AlphaJ * l; + T[VarBin] = NombreDeVariables + NbVarBinaires; + NbVarBinaires++; + } + else { + Nb = T[VarBin] - NombreDeVariables; + CoeffDeLaVariableBinaire[Nb] += AlphaJ * l; + } + + Beta -= AlphaJ * bBorne; + + ValeurDeTJ = U[Var] - ( l * U[VarBin] ) - bBorne; + } + else { + /* Pas de borne inf variable */ + Beta -= AlphaJ * Umin[Var]; + ValeurDeTJ = U[Var] - Umin[Var]; + } + DeltaJ = AlphaJ; + if ( DeltaJ < 0 ) { + ValeurDeS += -DeltaJ * ValeurDeTJ; + *YaUneVariableS = OUI_PNE; + NumeroDesVariablesSubstituees[*NombreDeVariablesSubstituees] = Var; + if ( l_valide == OUI_PNE ) TypeDeSubsitution[*NombreDeVariablesSubstituees] = LOW_VARBIN; + else TypeDeSubsitution[*NombreDeVariablesSubstituees] = LOW; + CoefficientDeLaVariableSubstituee[*NombreDeVariablesSubstituees] = DeltaJ; + *NombreDeVariablesSubstituees = *NombreDeVariablesSubstituees + 1; + } + continue; + } + /* Si la variable est sur sa borne sup on remplace par l'expression de sa borne sup */ + if ( VarEstSurBorneSup == OUI_PNE ) { + if ( u_valide == OUI_PNE ) { + /* On fait x = u * y - t */ + + if ( T[VarBin] == 0 ) { + NumeroDeLaVariableBinaire[NbVarBinaires] = VarBin; + CoeffDeLaVariableBinaire[NbVarBinaires] = AlphaJ * u; + T[VarBin] = NombreDeVariables + NbVarBinaires; + NbVarBinaires++; + } + else { + Nb = T[VarBin] - NombreDeVariables; + CoeffDeLaVariableBinaire[Nb] += AlphaJ * u; + } + + Beta -= AlphaJ * bBorne; + + ValeurDeTJ = bBorne + ( u * U[VarBin] ) - U[Var]; + } + else { + /* Pas de borne sup variable */ + Beta -= AlphaJ * Umax[Var]; + ValeurDeTJ = Umax[Var] - U[Var]; + } + DeltaJ = -AlphaJ; + if ( DeltaJ < 0 ) { + ValeurDeS += -DeltaJ * ValeurDeTJ; + *YaUneVariableS = OUI_PNE; + NumeroDesVariablesSubstituees[*NombreDeVariablesSubstituees] = Var; + if ( u_valide == OUI_PNE ) TypeDeSubsitution[*NombreDeVariablesSubstituees] = HIGH_VARBIN; + else TypeDeSubsitution[*NombreDeVariablesSubstituees] = HIGH; + CoefficientDeLaVariableSubstituee[*NombreDeVariablesSubstituees] = DeltaJ; + *NombreDeVariablesSubstituees = *NombreDeVariablesSubstituees + 1; + } + continue; + } + /* Si AlphaJ < 0 on remplace par l'expression de sa borne sup */ + if ( AlphaJ < 0.0 ) { + if ( u_valide == OUI_PNE ) { + /* On fait x = u * y - t */ + + if ( T[VarBin] == 0 ) { + NumeroDeLaVariableBinaire[NbVarBinaires] = VarBin; + CoeffDeLaVariableBinaire[NbVarBinaires] = AlphaJ * u; + T[VarBin] = NombreDeVariables + NbVarBinaires; + NbVarBinaires++; + } + else { + Nb = T[VarBin] - NombreDeVariables; + CoeffDeLaVariableBinaire[Nb] += AlphaJ * u; + } + + Beta -= AlphaJ * bBorne; + + ValeurDeTJ = bBorne + ( u * U[VarBin] ) - U[Var]; + } + else { + /* Pas de borne sup variable */ + Beta -= AlphaJ * Umax[Var]; + ValeurDeTJ = Umax[Var] - U[Var]; + } + DeltaJ = -AlphaJ; + if ( DeltaJ < 0 ) { + ValeurDeS += -DeltaJ * ValeurDeTJ; + *YaUneVariableS = OUI_PNE; + NumeroDesVariablesSubstituees[*NombreDeVariablesSubstituees] = Var; + if ( u_valide == OUI_PNE ) TypeDeSubsitution[*NombreDeVariablesSubstituees] = HIGH_VARBIN; + else TypeDeSubsitution[*NombreDeVariablesSubstituees] = HIGH; + CoefficientDeLaVariableSubstituee[*NombreDeVariablesSubstituees] = DeltaJ; + *NombreDeVariablesSubstituees = *NombreDeVariablesSubstituees + 1; + } + continue; + } + else { + /* Si AlphaJ < 0 on remplace par l'expression de sa borne inf */ + if ( l_valide == OUI_PNE ) { + /* On fait x = l * y + t */ + + if ( T[VarBin] == 0 ) { + NumeroDeLaVariableBinaire[NbVarBinaires] = VarBin; + CoeffDeLaVariableBinaire[NbVarBinaires] = AlphaJ * l; + T[VarBin] = NombreDeVariables + NbVarBinaires; + NbVarBinaires++; + } + else { + Nb = T[VarBin] - NombreDeVariables; + CoeffDeLaVariableBinaire[Nb] += AlphaJ * l; + } + + Beta -= AlphaJ * bBorne; + + ValeurDeTJ = U[Var] - ( l * U[VarBin] ) - bBorne; + } + else { + /* Pas de borne inf variable */ + Beta -= AlphaJ * Umin[Var]; + ValeurDeTJ = U[Var] - Umin[Var]; + } + DeltaJ = AlphaJ; + if ( DeltaJ < 0 ) { + ValeurDeS += -DeltaJ * ValeurDeTJ; + *YaUneVariableS = OUI_PNE; + NumeroDesVariablesSubstituees[*NombreDeVariablesSubstituees] = Var; + if ( l_valide == OUI_PNE ) TypeDeSubsitution[*NombreDeVariablesSubstituees] = LOW_VARBIN; + else TypeDeSubsitution[*NombreDeVariablesSubstituees] = LOW; + CoefficientDeLaVariableSubstituee[*NombreDeVariablesSubstituees] = DeltaJ; + *NombreDeVariablesSubstituees = *NombreDeVariablesSubstituees + 1; + } + continue; + } +} + +*b = Beta; +*CoeffDeLaVariableContinue = 1.0; +*ValeurDeLaVariableContinue = ValeurDeS; + +/* On complete avec les variables binaires existantes */ +IndexFin = NombreDeVariables - 1; +for ( i = 0 , Index = IndexFin ; i < NbVarEntieres ; i++ , Index-- ) { + VarBin = NumeroDesVariables[Index]; + if ( T[VarBin] == 0 ) { + NumeroDeLaVariableBinaire[NbVarBinaires] = VarBin; + CoeffDeLaVariableBinaire[NbVarBinaires] = CoeffDesVariables[Index]; + T[VarBin] = NombreDeVariables + NbVarBinaires; + NbVarBinaires++; + } + else { + Nb = T[VarBin] - NombreDeVariables; + CoeffDeLaVariableBinaire[Nb] += CoeffDesVariables[Index]; + } +} + +*NombreDeVariablesBinaires = NbVarBinaires; +CodeRet = OUI_PNE; + +FinBoundSubstitution: + +/* RAZ de T */ +for ( i = 0 ; i < NbVarBinaires ; i++ ) T[NumeroDeLaVariableBinaire[i]] = 0; + +return( CodeRet ); +} + +/*----------------------------------------------------------------------------*/ + +char PNE_Agregation( PROBLEME_PNE * Pne, char * VariableDansContrainteMixte, int * NbVarCont, int * NbVarEnt, + int * NumeroDesVariables, double * CoeffDesVariables, + double * SecondMembreContrainteAgregee, char * ContrainteAgregee, + char * VariableSelectionable, int * NbV, int * NumV, int * NbC, int * NumC ) +{ +int IndexFin; int NombreDeVariablesTrav; int i; int Var; int * CntDeBorneSupVariable; int * CntDeBorneInfVariable; +double * UTrav; char * ContrainteMixte; double B; double * BTrav; int NbCSv; +int Cont; int * MdebTrav; int * NbTermTrav; double * ATrav; double * UminTrav; double * UmaxTrav; +int * NuvarTrav; double f; int VarBin; int il; int ilMax; double Fmax; int Kappa; double AlfaKappa; +int * CdebTrav; int * CsuiTrav; int * NumContrainteTrav; int ic; int Cnt; double AlfaJ; +double Gamma; double * V; int * T; int Index; int * TypeDeVariableTrav; double l; double u; char l_valide; char u_valide; +int * TypeDeBorneTrav; int TypeBorne; char * SensContrainteTrav; double bBorne; +int NbVarContinues; int NbVarEntieres; int Nn; int j; int NbTestAggregCnt; int NbTestAggregVar; +int Nb; int * ContrainteSaturee; char NUtiliserQueLesContraintesSaturees; + +NbVarContinues = *NbVarCont; +NbVarEntieres = *NbVarEnt; + +if ( NbVarEntieres == 0 && 0 ) return( NON_PNE ); /* J'ai rajoute ca le 24/10/2014 */ + +/* Attention a la restriction: pour l'instant on a 1 seule variable bound par variable */ + +NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; +IndexFin = NombreDeVariablesTrav - 1; +CntDeBorneSupVariable = Pne->CntDeBorneSupVariable; +CntDeBorneInfVariable = Pne->CntDeBorneInfVariable; +UTrav = Pne->UTrav; +UminTrav = Pne->UminTravSv; +UmaxTrav = Pne->UmaxTravSv; +SensContrainteTrav = Pne->SensContrainteTrav; + +BTrav = Pne->BTrav; +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +ATrav = Pne->ATrav; +NuvarTrav = Pne->NuvarTrav; +CdebTrav = Pne->CdebTrav; +CsuiTrav = Pne->CsuiTrav; +NumContrainteTrav = Pne->NumContrainteTrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +ContrainteMixte = Pne->ContrainteMixte; + +ContrainteSaturee = Pne->ContrainteSaturee; + +if ( Pne->NombreDeContraintesTrav > Pne->NombreDeVariablesTrav && Pne->NombreDeContraintesTrav > 20000 ) NUtiliserQueLesContraintesSaturees = OUI_PNE; +else NUtiliserQueLesContraintesSaturees = NON_PNE; + +/* La contrainte est rangee dans les vecteurs NumeroDesVariables CoeffDesVariables. + Pour les variables continues on commence a 0. Pour les variables entieres on commence + a NombreDeVariablesTrav - 1 */ + +NbTestAggregVar = 0; + + +/* A essayer: +balayer les variables du graphe de conflit reliees aux variables entieres de la contrainte +on ne choisi les contraintes a concatener que parmi ces contraintes +*/ + +VARTEST: + +Fmax = -1.; +Kappa = -1; +AlfaJ = 0.0; +l = 0.0; +u = 0.0; +f = 0.0; + +/* Choix de la variable continue P* et de la contrainte a ajouter */ + +for ( i = 0 ; i < NbVarContinues ; i++ ) { + Var = NumeroDesVariables[i]; + + if ( VariableSelectionable[Var] == NON_PNE ) continue; + + /* Remarque: la seule contrainte mixte de la variable a pu etre agregee mais comme + c'est long a tester on ne le fait pas */ + if ( VariableDansContrainteMixte[Var] == 0 ) continue; + + if ( UminTrav[Var] == UmaxTrav[Var] ) continue; + + /* Presence d'une borne inf ou sup variable */ + TypeBorne = TypeDeBorneTrav[Var]; + l_valide = NON_PNE; + u_valide = NON_PNE; + bBorne = 0.0; + if ( CntDeBorneInfVariable != NULL ) { + if ( CntDeBorneInfVariable[Var] >= 0 ) { + Cnt = CntDeBorneInfVariable[Var]; + bBorne = -BTrav[Cnt]; + il = MdebTrav[Cnt]; + VarBin = NuvarTrav[il]; /* Ne sert plus a rien */ + l = ATrav[il]; + l_valide = OUI_PNE; + } + } + if ( CntDeBorneSupVariable != NULL ) { + if ( CntDeBorneSupVariable[Var] >= 0 ) { + Cnt = CntDeBorneSupVariable[Var]; + bBorne = BTrav[Cnt]; + il = MdebTrav[Cnt]; + u = -ATrav[il]; + u_valide = OUI_PNE; + } + } + if ( l_valide == NON_PNE ) { + if ( TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT || TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES ) { + l = UminTrav[Var]; + l_valide = OUI_PNE; + } + } + if ( u_valide == NON_PNE ) { + if ( TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT || TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES ) { + u = UmaxTrav[Var]; + u_valide = OUI_PNE; + } + } + + /* Remarque: les contraintes d'egalite sont classees en premier */ + + if ( u_valide == NON_PNE && l_valide == NON_PNE ) { + f = LINFINI_PNE; + } + else if ( u_valide == OUI_PNE ) { + f = fabs( u - UTrav[Var] ); + if ( l_valide ) { + if ( f > fabs( UTrav[Var] - l ) ) f = fabs( UTrav[Var] - l ); + } + } + else if ( l_valide == OUI_PNE ) f = fabs( UTrav[Var] - l ); + + /* La variable ne doit pas etre sur borne */ + if ( f < Z0 ) { + if ( VariableSelectionable[Var] == OUI_PNE ) { + VariableSelectionable[Var] = NON_PNE; + NumV[*NbV] = Var; + *NbV = *NbV + 1; + } + continue; + } + if ( f > Fmax ) { + Fmax = f; + Kappa = Var; + AlfaJ = CoeffDesVariables[i]; + } +} + +if ( Kappa < 0 ) { + /* Rien a agreger */ + return( NON_PNE ); +} + +/* Choix de la contrainte */ + +NbTestAggregCnt = 0; +NbCSv = *NbC; + +CNTTEST: + +Cnt = -1; +Nb = -1; +Nn = 0; + +/* Les contraintes d'egalite sont classees en premier */ + +AlfaKappa = 0.; +ic = CdebTrav[Kappa]; +while ( ic >= 0 ) { + Cont = NumContrainteTrav[ic]; + if ( SensContrainteTrav[Cont] != '=' ) break; + if ( ATrav[ic] != 0.0 ) { + if ( ContrainteMixte[Cont] == OUI_PNE && ContrainteAgregee[Cont] == NON && fabs( AlfaJ / ATrav[ic] ) < 1.e+9 ) { + Cnt = Cont; + AlfaKappa = ATrav[ic]; + break; + } + } + ic = CsuiTrav[ic]; +} +if ( Cnt >= 0 ) goto ContrainteChoisie; + +/* Le cas echeant on continue et alors il s'agit de contraintes d'inegalite */ +/* Peut-etre serait-il plus rapide de ne prendre en compte que les contraintes d'inegalite qui sont saturees */ +if ( NUtiliserQueLesContraintesSaturees == OUI_PNE ) { + while ( ic >= 0 ) { + Cont = NumContrainteTrav[ic]; + if ( ContrainteSaturee[Cont] == OUI_PNE ) { + if ( ATrav[ic] != 0.0 ) { + if ( ContrainteMixte[Cont] == OUI_PNE && ContrainteAgregee[Cont] == NON && fabs( AlfaJ / ATrav[ic] ) < 1.e+9 ) { + Cnt = Cont; + AlfaKappa = ATrav[ic]; + break; + } + } + } + ic = CsuiTrav[ic]; + } +} +else { + while ( ic >= 0 ) { + Cont = NumContrainteTrav[ic]; + if ( ATrav[ic] != 0.0 ) { + if ( ContrainteMixte[Cont] == OUI_PNE && ContrainteAgregee[Cont] == NON && fabs( AlfaJ / ATrav[ic] ) < 1.e+9 ) { + Cnt = Cont; + AlfaKappa = ATrav[ic]; + break; + } + } + ic = CsuiTrav[ic]; + } +} + +ContrainteChoisie: +if ( Cnt < 0 ) { + NbTestAggregVar++; + if ( NbTestAggregVar <= MAX_CYCLES_SUR_VARIABLES ) { + if ( VariableSelectionable[Kappa] == OUI_PNE ) { + VariableSelectionable[Kappa] = NON_PNE; + NumV[*NbV] = Kappa; + *NbV = *NbV + 1; + } + goto VARTEST; + } + return( NON_PNE ); +} + +if ( ContrainteAgregee[Cnt] == NON_PNE ) { + ContrainteAgregee[Cnt] = OUI_PNE; + NumC[*NbC] = Cnt; + *NbC = *NbC + 1; +} + +if ( AlfaKappa == 0. ) return( NON_PNE ); + +Gamma = -( AlfaJ / AlfaKappa ); + +/* S'il decoule de la nouvelle contrainte agregee une variable d'ecart qui prend un coeff negatif on + refuse l'agregation */ +if ( SensContrainteTrav[Cnt] == '<' ) { + if ( Gamma < 0.0 ) { + NbTestAggregCnt++; + if ( NbTestAggregCnt <= MAX_CYCLES_SUR_CONTRAINTES ) { + /*ContrainteAgregee[Cnt] = NON_PNE;*/ /* Non: il ne faut plus la prendre en compte pour la variable Kappa */ + goto CNTTEST; + } + NbTestAggregVar++; + if ( NbTestAggregVar <= MAX_CYCLES_SUR_VARIABLES ) { + if ( VariableSelectionable[Kappa] == OUI_PNE ) { + VariableSelectionable[Kappa] = NON_PNE; + NumV[*NbV] = Kappa; + *NbV = *NbV + 1; + } + for ( i = NbCSv; i < *NbC ; i++ ) ContrainteAgregee[NumC[i]] = NON_PNE; + *NbC = NbCSv; + goto VARTEST; + } + return( NON_PNE ); + } +} + +V = (double *) Pne->Coefficient_CG; +T = (int *) Pne->IndiceDeLaVariable_CG; + +/* Expand de la contrainte dans V */ +B = BTrav[Cnt]; +il = MdebTrav[Cnt]; +ilMax = il + NbTermTrav[Cnt]; +while ( il < ilMax ) { + Var = NuvarTrav[il]; + if ( TypeDeBorneTrav[Var] == VARIABLE_FIXE ) { + B -= ATrav[il] * UTrav[Var]; + } + else { + if ( ATrav[il] != 0.0 ) { + V[Var] = Gamma * ATrav[il]; + T[Var] = 1; + } + } + il++; +} +B *= Gamma; + +/* Combinaision avec l'existant */ +for ( i = 0 ; i < NbVarContinues ; i++ ) { + Var = NumeroDesVariables[i]; + if ( T[Var] == 1 ) { + CoeffDesVariables[i] += V[Var]; + V[Var] = 0.0; + T[Var] = 0; + } +} +for ( i = 0 , Index = IndexFin ; i < NbVarEntieres ; i++ , Index-- ) { + Var = NumeroDesVariables[Index]; + if ( T[Var] == 1 ) { + CoeffDesVariables[Index] += V[Var]; + V[Var] = 0.0; + T[Var] = 0; + } +} + +/* On complete avec la partie de la contrainte ajoutee qui n'a pas pu etre prise en compte */ +il = MdebTrav[Cnt]; +ilMax = il + NbTermTrav[Cnt]; +while ( il < ilMax ) { + Var = NuvarTrav[il]; + if ( T[Var] != 0 ) { + if ( TypeDeVariableTrav[Var] == ENTIER ) { + CoeffDesVariables[Index] = V[Var]; + NumeroDesVariables[Index] = Var; + Index--; + NbVarEntieres++; + } + else { + CoeffDesVariables[NbVarContinues] = V[Var]; + NumeroDesVariables[NbVarContinues] = Var; + NbVarContinues++; + } + V[Var] = 0.0; + T[Var] = 0; + } + il++; +} + +/* On enleve tous les coeff de variables continues qui sont a 0 et au passage la + variable continue Kappa dont le coefficient est devenu nul */ +Nn = 0; +for ( i = 0 ; i < NbVarContinues ; i++ ) { + if ( fabs( CoeffDesVariables[i] ) < VALEUR_NULLE_DUN_COEFF ) { + for ( j = i + 1 ; j < NbVarContinues ; j++ ) { + if ( fabs( CoeffDesVariables[j] ) >= VALEUR_NULLE_DUN_COEFF ) { + CoeffDesVariables[i] = CoeffDesVariables[j]; + CoeffDesVariables[j] = 0.0; + NumeroDesVariables[i] = NumeroDesVariables[j]; + Nn++; + break; + } + } + } + else Nn++; +} +NbVarContinues = Nn; + +/* On enleve tous les coeff de variables entieres qui sont a 0 */ +Nn = 0; +for ( i = 0 , Index = IndexFin ; i < NbVarEntieres ; i++ , Index-- ) { + if ( fabs( CoeffDesVariables[Index] ) < VALEUR_NULLE_DUN_COEFF ) { + for ( j = Index - 1 ; j >= IndexFin - NbVarEntieres + 1 ; j-- ) { + if ( fabs( CoeffDesVariables[j] ) >= VALEUR_NULLE_DUN_COEFF ) { + CoeffDesVariables[Index] = CoeffDesVariables[j]; + CoeffDesVariables[j] = 0.0; + NumeroDesVariables[Index] = NumeroDesVariables[j]; + Nn++; + break; + } + } + } + else Nn++; +} +NbVarEntieres = Nn; + +*SecondMembreContrainteAgregee = *SecondMembreContrainteAgregee + B; + +*NbVarCont = NbVarContinues; +*NbVarEnt = NbVarEntieres; + +/* Construction de la constrainte sur laquelle on va faire la MIR */ +return( OUI_PNE ); +} + +/*----------------------------------------------------------------------------*/ + +void PNE_MIRMarchandWolsey( PROBLEME_PNE * Pne ) +{ +int Cnt; int Var; char * ContrainteMixte; int il; int ilMax; int * Mdeb; int * NbTerm; +int * NumeroDesVariables; double * CoeffDesVariables; int NbVarContinues; int NbVarEntieres; +double * A; int * Nuvar; int IndexFin; int Index; char * ContrainteAgregee; +int * TypeDeVariable; char Agreg; char OK; double * B; double * X; +int NombreDeVariablesBinaires; int * NumeroDeLaVariableBinaire; double * CoeffDeLaVariableBinaire; +double b; double CoeffDeLaVariableContinue; double ValeurDeLaVariableContinue; +double SecondMembreContrainteAgregee; int NbAgr; char MIRviolee; int NombreDeVariablesSubstituees; +int * NumeroDesVariablesSubstituees; double * CoefficientDeLaVariableSubstituee; +char * TypeDeSubsitution; int NombreDeVariables; int NombreDeContraintes; +int * TypeDeBorne; char * TasPourKnapsack; char * pt; int LallocTas; +char * VariableDansContrainteMixte; int NbMIRCreees; char YaUneVariableS; double * L; BB * Bb; +char * VariableSelectionable; double * Xmin; double * Xmax; +int NbV; int * NumV; int NbC; int * NumC; + +if ( Pne->ContrainteMixte == NULL ) return; + +/* L'agregation est couteuse en temps */ +/* +if ( Pne->CalculDeMIRmarchandWolsey == NON_PNE ) { + Pne->NbEvitementsDeCalculsMIRmarchandWolsey++; + if ( Pne->NbEvitementsDeCalculsMIRmarchandWolsey >= SEUIL_EVITEMENT_MIR_MARCHAND_WOLSEY ) { + Pne->NbEvitementsDeCalculsMIRmarchandWolsey = 0; + Pne->CalculDeMIRmarchandWolsey = OUI_PNE; + Pne->NbEchecsConsecutifsDeCalculsMIRmarchandWolsey = 0; + } + else { + return; + } +} +*/ + +Bb = (BB *) Pne->ProblemeBbDuSolveur; + +if ( Bb->NoeudEnExamen->ProfondeurDuNoeud > 20 ) return; + +if ( Bb->NoeudEnExamen->ProfondeurDuNoeud > Pne->ProfondeurMirMarchandWolseTrouvees ) return; + +NbMIRCreees = 0; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +L = Pne->LTrav; + +CoeffDesVariables = Pne->ValeurLocale; +NumeroDesVariables = Pne->IndiceLocal; + +LallocTas = 0; +LallocTas += NombreDeVariables * sizeof( int ); /* Pour NumeroDesVariablesSubstituees */ +LallocTas += NombreDeVariables * sizeof( double ); /* Pour CoefficientDeLaVariableSubstituee */ +LallocTas += NombreDeVariables * sizeof( int ); /* Pour NumeroDeLaVariableBinaire */ +LallocTas += NombreDeVariables * sizeof( double ); /* Pour CoeffDeLaVariableBinaire */ +LallocTas += NombreDeVariables * sizeof( char ); /* Pour TypeDeSubsitution */ +LallocTas += NombreDeContraintes * sizeof( char ); /* Pour ContrainteAgregee */ +LallocTas += NombreDeVariables * sizeof( char ); /* Pour VariableDansContrainteMixte */ +LallocTas += NombreDeVariables * sizeof( char ); /* Pour VariableSelectionable */ + +LallocTas += NombreDeVariables * sizeof( int ); /* Pour NumV */ +LallocTas += NombreDeContraintes * sizeof( int ); /* Pour NumC */ + +TasPourKnapsack = (char *) malloc( LallocTas ); +if ( TasPourKnapsack == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_MIRMarchandWolsey \n"); + return; +} + +pt = TasPourKnapsack; +NumeroDesVariablesSubstituees = (int *) pt; +pt += NombreDeVariables * sizeof( int ); +CoefficientDeLaVariableSubstituee = (double *) pt; +pt += NombreDeVariables * sizeof( double ); +NumeroDeLaVariableBinaire = (int *) pt; +pt += NombreDeVariables * sizeof( int ); +CoeffDeLaVariableBinaire = (double *) pt; +pt += NombreDeVariables * sizeof( double ); +TypeDeSubsitution = (char *) pt; +pt += NombreDeVariables * sizeof( char ); +ContrainteAgregee = (char *) pt; +pt += NombreDeContraintes * sizeof( char ); +VariableDansContrainteMixte = (char *) pt; +pt += NombreDeVariables * sizeof( char ); +VariableSelectionable = (char *) pt; +pt += NombreDeVariables * sizeof( char ); + +NumV = (int *) pt; +pt += NombreDeVariables * sizeof( int ); +NumC = (int *) pt; +pt += NombreDeContraintes * sizeof( int ); + +ContrainteMixte = Pne->ContrainteMixte; +B = Pne->BTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +A = Pne->ATrav; +Nuvar = Pne->NuvarTrav; +X = Pne->UTrav; +Xmin = Pne->UminTravSv; +Xmax = Pne->UmaxTravSv; +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +IndexFin = Pne->NombreDeVariablesTrav - 1; + +memset( (char *) VariableDansContrainteMixte, 0, NombreDeVariables * sizeof( char ) ); + +memset( (char *) ContrainteAgregee, NON_PNE, NombreDeContraintes * sizeof( char ) ); +memset( (char *) VariableSelectionable, OUI_PNE, NombreDeVariables * sizeof( char ) ); + +/* RAZ de Coefficient_CG et IndiceDeLaVariable_CG car utilises et razes ensuite + dans la phase d'agregation */ +memset( (char *) Pne->Coefficient_CG, 0, NombreDeVariables * sizeof( double ) ); +memset( (char *) Pne->IndiceDeLaVariable_CG, 0, NombreDeVariables * sizeof( int ) ); + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteMixte[Cnt] == NON_PNE ) continue; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + VariableDansContrainteMixte[Nuvar[il]] = 1; + il++; + } +} + +/* +goto TestGrapheDeConflits; +*/ + +/* Choix d'une contrainte mixte pour demarrer le processus d'agregation */ + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + + if ( ContrainteMixte[Cnt] == NON_PNE && 0 ) continue; + + if ( Pne->FoisCntSuccesMirMarchandWolseyTrouvees[Cnt] > MAX_FOIS_SUCCESS_MIR ) continue; + + /* On tente Marchand-Wolsey */ + /* + printf(" Tentative Marchand Wolsey sur Cnt %d \n",Cnt); + */ + NbVarContinues = 0; + NbVarEntieres = 0; + il = Mdeb[Cnt]; + + if ( NbTerm[Cnt] > 10000 ) { + /*printf(" Tentative Marchand Wolsey rejetee car NbTermTrav %d \n",NbTermTrav[Cnt]);*/ + continue; + } + + SecondMembreContrainteAgregee = B[Cnt]; + ilMax = il + NbTerm[Cnt]; + Index = IndexFin; + while ( il < ilMax ) { + if ( A[il] == 0.0 ) goto NextIl; + Var = Nuvar[il]; + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) { + SecondMembreContrainteAgregee -= A[il] * X[Var]; + goto NextIl; + } + else if ( Xmin[Var] == Xmax[Var] ) { + SecondMembreContrainteAgregee -= A[il] * Xmin[Var]; + goto NextIl; + } + if ( TypeDeVariable[Var] == ENTIER ) { + CoeffDesVariables[Index] = A[il]; + NumeroDesVariables[Index] = Var; + Index--; + NbVarEntieres++; + } + else { + CoeffDesVariables[NbVarContinues] = A[il]; + NumeroDesVariables[NbVarContinues] = Var; + NbVarContinues++; + } + NextIl: + il++; + } + + NbAgr = 1; + NbC = 0; + NbV = 0; + + ContrainteAgregee[Cnt] = OUI_PNE; + NumC[NbC] = Cnt; + NbC = NbC + 1; + + DEBUT_MIR: + + /*printf("1- NbAgr %d Cnt %d Avant BoundSubstitution NbVarContinues %d NbVarEntieres %d \n",NbAgr,Cnt,NbVarContinues,NbVarEntieres);*/ + + if ( NbVarContinues + NbVarEntieres == 0 ) goto RAZ; + + OK = PNE_BoundSubstitution( Pne, NbVarContinues, NbVarEntieres, NumeroDesVariables, CoeffDesVariables, + SecondMembreContrainteAgregee, + /* En sortie, la contrainte pour y faire une MIR */ + &NombreDeVariablesBinaires, NumeroDeLaVariableBinaire, + CoeffDeLaVariableBinaire, &b, &CoeffDeLaVariableContinue, + &ValeurDeLaVariableContinue, + &NombreDeVariablesSubstituees, NumeroDesVariablesSubstituees, TypeDeSubsitution, + CoefficientDeLaVariableSubstituee, &YaUneVariableS ); + + if ( OK == OUI_PNE && NombreDeVariablesBinaires >= 1 ) { + /* Si la valeur de la variable continue est negative, c'est a cause des imprecisions et on evite de faire un calcul */ + if ( ValeurDeLaVariableContinue < 0.0 ) goto RAZ; + + # if CALCULS_SUR_MIXED_0_1_KNAPSACK == OUI_PNE + if ( YaUneVariableS == OUI_PNE && ValeurDeLaVariableContinue != 0.0 ) { + PNE_Knapsack_0_1_AvecVariableContinue( Pne, + NombreDeVariablesBinaires, NumeroDeLaVariableBinaire, CoeffDeLaVariableBinaire, + b, ValeurDeLaVariableContinue, + NombreDeVariablesSubstituees, NumeroDesVariablesSubstituees, + TypeDeSubsitution, CoefficientDeLaVariableSubstituee + ); + } + goto RAZ; + # endif + + /* cMIR separation */ + /*printf("2- Avant CMIR NombreDeVariablesBinaires %d b = %e ValeurDeLaVariableContinue = %e\n",NombreDeVariablesBinaires,b,ValeurDeLaVariableContinue);*/ + + MIRviolee= PNE_C_MIR( Pne, NombreDeVariablesBinaires, NumeroDeLaVariableBinaire, + CoeffDeLaVariableBinaire, &b, &CoeffDeLaVariableContinue, + ValeurDeLaVariableContinue ); + + if ( MIRviolee == OUI_PNE ) { + /*printf("MIR violee, contrainte de depart: %d - nb termes de la contrainte: %d - NbAgr: %d\n",Cnt,NbTerm[Cnt],NbAgr);*/ + + NbMIRCreees++; + if ( NbAgr == 1 ) Pne->FoisCntSuccesMirMarchandWolseyTrouvees[Cnt]++; + + PNE_SyntheseEtStockageMIR( Pne, NombreDeVariablesBinaires, NumeroDeLaVariableBinaire, + CoeffDeLaVariableBinaire, b, CoeffDeLaVariableContinue, + NombreDeVariablesSubstituees, + NumeroDesVariablesSubstituees, TypeDeSubsitution, + CoefficientDeLaVariableSubstituee ); + goto RAZ; + } + } + + /*printf("3- Avant Agregation\n");*/ + if ( NbVarEntieres > TROP_DE_VARIABLES_ENTIERES && 0 ) goto RAZ; + + /* Attention. Dans l'article Marchand-Wolsey il est dit qu'on peut aller jusqu'a 5. Mais experimentalement + on constate qu'il ne faut aller aussi loin a cause des imprecisions */ + if ( NbAgr < MAX_AGREG ) { + /* memset( (char *) VariableSelectionable, OUI_PNE, NombreDeVariables * sizeof( char ) ); */ + /*printf("3- PNE_Agregation\n");*/ + Agreg = PNE_Agregation( Pne, VariableDansContrainteMixte, &NbVarContinues, &NbVarEntieres, NumeroDesVariables, + CoeffDesVariables, &SecondMembreContrainteAgregee, ContrainteAgregee, VariableSelectionable, + &NbV, NumV, &NbC, NumC ); + if ( Agreg == NON_PNE || NbVarContinues + NbVarEntieres == 0 ) { + /*printf("Echec agregation \n");*/ + goto RAZ; + } + NbAgr++; + + goto DEBUT_MIR; + } + else { + /*printf(" Marchand Wolsey arretee car NbAgr > MAX_AGREG \n");*/ + } + + RAZ: + + for ( il = 0 ; il < NbV ; il++ ) VariableSelectionable[NumV[il]] = OUI_PNE; + for ( il = 0 ; il < NbC ; il++ ) { + if ( NumC[il] < 0 || NumC[il] >= NombreDeContraintes ) { + printf("Bug NumC[%d] = %d\n",il,NumC[il]); + exit(0); + } + ContrainteAgregee[NumC[il]] = NON_PNE; + } + +} + +/* +TestGrapheDeConflits: +*/ +/* Ca sert a rien alors j'ai mis un return dedans */ +/*PNE_MIRMarchandWolseySurContrainteConcateeGrapheDeConflits( Pne, CoeffDesVariables, NumeroDesVariables, + ContrainteAgregee, VariableDansContrainteMixte, + CoefficientDeLaVariableSubstituee, NumeroDesVariablesSubstituees, + TypeDeSubsitution, CoeffDeLaVariableBinaire, + NumeroDeLaVariableBinaire, VariableSelectionable, ContrainteMixte ); +*/ +/* Fin test avec graphes de conflits */ + +free( TasPourKnapsack ); + +if ( NbMIRCreees == 0 ) { + Pne->NbEchecsConsecutifsDeCalculsMIRmarchandWolsey++; + if ( Pne->NbEchecsConsecutifsDeCalculsMIRmarchandWolsey >= NB_ECHECS_INHIB_MIR ) { + Pne->CalculDeMIRmarchandWolsey = NON_PNE; + } +} +else { + /* On a cree une ou plusieurs MIR => on remet le compteur a 0 */ + Pne->NbEchecsConsecutifsDeCalculsMIRmarchandWolsey = 0; + if ( Bb->NoeudEnExamen->ProfondeurDuNoeud + 1 > Pne->ProfondeurMirMarchandWolseTrouvees ) { + Pne->ProfondeurMirMarchandWolseTrouvees = Bb->NoeudEnExamen->ProfondeurDuNoeud + 1; + } + if ( Pne->AffichageDesTraces == OUI_PNE ) { + /* + printf("Mir cuts found %d at depth %d\n",NbMIRCreees,Bb->NoeudEnExamen->ProfondeurDuNoeud); + fflush( stdout ); + */ + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + diff --git a/src/ext/Sirius_Solver/pne/pne_ajouter_la_contrainte_de_cout_max.c b/src/ext/Sirius_Solver/pne/pne_ajouter_la_contrainte_de_cout_max.c new file mode 100644 index 0000000000..c3f976bb5f --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_ajouter_la_contrainte_de_cout_max.c @@ -0,0 +1,131 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: S'il y a des variables entieres on ajoute la contrainte de + cout max avec une variable. C'est une contrainte d'egalite + avec une variable non bornee et un second membre nul. + Lorsqu'opn dispose d'une solution admissible, la variable + non bornee devient une variable >= 0 et on met le cout + dans le scond membre. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_AjouterLaContrainteDeCoutMax( PROBLEME_PNE * Pne ) +{ +int Var; int NombreDeVariables; int NombreDeContraintes; int * Mdeb; int * NbTerm; +int * Nuvar; double * A; int NbT; double * CoutLineaire; int Cnt; int il; int Nb; + +/* Je ne recommande pas d'utiliser la contrainte de cout max */ +# if UTILISER_UNE_CONTRAINTE_DE_COUT_MAX == NON_PNE + return; +# endif + +if ( Pne->NombreDeContraintesTrav + 1 > Pne->NombreDeContraintesAllouees ) { + PNE_AugmenterLeNombreDeContraintes( Pne ); +} +if ( Pne->NombreDeVariablesTrav + 1 > Pne->NombreDeVariablesAllouees ) { + PNE_AugmenterLeNombreDeVariables( Pne ); +} + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +CoutLineaire = Pne->LTrav; + +Cnt = NombreDeContraintes - 1; +il = Mdeb[Cnt] + NbTerm[Cnt] + 1; + +NbT = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( CoutLineaire[Var] != 0.0 ) NbT++; +} + +Nb = 0; +ControleTailleMatrice: +if ( il + NbT + 1 > Pne->TailleAlloueePourLaMatriceDesContraintes ) { + PNE_AugmenterLaTailleDeLaMatriceDesContraintes( Pne ); + Nuvar = Pne->NuvarTrav; + A = Pne->ATrav; + Nb++; + if ( Nb < 100 ) goto ControleTailleMatrice; + else { + /* Probleme de place: remarque dans ce cas il faudrait activer UtiliserCoutMax donc il faut + monter un flag: a faire */ + return; + } +} + +Cnt++; +Mdeb[Cnt] = il; +NbT = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( CoutLineaire[Var] == 0.0 ) continue; + Nuvar[il] = Var; + A[il] = CoutLineaire[Var]; + NbT++; + il++; +} +if ( NbT == 0 ) return; + +/* Variable d'ecart de la contrainte de cout max */ +Var = NombreDeVariables; +Pne->TypeDeVariableTrav[Var] = REEL; +Pne->TypeDeBorneTrav [Var] = VARIABLE_NON_BORNEE; +Pne->VariableAInverser [Var] = NON_PNE; +Pne->UTrav [Var] = 0.; +Pne->UminTrav[Var] = -LINFINI_PNE; +Pne->UmaxTrav[Var] = LINFINI_PNE; +Pne->LTrav [Var] = 0.; + +Pne->NumeroDeLaVariableDEcartPourCoutMax = Var; + +Nuvar[il] = Var; /* <- important: coefficient 1 */ +A[il] = 1.; +NbT++; +il++; + +/* */ + +NbTerm[Cnt] = NbT; +Pne->BTrav[Cnt] = 0.0; +Pne->SensContrainteTrav[Cnt] = '='; +Pne->CorrespondanceCntPneCntEntree[Cnt] = -1; + +Pne->NumeroDeLaContrainteDeCoutMax = Cnt; + +Pne->NombreDeVariablesTrav++; +Pne->NombreDeContraintesTrav++; + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_alloc_probleme.c b/src/ext/Sirius_Solver/pne/pne_alloc_probleme.c new file mode 100644 index 0000000000..7c0cef0ac6 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_alloc_probleme.c @@ -0,0 +1,814 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Allocations et liberation du probleme + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# include "prs_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_AllocProbleme( PROBLEME_PNE * Pne, + int NombreDeVariablesE , + int * TypeDeVariableE , + int * TypeDeBorneE , + double * UmaxE , + double * UminE , + int NombreDeContraintesE, + int * MdebE , + int * NbtermE , + int * IndicesColonnesE , + double * AE + ) +{ +int NbVarAlloc; int NbCntAlloc; int NbGub; char Gub; int i; int ilMax; +int Cnt ; int il ; int Var ; int NbV; int NbVmxGub ; + +Pne->ProblemeSpxDuSolveur = NULL; +Pne->ProblemeSpxDuNoeudRacine = NULL; +Pne->MatriceDesContraintesAuNoeudRacine = NULL; + +NbVarAlloc = NombreDeVariablesE + INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_VARIABLES_PNE; +NbCntAlloc = NombreDeContraintesE + INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_CONTRAINTES_PNE; + +#if VERBOSE_PNE + printf("Allocations memoire du PNE:\n"); + printf("Nombre de variables allouees: %d\n", NbVarAlloc); + printf("Nombre de contraintes allouees: %d\n", NbCntAlloc); +#endif + +/* Calcul d'un majorant du nombre de Gub */ +/* Recherche de GUB */ +NbGub = 0; +NbVmxGub = -1; +for ( Cnt = 0 ; Cnt < NombreDeContraintesE ; Cnt++ ) { + il = MdebE[Cnt]; + ilMax = il + NbtermE[Cnt]; + Gub = OUI_PNE; + NbV = 0; + if ( NbtermE[Cnt] <= 2 ) continue; + while ( il < ilMax ) { + Var = IndicesColonnesE[il]; + if ( TypeDeBorneE[Var] != VARIABLE_FIXE ) { + if ( TypeDeVariableE[Var] != ENTIER || ( AE[il] != 1.0 && AE[il] != -1.0 ) ) { + if ( fabs( UmaxE[Var] - UminE[Var] ) > ZERO_VARFIXE && TypeDeBorneE[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + Gub = NON_PNE; + break; + } + } + } + NbV++; + il++; + } + if ( Gub == OUI_PNE ) { + if ( NbV > NbVmxGub ) NbVmxGub = NbV; + NbGub++; + } +} + +if ( NbVmxGub <= 0 ) NbVmxGub = 1; + +/* Estimation par exces du nombre de Gub, reduit apres les avoir determine */ +NbGub = NbCntAlloc; + +Pne->NombreDeVariablesAllouees = NbVarAlloc; +Pne->NombreDeContraintesAllouees = NbCntAlloc; + +Pne->CorrespondanceVarEntreeVarNouvelle = (int *) malloc( NbVarAlloc * sizeof( int ) ); + +Pne->VariableAInverser = (char *) malloc( NbVarAlloc * sizeof( char ) ); + +Pne->VariableElimineeSansValeur = (int *) malloc( NbVarAlloc * sizeof( int ) ); + +Pne->NumeroDesVariablesNonFixes = (int *) malloc( NbVarAlloc * sizeof( int ) ); +Pne->NumerosDesVariablesEntieresTrav = (int *) malloc( NbVarAlloc * sizeof( int ) ); +Pne->TypeDeVariableTrav = (int *) malloc( NbVarAlloc * sizeof( int ) ); +Pne->SeuilDeFractionnalite = (double *) malloc( NbVarAlloc * sizeof( double ) ); +Pne->VariableBinaireBigM = (char *) malloc( NbVarAlloc * sizeof( char ) ); +Pne->TypeDeBorneTrav = (int *) malloc( NbVarAlloc * sizeof( int ) ); +Pne->TypeDeBorneTravSv = (int *) malloc( NbVarAlloc * sizeof( int ) ); + +Pne->UTrav = (double *) malloc( NbVarAlloc * sizeof( double ) ); +Pne->S1Trav = (double *) malloc( NbVarAlloc * sizeof( double ) ); +Pne->S2Trav = (double *) malloc( NbVarAlloc * sizeof( double ) ); +Pne->UmaxTrav = (double *) malloc( NbVarAlloc * sizeof( double ) ); +Pne->UmaxTravSv = (double *) malloc( NbVarAlloc * sizeof( double ) ); +Pne->UminTrav = (double *) malloc( NbVarAlloc * sizeof( double ) ); +Pne->UminTravSv = (double *) malloc( NbVarAlloc * sizeof( double ) ); +Pne->UmaxEntree = (double *) malloc( NbVarAlloc * sizeof( double ) ); +Pne->UminEntree = (double *) malloc( NbVarAlloc * sizeof( double ) ); + +Pne->LTrav = (double *) malloc( NbVarAlloc * sizeof( double ) ); +Pne->CoutsReduits = (double *) malloc( NbVarAlloc * sizeof( double ) ); + +Pne->BTrav = (double *) malloc( NbCntAlloc * sizeof( double ) ); +Pne->SensContrainteTrav = (char *) malloc( NbCntAlloc * sizeof( char ) ); +Pne->ContrainteSaturee = (int *) malloc( NbCntAlloc * sizeof( int ) ); + +Pne->CorrespondanceCntPneCntEntree = (int *) malloc( NbCntAlloc * sizeof( int ) ); +Pne->VariablesDualesDesContraintesTrav = (double *) malloc( NbCntAlloc * sizeof( double ) ); + +Pne->VariablesDualesDesContraintesTravEtDesCoupes = NULL; +Pne->TailleAlloueeVariablesDualesDesContraintesTravEtDesCoupes = 0; + +Pne->MdebTrav = (int *) malloc( NbCntAlloc * sizeof( int ) ); +Pne->NbTermTrav = (int *) malloc( NbCntAlloc * sizeof( int ) ); + +for ( ilMax = -1 , i = 0 ; i < NombreDeContraintesE ; i++ ) { + if ( ( MdebE[i] + NbtermE[i] - 1 ) > ilMax ) ilMax = MdebE[i] + NbtermE[i] - 1; +} + +/*ilMax+= Pne->NombreDeContraintesAllouees;*/ /* Afin de pouvoir mettre tout de suite le probleme sous + la forme standard si on le souhaite */ +ilMax += MARGE_EN_FIN_DE_CONTRAINTE * NombreDeContraintesE; + +ilMax+= INCREMENT_DALLOCATION_POUR_LA_MATRICE_DES_CONTRAINTES_PNE; + +#if VERBOSE_PNE + printf("Taille allouee pour la matrice des contrainte: %d \n", ilMax); +#endif + +Pne->TailleAlloueePourLaMatriceDesContraintes = ilMax; + +Pne->NuvarTrav = (int *) malloc( ilMax * sizeof( int ) ); +Pne->ATrav = (double *) malloc( ilMax * sizeof( double ) ); + +Pne->NumeroDeContrainteDeLaGub = (int *) malloc( NbGub * sizeof( int ) ); +Pne->ValeurDInstanciationPourLaGub = (int *) malloc( NbGub * sizeof( int ) ); + +Pne->CdebTrav = (int *) malloc( NbVarAlloc * sizeof( int ) ); +Pne->CNbTermTrav = (int *) malloc( NbVarAlloc * sizeof( int ) ); +Pne->CsuiTrav = (int *) malloc( ilMax * sizeof( int ) ); +Pne->NumContrainteTrav = (int *) malloc( ilMax * sizeof( int ) ); + +Pne->PaquetDeGauche = (int *) malloc( NbVmxGub * sizeof( int ) ); +Pne->PaquetDeDroite = (int *) malloc( NbVmxGub * sizeof( int ) ); +Pne->DimBranchementGub = NbVmxGub; + +Pne->LaVariableAUneValeurFractionnaire = (int *) malloc( NbVarAlloc * sizeof( int ) ); +Pne->SuivFrac = (int *) malloc( NbVarAlloc * sizeof( int ) ); + +Pne->UStrongBranching = (double *) malloc( NbVarAlloc * sizeof( double ) ); + +Pne->CoutOpt = LINFINI_PNE; +Pne->UOpt = (double *) malloc( NbVarAlloc * sizeof( double ) ); + +if ( + Pne->CorrespondanceVarEntreeVarNouvelle == NULL || + Pne->VariableAInverser == NULL || + Pne->VariableElimineeSansValeur == NULL || + Pne->NumeroDesVariablesNonFixes == NULL || + Pne->NumerosDesVariablesEntieresTrav == NULL || + Pne->TypeDeVariableTrav == NULL || + Pne->SeuilDeFractionnalite == NULL || + Pne->VariableBinaireBigM == NULL || + Pne->TypeDeBorneTrav == NULL || + Pne->TypeDeBorneTravSv == NULL || + Pne->UTrav == NULL || + Pne->S1Trav == NULL || + Pne->S2Trav == NULL || + Pne->UmaxTrav == NULL || + Pne->UmaxTravSv == NULL || + Pne->UminTrav == NULL || + Pne->UminTravSv == NULL || + Pne->UmaxEntree == NULL || + Pne->UminEntree == NULL || + Pne->LTrav == NULL || + Pne->CoutsReduits == NULL || + Pne->BTrav == NULL || + Pne->SensContrainteTrav == NULL || + Pne->CorrespondanceCntPneCntEntree == NULL || + Pne->VariablesDualesDesContraintesTrav == NULL || + Pne->MdebTrav == NULL || + Pne->NbTermTrav == NULL || + Pne->NuvarTrav == NULL || + Pne->ATrav == NULL || + Pne->NumeroDeContrainteDeLaGub == NULL || + Pne->ValeurDInstanciationPourLaGub == NULL || + Pne->CdebTrav == NULL || + Pne->CNbTermTrav == NULL || + Pne->CsuiTrav == NULL || + Pne->NumContrainteTrav == NULL || + Pne->PaquetDeGauche == NULL || + Pne->PaquetDeDroite == NULL || + Pne->LaVariableAUneValeurFractionnaire == NULL || + Pne->SuivFrac == NULL || + Pne->UStrongBranching == NULL || + Pne->UOpt == NULL + ) { + + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AllocProbleme \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +Pne->ContrainteActivable = NULL; + +Pne->NombreDeCoupesCalculees = 0; +Pne->Coefficient_CG = NULL; +Pne->IndiceDeLaVariable_CG = NULL; +Pne->ValeurLocale = NULL; +Pne->IndiceLocal = NULL; +Pne->ContrainteKnapsack = NULL; +Pne->CntDeBorneSupVariable = NULL; +Pne->CntDeBorneInfVariable = NULL; +Pne->ContrainteMixte = NULL; +Pne->FoisCntSuccesMirMarchandWolseyTrouvees = NULL; + +Pne->CoupesCalculees = NULL; +Pne->Coupes.B = NULL; +Pne->Coupes.PositionDeLaVariableDEcart = NULL; +Pne->Coupes.PositionDeLaVariableDEcartAGauche = NULL; +Pne->Coupes.PositionDeLaVariableDEcartADroite = NULL; +Pne->Coupes.Mdeb = NULL; +Pne->Coupes.NbTerm = NULL; +Pne->Coupes.Nuvar = NULL; +Pne->Coupes.A = NULL; +Pne->Coupes.TypeDeCoupe = NULL; + +Pne->CoutsReduitsAuNoeudRacine = NULL; +Pne->PositionDeLaVariableAuNoeudRacine = NULL; +/* +Pne->NumeroDeVariableCoutReduit = NULL; +Pne->CoutsReduitsAuNoeudRacineFoisDeltaBornes = NULL; +*/ + +Pne->ProbingOuNodePresolve = NULL; +Pne->ConflictGraph = NULL; +Pne->Cliques = NULL; +Pne->CoupesDeProbing = NULL; +Pne->ContraintesDeBorneVariable = NULL; +Pne->CoupesKNegligees = NULL; +Pne->CoupesGNegligees = NULL; + +/* Infos qui seront utilisees par le postsolve */ +Pne->NombreDOperationsDePresolve = 0; +Pne->TailleTypeDOperationDePresolve = 0; +Pne->TypeDOperationDePresolve = NULL; +Pne->IndexDansLeTypeDOperationDePresolve = NULL; + +Pne->IndexLibreVecteurDeSubstitution = 0; +Pne->NbVariablesSubstituees = 0; +Pne->NumeroDesVariablesSubstituees = NULL; +Pne->CoutDesVariablesSubstituees = NULL; +Pne->ContrainteDeLaSubstitution = NULL; +Pne->ValeurDeLaConstanteDeSubstitution = NULL; +Pne->IndiceDebutVecteurDeSubstitution = NULL; +Pne->NbTermesVecteurDeSubstitution = NULL; +Pne->CoeffDeSubstitution = NULL; +Pne->NumeroDeVariableDeSubstitution = NULL; + +Pne->NbCouplesDeVariablesColineaires = 0; +Pne->PremiereVariable = NULL; +Pne->XminPremiereVariable = NULL; +Pne->XmaxPremiereVariable = NULL; +Pne->DeuxiemeVariable = NULL; +Pne->XminDeuxiemeVariable = NULL; +Pne->XmaxDeuxiemeVariable = NULL; +Pne->ValeurDeNu = NULL; + +Pne->NbLignesSingleton = 0; +Pne->NumeroDeLaContrainteSingleton = NULL; +Pne->VariableDeLaContrainteSingleton = NULL; +Pne->SecondMembreDeLaContrainteSingleton = NULL; + +Pne->NbForcingConstraints = 0; +Pne->NumeroDeLaForcingConstraint = NULL; + +Pne->NbSuppressionsDeContraintesColineaires = 0; +Pne->ContrainteConservee = NULL; +Pne->ContrainteSupprimee = NULL; + +Pne->NombreDeContraintesInactives = 0; +Pne->NumeroDesContraintesInactives = NULL; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AugmenterLeNombreDeVariables( PROBLEME_PNE * Pne ) +{ +int NbVarAlloc; +/* +printf(" Augmentation du nombre de variables\n"); fflush(stdout); +*/ +NbVarAlloc = Pne->NombreDeVariablesAllouees + INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_VARIABLES_PNE; + +Pne->NombreDeVariablesAllouees = NbVarAlloc; + +Pne->CorrespondanceVarEntreeVarNouvelle = (int *) realloc( Pne->CorrespondanceVarEntreeVarNouvelle , NbVarAlloc * sizeof( int ) ); + +Pne->VariableAInverser = (char *) realloc( Pne->VariableAInverser , NbVarAlloc * sizeof( char ) ); + +Pne->VariableElimineeSansValeur = (int *) realloc( Pne->VariableElimineeSansValeur , NbVarAlloc * sizeof( int ) ); + +Pne->NumeroDesVariablesNonFixes = (int *) realloc( Pne->NumeroDesVariablesNonFixes , NbVarAlloc * sizeof( int ) ); +Pne->NumerosDesVariablesEntieresTrav = (int *) realloc( Pne->NumerosDesVariablesEntieresTrav , NbVarAlloc * sizeof( int ) ); +Pne->TypeDeVariableTrav = (int *) realloc( Pne->TypeDeVariableTrav , NbVarAlloc * sizeof( int ) ); +Pne->SeuilDeFractionnalite = (double *) realloc( Pne->SeuilDeFractionnalite , NbVarAlloc * sizeof( double ) ); +Pne->VariableBinaireBigM = (char *) realloc( Pne->VariableBinaireBigM , NbVarAlloc * sizeof( char ) ); +Pne->TypeDeBorneTrav = (int *) realloc( Pne->TypeDeBorneTrav , NbVarAlloc * sizeof( int ) ); +Pne->TypeDeBorneTravSv = (int *) realloc( Pne->TypeDeBorneTravSv , NbVarAlloc * sizeof( int ) ); + +Pne->UTrav = (double *) realloc( Pne->UTrav , NbVarAlloc * sizeof( double ) ); +Pne->S1Trav = (double *) realloc( Pne->S1Trav , NbVarAlloc * sizeof( double ) ); +Pne->S2Trav = (double *) realloc( Pne->S2Trav , NbVarAlloc * sizeof( double ) ); +Pne->UmaxTrav = (double *) realloc( Pne->UmaxTrav , NbVarAlloc * sizeof( double ) ); +Pne->UmaxTravSv = (double *) realloc( Pne->UmaxTravSv , NbVarAlloc * sizeof( double ) ); +Pne->UminTrav = (double *) realloc( Pne->UminTrav , NbVarAlloc * sizeof( double ) ); +Pne->UminTravSv = (double *) realloc( Pne->UminTravSv , NbVarAlloc * sizeof( double ) ); +Pne->UmaxEntree = (double *) realloc( Pne->UmaxEntree , NbVarAlloc * sizeof( double ) ); +Pne->UminEntree = (double *) realloc( Pne->UminEntree , NbVarAlloc * sizeof( double ) ); + +Pne->LTrav = (double *) realloc( Pne->LTrav , NbVarAlloc * sizeof( double ) ); +Pne->CoutsReduits = (double *) realloc( Pne->CoutsReduits , NbVarAlloc * sizeof( double ) ); + +Pne->CdebTrav = (int *) realloc( Pne->CdebTrav , NbVarAlloc * sizeof( int ) ); +Pne->CNbTermTrav = (int *) realloc( Pne->CNbTermTrav , NbVarAlloc * sizeof( int ) ); + +Pne->LaVariableAUneValeurFractionnaire = (int *) realloc( Pne->LaVariableAUneValeurFractionnaire , NbVarAlloc * sizeof( int ) ); +Pne->SuivFrac = (int *) realloc( Pne->SuivFrac , NbVarAlloc * sizeof( int ) ); + +Pne->UStrongBranching = (double *) realloc( Pne->UStrongBranching , NbVarAlloc * sizeof( double ) ); + +Pne->UOpt = (double *) realloc( Pne->UOpt , NbVarAlloc * sizeof( double ) ); + +if ( + Pne->CorrespondanceVarEntreeVarNouvelle == NULL || + Pne->VariableAInverser == NULL || + Pne->VariableElimineeSansValeur == NULL || + Pne->NumeroDesVariablesNonFixes == NULL || + Pne->NumerosDesVariablesEntieresTrav == NULL || + Pne->TypeDeVariableTrav == NULL || + Pne->SeuilDeFractionnalite == NULL || + Pne->VariableBinaireBigM == NULL || + Pne->TypeDeBorneTrav == NULL || + Pne->TypeDeBorneTravSv == NULL || + Pne->UTrav == NULL || + Pne->S1Trav == NULL || + Pne->S2Trav == NULL || + Pne->UmaxTrav == NULL || + Pne->UmaxTravSv == NULL || + Pne->UminTrav == NULL || + Pne->UminTravSv == NULL || + Pne->UmaxEntree == NULL || + Pne->UminEntree == NULL || + Pne->LTrav == NULL || + Pne->CoutsReduits == NULL || + Pne->CdebTrav == NULL || + Pne->CNbTermTrav == NULL || + Pne->LaVariableAUneValeurFractionnaire == NULL || + Pne->SuivFrac == NULL || + Pne->UStrongBranching == NULL || + Pne->UOpt == NULL + ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AugmenterLeNombreDeVariables\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AugmenterLeNombreDeContraintes( PROBLEME_PNE * Pne ) +{ +int NbCntAlloc; + +/*printf(" Augmentation du nombre de contraintes\n"); fflush(stdout);*/ + +NbCntAlloc = Pne->NombreDeContraintesAllouees + INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_CONTRAINTES_PNE; + +Pne->NombreDeContraintesAllouees = NbCntAlloc; + +Pne->BTrav = (double *) realloc( Pne->BTrav , NbCntAlloc * sizeof( double ) ); + +Pne->SensContrainteTrav = (char *) realloc( Pne->SensContrainteTrav , NbCntAlloc * sizeof( char ) ); +Pne->ContrainteSaturee = (int *) realloc( Pne->ContrainteSaturee , NbCntAlloc * sizeof( int ) ); + +Pne->CorrespondanceCntPneCntEntree = (int *) realloc( Pne->CorrespondanceCntPneCntEntree , NbCntAlloc * sizeof( int ) ); +Pne->VariablesDualesDesContraintesTrav = (double *) realloc( Pne->VariablesDualesDesContraintesTrav , NbCntAlloc * sizeof( double ) ); + +Pne->MdebTrav = (int *) realloc( Pne->MdebTrav , NbCntAlloc * sizeof( int ) ); +Pne->NbTermTrav = (int *) realloc( Pne->NbTermTrav , NbCntAlloc * sizeof( int ) ); + +if ( + Pne->BTrav == NULL || + Pne->SensContrainteTrav == NULL || + Pne->ContrainteSaturee == NULL || + Pne->CorrespondanceCntPneCntEntree == NULL || + Pne->VariablesDualesDesContraintesTrav == NULL || + Pne->MdebTrav == NULL || + Pne->NbTermTrav == NULL + ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AugmenterLeNombreDeContraintes\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +if ( Pne->ContrainteKnapsack != NULL ) { + Pne->ContrainteKnapsack = (char *) realloc( Pne->ContrainteKnapsack, NbCntAlloc * sizeof( char ) ); + if ( Pne->ContrainteKnapsack == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AugmenterLeNombreDeContraintes\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AugmenterLaTailleDeLaMatriceDesContraintes( PROBLEME_PNE * Pne ) +{ +int ilMax; + +/*printf(" Augmentation de la taille de la matrice des contraintes\n"); fflush(stdout);*/ + +ilMax = Pne->TailleAlloueePourLaMatriceDesContraintes + INCREMENT_DALLOCATION_POUR_LA_MATRICE_DES_CONTRAINTES_PNE; + +Pne->TailleAlloueePourLaMatriceDesContraintes = ilMax; + +Pne->NuvarTrav = (int *) realloc( Pne->NuvarTrav , ilMax * sizeof( int ) ); +Pne->ATrav = (double *) realloc( Pne->ATrav , ilMax * sizeof( double ) ); + +Pne->CsuiTrav = (int *) realloc( Pne->CsuiTrav , ilMax * sizeof( int ) ); +Pne->NumContrainteTrav = (int *) realloc( Pne->NumContrainteTrav , ilMax * sizeof( int ) ); + +if ( + Pne->NuvarTrav == NULL || + Pne->ATrav == NULL || + Pne->CsuiTrav == NULL || + Pne->NumContrainteTrav == NULL + ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AugmenterLaTailleDeLaMatriceDesContraintes\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AllocCoupes( PROBLEME_PNE * Pne ) +{ +int NbCntAlloc; int ilMax; + +NbCntAlloc = INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_CONTRAINTES_PNE; +ilMax = INCREMENT_DALLOCATION_POUR_LA_MATRICE_DES_CONTRAINTES_PNE; +/* +printf("Allocations memoire pour les coupes du PNE\n"); +*/ +Pne->Coupes.NombreDeContraintesAllouees = NbCntAlloc; +Pne->Coupes.TailleAlloueePourLaMatriceDesContraintes = ilMax; + +Pne->Coupes.B = (double *) malloc( NbCntAlloc * sizeof( double ) ); +Pne->Coupes.PositionDeLaVariableDEcart = (char *) malloc( NbCntAlloc * sizeof( char ) ); +Pne->Coupes.PositionDeLaVariableDEcartAGauche = (char *) malloc( NbCntAlloc * sizeof( char ) ); +Pne->Coupes.PositionDeLaVariableDEcartADroite = (char *) malloc( NbCntAlloc * sizeof( char ) ); + +Pne->Coupes.Mdeb = (int *) malloc( NbCntAlloc * sizeof( int ) ); +Pne->Coupes.NbTerm = (int *) malloc( NbCntAlloc * sizeof( int ) ); + +Pne->Coupes.Nuvar = (int *) malloc( ilMax * sizeof( int ) ); +Pne->Coupes.A = (double *) malloc( ilMax * sizeof( double ) ); + +Pne->Coupes.TypeDeCoupe = (char *) malloc( NbCntAlloc * sizeof( char ) ); + +if ( + Pne->Coupes.B == NULL || Pne->Coupes.PositionDeLaVariableDEcart == NULL || + Pne->Coupes.PositionDeLaVariableDEcartAGauche == NULL || Pne->Coupes.PositionDeLaVariableDEcartADroite == NULL || + Pne->Coupes.Mdeb == NULL || Pne->Coupes.NbTerm == NULL || + Pne->Coupes.Nuvar == NULL || Pne->Coupes.A == NULL || + Pne->Coupes.TypeDeCoupe == NULL + ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AllocCoupes\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AugmenterLeNombreDeCoupes( PROBLEME_PNE * Pne ) +{ +int NbCntAlloc; +/* +printf(" Augmentation du nombre de coupes\n"); fflush(stdout); +*/ +NbCntAlloc = Pne->Coupes.NombreDeContraintesAllouees + INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_CONTRAINTES_PNE; + +Pne->Coupes.NombreDeContraintesAllouees = NbCntAlloc; + +Pne->Coupes.B = (double *) realloc( Pne->Coupes.B , NbCntAlloc * sizeof( double ) ); +Pne->Coupes.PositionDeLaVariableDEcart = (char *) realloc( Pne->Coupes.PositionDeLaVariableDEcart, NbCntAlloc * sizeof( char ) ); + +Pne->Coupes.PositionDeLaVariableDEcartAGauche = (char *) realloc( Pne->Coupes.PositionDeLaVariableDEcartAGauche, NbCntAlloc * sizeof( char ) ); +Pne->Coupes.PositionDeLaVariableDEcartADroite = (char *) realloc( Pne->Coupes.PositionDeLaVariableDEcartADroite, NbCntAlloc * sizeof( char ) ); + +Pne->Coupes.Mdeb = (int *) realloc( Pne->Coupes.Mdeb , NbCntAlloc * sizeof( int ) ); +Pne->Coupes.NbTerm = (int *) realloc( Pne->Coupes.NbTerm , NbCntAlloc * sizeof( int ) ); + +Pne->Coupes.TypeDeCoupe = (char *) realloc( Pne->Coupes.TypeDeCoupe , NbCntAlloc * sizeof( char ) ); + +if ( + Pne->Coupes.B == NULL || Pne->Coupes.PositionDeLaVariableDEcart == NULL || + Pne->Coupes.PositionDeLaVariableDEcartAGauche == NULL || Pne->Coupes.PositionDeLaVariableDEcartADroite == NULL || + Pne->Coupes.Mdeb == NULL || Pne->Coupes.NbTerm == NULL || + Pne->Coupes.TypeDeCoupe == NULL + ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AugmenterLeNombreDeCoupes\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AugmenterLaTailleDeLaMatriceDesCoupes( PROBLEME_PNE * Pne ) +{ +int ilMax; +/* +printf(" Augmentation de la taille de la matrice des coupes\n"); fflush(stdout); +*/ +ilMax = Pne->Coupes.TailleAlloueePourLaMatriceDesContraintes + INCREMENT_DALLOCATION_POUR_LA_MATRICE_DES_CONTRAINTES_PNE; + +Pne->Coupes.TailleAlloueePourLaMatriceDesContraintes = ilMax; + + +Pne->Coupes.Nuvar = (int *) realloc( Pne->Coupes.Nuvar, ilMax * sizeof( int ) ); +Pne->Coupes.A = (double *) realloc( Pne->Coupes.A , ilMax * sizeof( double ) ); + +if ( Pne->Coupes.Nuvar == NULL || Pne->Coupes.A == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AugmenterLaTailleDeLaMatriceDesCoupes\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_LibereProbleme( PROBLEME_PNE * Pne ) +{ +int i; COUPE_CALCULEE ** Coupe; + +if ( Pne == NULL ) return; + +if ( Pne->ProblemeSpxDuSolveur != NULL ) { + SPX_LibererProbleme( (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur); + Pne->ProblemeSpxDuSolveur = NULL; +} + +if ( Pne->ProblemeSpxDuNoeudRacine != NULL ) { + SPX_LibererProbleme( (PROBLEME_SPX *) Pne->ProblemeSpxDuNoeudRacine ); + Pne->ProblemeSpxDuNoeudRacine = NULL; +} + +if ( Pne->MatriceDesContraintesAuNoeudRacine != NULL ) { + PNE_LibererMatriceDeContraintesDuSimplexeAuNoeudRacine( Pne->MatriceDesContraintesAuNoeudRacine ); +} + +/* Par precaution liberation des structures du BB au cas ou on serait sorti + suite a une erreur interne */ +if ( Pne->ProblemeBbDuSolveur != NULL ) { + BB_BranchAndBoundDesallouerProbleme( (BB *) Pne->ProblemeBbDuSolveur ); +} + +if ( Pne->ProblemePrsDuSolveur != NULL ) { + PRS_LiberationStructure( (PRESOLVE *) Pne->ProblemePrsDuSolveur ); +} + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + MEM_Quit( Pne->Tas ); + return; +# endif + +free( Pne->CorrespondanceVarEntreeVarNouvelle ); +free( Pne->VariableAInverser ); +free( Pne->VariableElimineeSansValeur ); +free( Pne->NumeroDesVariablesNonFixes ); +free( Pne->NumerosDesVariablesEntieresTrav ); +free( Pne->TypeDeVariableTrav ); +free( Pne->SeuilDeFractionnalite ); +free( Pne->VariableBinaireBigM ); +free( Pne->TypeDeBorneTrav ); +free( Pne->TypeDeBorneTravSv ); +free( Pne->UTrav ); +free( Pne->S1Trav ); +free( Pne->S2Trav ); +free( Pne->UmaxTrav ); +free( Pne->UmaxTravSv ); +free( Pne->UminTrav ); +free( Pne->UminTravSv ); +free( Pne->UmaxEntree ); +free( Pne->UminEntree ); +free( Pne->LTrav ); +free( Pne->CoutsReduits ); +free( Pne->BTrav ); +free( Pne->SensContrainteTrav ); +free( Pne->ContrainteSaturee ); +free( Pne->ContrainteActivable ); +free( Pne->CorrespondanceCntPneCntEntree ); +free( Pne->VariablesDualesDesContraintesTrav ); +free( Pne->VariablesDualesDesContraintesTravEtDesCoupes ); +free( Pne->MdebTrav ); +free( Pne->NbTermTrav ); +free( Pne->NuvarTrav ); +free( Pne->ATrav ); +free( Pne->NumeroDeContrainteDeLaGub ); +free( Pne->ValeurDInstanciationPourLaGub ); +free( Pne->CdebTrav ); +free( Pne->CNbTermTrav ); +free( Pne->CsuiTrav ); +free( Pne->NumContrainteTrav ); +free( Pne->PaquetDeGauche ); +free( Pne->PaquetDeDroite ); +free( Pne->LaVariableAUneValeurFractionnaire ); +free( Pne->SuivFrac ); +free( Pne->UStrongBranching ); +free( Pne->Coefficient_CG ); +free( Pne->IndiceDeLaVariable_CG ); +free( Pne->ValeurLocale ); +free( Pne->IndiceLocal ); +free( Pne->ContrainteKnapsack ); +free( Pne->CntDeBorneSupVariable ); +free( Pne->CntDeBorneInfVariable ); +free( Pne->ContrainteMixte ); +free( Pne->FoisCntSuccesMirMarchandWolseyTrouvees ); + +free( Pne->UOpt ); + +if ( Pne->ProbingOuNodePresolve != NULL ) { + free( Pne->ProbingOuNodePresolve->Buffer ); + free( Pne->ProbingOuNodePresolve ); +} + +if ( Pne->ConflictGraph != NULL ) { + free( Pne->ConflictGraph->First ); + free( Pne->ConflictGraph->Adjacent ); + free( Pne->ConflictGraph->Next ); + free( Pne->ConflictGraph ); +} + +if ( Pne->Cliques != NULL ) { + free( Pne->Cliques->First ); + free( Pne->Cliques->NbElements ); + free( Pne->Cliques->Noeud ); + free( Pne->Cliques->LaCliqueEstDansLePool ); + free( Pne->Cliques->CliqueDeTypeEgalite ); + free( Pne->Cliques->NumeroDeCliqueDuNoeud ); + free( Pne->Cliques ); +} + +if ( Pne->CoupesDeProbing != NULL ) { + free( Pne->CoupesDeProbing->SecondMembre ); + free( Pne->CoupesDeProbing->First ); + free( Pne->CoupesDeProbing->NbElements ); + free( Pne->CoupesDeProbing->Colonne ); + free( Pne->CoupesDeProbing->Coefficient ); + free( Pne->CoupesDeProbing->LaCoupDeProbingEstDansLePool ); + free( Pne->CoupesDeProbing ); +} + +if ( Pne->ContraintesDeBorneVariable != NULL ) { + free( Pne->ContraintesDeBorneVariable->SecondMembre ); + free( Pne->ContraintesDeBorneVariable->First ); + free( Pne->ContraintesDeBorneVariable->Colonne ); + free( Pne->ContraintesDeBorneVariable->Coefficient ); + free( Pne->ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool ); + free( Pne->ContraintesDeBorneVariable ); +} + +if ( Pne->CoupesKNegligees != NULL ) { + free( Pne->CoupesKNegligees->SecondMembre ); + free( Pne->CoupesKNegligees->First ); + free( Pne->CoupesKNegligees->NbElements ); + free( Pne->CoupesKNegligees->Colonne ); + free( Pne->CoupesKNegligees->Coefficient ); + free( Pne->CoupesKNegligees->LaCoupeEstDansLePool ); + free( Pne->CoupesKNegligees ); +} + +if ( Pne->CoupesGNegligees != NULL ) { + free( Pne->CoupesGNegligees->SecondMembre ); + free( Pne->CoupesGNegligees->First ); + free( Pne->CoupesGNegligees->NbElements ); + free( Pne->CoupesGNegligees->Colonne ); + free( Pne->CoupesGNegligees->Coefficient ); + free( Pne->CoupesGNegligees->LaCoupeEstDansLePool ); + free( Pne->CoupesGNegligees ); +} + +/* Ce qui suit ne serait a faire que dans le cas d'une PNE */ +if ( Pne->Coupes.NombreDeContraintesAllouees > 0 ) { + free( Pne->Coupes.B ); + free( Pne->Coupes.PositionDeLaVariableDEcart ); + free( Pne->Coupes.PositionDeLaVariableDEcartAGauche ); + free( Pne->Coupes.PositionDeLaVariableDEcartADroite ); + free( Pne->Coupes.Mdeb ); + free( Pne->Coupes.NbTerm ); + free( Pne->Coupes.Nuvar); + free( Pne->Coupes.A ); + free( Pne->Coupes.TypeDeCoupe ); +} + +/* Par precaution, liberation des coupes au niveau pne */ +if( Pne->NombreDeCoupesCalculees > 0 ) { + Coupe = Pne->CoupesCalculees; /* Pointeur sur le tableau de pointeurs sur les coupes */ + for ( i = 0 ; i < Pne->NombreDeCoupesCalculees ; i++ ) { + free( Coupe[i]->Coefficient ); + free( Coupe[i]->IndiceDeLaVariable ); + free( Coupe[i] ); + } + free( Pne->CoupesCalculees ); +} + +free( Pne->CoutsReduitsAuNoeudRacine ); +free( Pne->PositionDeLaVariableAuNoeudRacine ); +/* +free( Pne->NumeroDeVariableCoutReduit ); +free( Pne->CoutsReduitsAuNoeudRacineFoisDeltaBornes ); +*/ + +/* Informations pour le postsolve */ +free( Pne->TypeDOperationDePresolve ); +free( Pne->IndexDansLeTypeDOperationDePresolve ); + +free( Pne->NumeroDesVariablesSubstituees ); +free( Pne->CoutDesVariablesSubstituees ); +free( Pne->ContrainteDeLaSubstitution ); +free( Pne->ValeurDeLaConstanteDeSubstitution ); +free( Pne->IndiceDebutVecteurDeSubstitution ); +free( Pne->NbTermesVecteurDeSubstitution ); +free( Pne->CoeffDeSubstitution ); +free( Pne->NumeroDeVariableDeSubstitution ); + +free( Pne->PremiereVariable ); +free( Pne->XminPremiereVariable ); +free( Pne->XmaxPremiereVariable ); +free( Pne->DeuxiemeVariable ); +free( Pne->XminDeuxiemeVariable ); +free( Pne->XmaxDeuxiemeVariable ); +free( Pne->ValeurDeNu ); + +free( Pne->NumeroDeLaContrainteSingleton ); +free( Pne->VariableDeLaContrainteSingleton ); +free( Pne->SecondMembreDeLaContrainteSingleton ); + +free( Pne->NumeroDeLaForcingConstraint ); + +free( Pne->ContrainteConservee ); +free( Pne->ContrainteSupprimee ); + +free( Pne->NumeroDesContraintesInactives ); + +free( Pne->Controls ); + +free( Pne ); + +return; +} + + diff --git a/src/ext/Sirius_Solver/pne/pne_allocations_pour_le_postsolve.c b/src/ext/Sirius_Solver/pne/pne_allocations_pour_le_postsolve.c new file mode 100644 index 0000000000..0002178312 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_allocations_pour_le_postsolve.c @@ -0,0 +1,307 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Allocation des structures pour le postsolve + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_AllocationsPourLePostSolve( PROBLEME_PNE * Pne ) +{ +int NombreDeVariables; int NombreDeContraintes; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; + +/* Preparation des infos sur les reductions qui seront utilisees dans le postsolve */ +if ( Pne->NombreDOperationsDePresolve != 0 ) { + return; +} + +Pne->NombreDOperationsDePresolve = 0; +Pne->TailleTypeDOperationDePresolve = NombreDeVariables + NombreDeContraintes; + +Pne->TypeDOperationDePresolve = (char *) malloc( Pne->TailleTypeDOperationDePresolve * sizeof( char ) ); +if ( Pne->TypeDOperationDePresolve == NULL ) return; +Pne->IndexDansLeTypeDOperationDePresolve = (int *) malloc( Pne->TailleTypeDOperationDePresolve * sizeof( int ) ); +if ( Pne->IndexDansLeTypeDOperationDePresolve == NULL ) return; + +/* Colonnes colineaires */ +Pne->NbCouplesDeVariablesColineaires = 0; +Pne->PremiereVariable = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->PremiereVariable == NULL ) return; +Pne->XminPremiereVariable = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->XminPremiereVariable == NULL ) return; +Pne->XmaxPremiereVariable = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->XmaxPremiereVariable == NULL ) return; + +Pne->DeuxiemeVariable = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->DeuxiemeVariable == NULL ) return; +Pne->XminDeuxiemeVariable = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->XminDeuxiemeVariable == NULL ) return; +Pne->XmaxDeuxiemeVariable = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->XmaxDeuxiemeVariable == NULL ) return; + +Pne->ValeurDeNu = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->ValeurDeNu == NULL ) return; + +/* Variables non bornees substituees car colonne singleton ou variables substituees a + l'aide d'un doubleton */ +PNE_AllocTablesDeSubstitution( Pne ); + +/* Contraintes singleton */ +Pne->NbLignesSingleton = 0; +Pne->NumeroDeLaContrainteSingleton = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->NumeroDeLaContrainteSingleton == NULL ) return; +Pne->VariableDeLaContrainteSingleton = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->VariableDeLaContrainteSingleton == NULL ) return; +Pne->SecondMembreDeLaContrainteSingleton = (double *) malloc( NombreDeContraintes * sizeof( double ) ); +if ( Pne->SecondMembreDeLaContrainteSingleton == NULL ) return; + +/* Forcing constraints */ +Pne->NbForcingConstraints = 0; +Pne->NumeroDeLaForcingConstraint = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->NumeroDeLaForcingConstraint == NULL ) return; + +/* Contraintes colineaires */ +Pne->NbSuppressionsDeContraintesColineaires = 0; +Pne->ContrainteConservee = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->ContrainteConservee == NULL ) return; +Pne->ContrainteSupprimee = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->ContrainteSupprimee == NULL ) return; + +/* Contraintes desactivees */ +Pne->NombreDeContraintesInactives = 0; +Pne->NumeroDesContraintesInactives = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->NumeroDesContraintesInactives == NULL ) return; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AllocTablesDeSubstitution( PROBLEME_PNE * Pne ) +{ +int NombreDeVariables; int ilMax; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +ilMax = Pne->TailleAlloueePourLaMatriceDesContraintes; + +Pne->IndexLibreVecteurDeSubstitution = 0; +Pne->NbVariablesSubstituees = 0; + +Pne->NumeroDesVariablesSubstituees = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->NumeroDesVariablesSubstituees == NULL ) return; + +Pne->ValeurDeLaConstanteDeSubstitution = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->ValeurDeLaConstanteDeSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); + return; +} + +Pne->IndiceDebutVecteurDeSubstitution = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->IndiceDebutVecteurDeSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + return; +} + +Pne->NbTermesVecteurDeSubstitution = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->NbTermesVecteurDeSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); + return; +} + +Pne->CoeffDeSubstitution = (double *) malloc( ilMax * sizeof( double ) ); +if ( Pne->CoeffDeSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); free( Pne->NbTermesVecteurDeSubstitution ); + return; +} + +Pne->NumeroDeVariableDeSubstitution = (int *) malloc( ilMax * sizeof( int ) ); +if ( Pne->NumeroDeVariableDeSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); free( Pne->NbTermesVecteurDeSubstitution ); + free( Pne->CoeffDeSubstitution ); + return; +} + +Pne->CoutDesVariablesSubstituees = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->CoutDesVariablesSubstituees == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); free( Pne->NbTermesVecteurDeSubstitution ); + free( Pne->CoeffDeSubstitution ); free( Pne->NumeroDeVariableDeSubstitution ); + return; +} + +Pne->ContrainteDeLaSubstitution = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->ContrainteDeLaSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); free( Pne->NbTermesVecteurDeSubstitution ); + free( Pne->CoeffDeSubstitution ); free( Pne->NumeroDeVariableDeSubstitution ); + free( Pne->CoutDesVariablesSubstituees ); + return; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CleanPostSolve( PROBLEME_PNE * Pne ) +{ +int ilMax; int NombreDeVariables; + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + if ( Pne != NULL ) Pne->ProblemePrsDuSolveur = NULL; + MEM_Quit( Presolve->Tas ); + return; +# endif + +/* Recuperation de la place des reductions du presolve */ + +if ( Pne->NombreDOperationsDePresolve != 0 ) { + Pne->TailleTypeDOperationDePresolve = Pne->NombreDOperationsDePresolve; + Pne->TypeDOperationDePresolve = (char *) realloc( Pne->TypeDOperationDePresolve, Pne->TailleTypeDOperationDePresolve * sizeof( char ) ); + Pne->IndexDansLeTypeDOperationDePresolve = (int *) realloc( Pne->IndexDansLeTypeDOperationDePresolve, Pne->TailleTypeDOperationDePresolve * sizeof( int ) ); +} + +if ( Pne->NumeroDesVariablesSubstituees != NULL ) { + NombreDeVariables = Pne->NbVariablesSubstituees; + ilMax = Pne->IndexLibreVecteurDeSubstitution; + Pne->NumeroDesVariablesSubstituees = (int *) realloc( Pne->NumeroDesVariablesSubstituees, NombreDeVariables * sizeof( int ) ); + Pne->CoutDesVariablesSubstituees = (double *) realloc( Pne->CoutDesVariablesSubstituees, NombreDeVariables * sizeof( double ) ); + Pne->ContrainteDeLaSubstitution = (int *) realloc( Pne->ContrainteDeLaSubstitution, NombreDeVariables * sizeof( int ) ); + Pne->ValeurDeLaConstanteDeSubstitution = (double *) realloc( Pne->ValeurDeLaConstanteDeSubstitution, NombreDeVariables * sizeof( double ) ); + Pne->IndiceDebutVecteurDeSubstitution = (int *) realloc( Pne->IndiceDebutVecteurDeSubstitution, NombreDeVariables * sizeof( int ) ); + Pne->NbTermesVecteurDeSubstitution = (int *) realloc( Pne->NbTermesVecteurDeSubstitution, NombreDeVariables * sizeof( int ) ); + Pne->CoeffDeSubstitution = (double *) realloc( Pne->CoeffDeSubstitution, ilMax * sizeof( double ) ); + Pne->NumeroDeVariableDeSubstitution = (int *) realloc( Pne->NumeroDeVariableDeSubstitution, ilMax * sizeof( int ) ); +} +else { + free( Pne->NumeroDesVariablesSubstituees ); + free( Pne->CoutDesVariablesSubstituees ); + free( Pne->ContrainteDeLaSubstitution ); + free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); + free( Pne->NbTermesVecteurDeSubstitution ); + free( Pne->CoeffDeSubstitution ); + free( Pne->NumeroDeVariableDeSubstitution ); + Pne->NumeroDesVariablesSubstituees = NULL; + Pne->CoutDesVariablesSubstituees = NULL; + Pne->ContrainteDeLaSubstitution = NULL; + Pne->ValeurDeLaConstanteDeSubstitution = NULL; + Pne->IndiceDebutVecteurDeSubstitution = NULL; + Pne->NbTermesVecteurDeSubstitution = NULL; + Pne->CoeffDeSubstitution = NULL; + Pne->NumeroDeVariableDeSubstitution = NULL; +} + +if ( Pne->NbCouplesDeVariablesColineaires != 0 ) { + NombreDeVariables = Pne->NbCouplesDeVariablesColineaires; + Pne->PremiereVariable = (int *) realloc( Pne->PremiereVariable , NombreDeVariables * sizeof( int ) ); + Pne->XminPremiereVariable = (double *) realloc( Pne->XminPremiereVariable, NombreDeVariables * sizeof( double ) ); + Pne->XmaxPremiereVariable = (double *) realloc( Pne->XmaxPremiereVariable, NombreDeVariables * sizeof( double ) ); + Pne->DeuxiemeVariable = (int *) realloc( Pne->DeuxiemeVariable , NombreDeVariables * sizeof( int ) ); + Pne->XminDeuxiemeVariable = (double *) realloc( Pne->XminDeuxiemeVariable, NombreDeVariables * sizeof( double ) ); + Pne->XmaxDeuxiemeVariable = (double *) realloc( Pne->XmaxDeuxiemeVariable, NombreDeVariables * sizeof( double ) ); + Pne->ValeurDeNu = (double *) realloc( Pne->ValeurDeNu , NombreDeVariables * sizeof( double ) ); +} +else { + free( Pne->PremiereVariable ); + free( Pne->XminPremiereVariable ); + free( Pne->XmaxPremiereVariable ); + free( Pne->DeuxiemeVariable ); + free( Pne->XminDeuxiemeVariable ); + free( Pne->XmaxDeuxiemeVariable ); + free( Pne->ValeurDeNu ); + Pne->PremiereVariable = NULL; + Pne->XminPremiereVariable = NULL; + Pne->XmaxPremiereVariable = NULL; + Pne->DeuxiemeVariable = NULL; + Pne->XminDeuxiemeVariable = NULL; + Pne->XmaxDeuxiemeVariable = NULL; + Pne->ValeurDeNu = NULL; +} + +/* Contraintes singleton */ +if ( Pne->NbLignesSingleton != 0 ) { + ilMax = Pne->NbLignesSingleton; + Pne->NumeroDeLaContrainteSingleton = (int *) realloc( Pne->NumeroDeLaContrainteSingleton , ilMax * sizeof( int ) ); + Pne->VariableDeLaContrainteSingleton = (int *) realloc( Pne->VariableDeLaContrainteSingleton , ilMax * sizeof( int ) ); + Pne->SecondMembreDeLaContrainteSingleton = (double *) realloc( Pne->SecondMembreDeLaContrainteSingleton , ilMax * sizeof( double ) ); +} +else { + free( Pne->NumeroDeLaContrainteSingleton ); + free( Pne->VariableDeLaContrainteSingleton ); + free( Pne->SecondMembreDeLaContrainteSingleton ); + Pne->NumeroDeLaContrainteSingleton = NULL; + Pne->VariableDeLaContrainteSingleton = NULL; + Pne->SecondMembreDeLaContrainteSingleton = NULL; +} + +/* Forcing constraints */ +if ( Pne->NbForcingConstraints != 0 ) { + ilMax = Pne->NbForcingConstraints; + Pne->NumeroDeLaForcingConstraint = (int *) realloc( Pne->NumeroDeLaForcingConstraint, ilMax * sizeof( int ) ); +} +else { + free( Pne->NumeroDeLaForcingConstraint ); + Pne->NumeroDeLaForcingConstraint = NULL; +} + +/* Contraintes colineaires */ +if ( Pne->NbSuppressionsDeContraintesColineaires > 0 ) { + ilMax = Pne->NbSuppressionsDeContraintesColineaires; + Pne->ContrainteConservee = (int *) realloc( Pne->ContrainteConservee, ilMax * sizeof( int ) ); + Pne->ContrainteSupprimee = (int *) realloc( Pne->ContrainteSupprimee, ilMax * sizeof( int ) ); +} +else { + free( Pne->ContrainteConservee ); + free( Pne->ContrainteSupprimee ); + Pne->ContrainteConservee = NULL; + Pne->ContrainteSupprimee = NULL; +} + +/* Contraintes inactives */ +if ( Pne->NombreDeContraintesInactives != 0 ) { + ilMax = Pne->NombreDeContraintesInactives; + Pne->NumeroDesContraintesInactives = (int *) realloc( Pne->NumeroDesContraintesInactives, ilMax * sizeof( int ) ); +} +else { + free( Pne->NumeroDesContraintesInactives ); + Pne->NumeroDesContraintesInactives = NULL; +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/pne/pne_ameliorer_coefficients.c b/src/ext/Sirius_Solver/pne/pne_ameliorer_coefficients.c new file mode 100644 index 0000000000..2e6c56c504 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_ameliorer_coefficients.c @@ -0,0 +1,218 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Amelioration des coefficients des variables entieres + (cas des variables binaires uniquement). + La description de la methode se trouve dans l'article: + "Computational Integer Programming and cutting planes" + Armin Fugenschuh & Alexander Martin, page 6, 2001. + Mais on peut aussi la trouver dans d'autres articles. + Bien que ce calcul soit fait dans le presolve, on le fait + aussi apres le variable probing et la prise en compte + des coupes de probing car l'ensemble des contraintes n'est + plus le meme. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "prs_define.h" +# include "prs_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PNE_AmeliorerLesCoefficientsDesVariablesBinaires( PROBLEME_PNE * Pne, + void * Prs, + char Mode ) + +{ +int Var; int Cnt; int il; double Smax; int ilEntier; int NombreDeVariables; double Coeff; +int * TypeDeVariable; int * Cdeb; int * Csui; int * NumContrainte; char * SensContrainte; +int * Mdeb; int * NbTerm; int * Nuvar; double a; double * B; double * A; double PlusPetitTerme; +double * Xmin; double * Xmax; int NbIter; char CoeffModifie; double * Bmax; char * BmaxValide; +char * BorneInfConnue; int * TypeDeBornePourPresolve; char * ContrainteInactive; +int Faisabilite; double Marge; int NbModifications; int NbC; PRESOLVE * Presolve; + +if ( Pne->YaDesVariablesEntieres != OUI_PNE ) return; + +if ( Pne->ChainageTransposeeExploitable == NON_PNE ) PNE_ConstruireLeChainageDeLaTransposee( Pne ); + +Presolve = (PRESOLVE *) Prs; + +if ( Mode == MODE_PNE ) { + /* + printf( "On n'utilise pas AmeliorerLesCoefficientsDesVariablesBinaires si MODE_PNE \n"); + return; + */ + # if TRACES == 1 + printf("AmeliorerLesCoefficientsDesVariablesBinaires: MODE_PNE\n"); + # endif + + PNE_InitBorneInfBorneSupDesVariables( Pne ); + PNE_CalculMinEtMaxDesContraintes( Pne, &Faisabilite ); +} +else if ( Mode == MODE_PRESOLVE ) { + # if TRACES == 1 + printf("AmeliorerLesCoefficientsDesVariablesBinaires: MODE_PRESOLVE\n"); + # endif + PRS_CalculerLesBornesDeToutesLesContraintes( Presolve, &NbModifications ); +} +else return; + +Marge = MARGE_REDUCTION; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +PlusPetitTerme = Pne->PlusPetitTerme; +NbC = 0; + +Xmin = NULL; +Xmax = NULL; +BorneInfConnue = NULL; +BmaxValide = NULL; +Bmax = NULL; +TypeDeBornePourPresolve = NULL; +ContrainteInactive = NULL; + +if ( Mode == MODE_PNE ) { + Xmin = Pne->ProbingOuNodePresolve->ValeurDeBorneInf; + Xmax = Pne->ProbingOuNodePresolve->ValeurDeBorneSup; + BorneInfConnue = Pne->ProbingOuNodePresolve->BorneInfConnue; + BmaxValide = Pne->ProbingOuNodePresolve->BmaxValide; + Bmax = Pne->ProbingOuNodePresolve->Bmax; +} +else { + Xmin = Presolve->BorneInfPourPresolve; + Xmax = Presolve->BorneSupPourPresolve; + TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; + ContrainteInactive = Presolve->ContrainteInactive; + BmaxValide = Presolve->MaxContrainteCalcule; + Bmax = Presolve->MaxContrainte; +} + +NbIter = 0; +Debut: +CoeffModifie = NON_PNE; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeVariable[Var] != ENTIER ) continue; + if ( Mode == MODE_PNE ) { + if ( BorneInfConnue[Var] == FIXE_AU_DEPART ) continue; + } + else { + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) continue; + } + il = Cdeb[Var]; + while ( il >= 0 ) { + Cnt = NumContrainte[il]; + if ( SensContrainte[Cnt] == '=' ) goto ContrainteSuivante; + if ( Mode == MODE_PRESOLVE ) { + if ( ContrainteInactive[Cnt] == OUI_PNE ) goto ContrainteSuivante; + } + /* La contrainte est donc de type < , calcul du max du membre de gauche */ + ilEntier = il; + Coeff = A[ilEntier]; + if ( BmaxValide[Cnt] == OUI_PNE ) Smax = Bmax[Cnt]; + else goto ContrainteSuivante; + + if ( Smax <= B[Cnt] ) goto ContrainteSuivante; /* Contrainte redondante */ + + if ( Coeff < 0.0 ) { + if ( Smax + Coeff < B[Cnt] - EPS_COEFF_REDUCTION ) { + /* On peut diminuer le coeff de la variable entiere */ + a = B[Cnt] - Smax - Marge; + if ( fabs( a ) < PlusPetitTerme ) { + a = -PlusPetitTerme; + } + if ( a < Coeff ) goto ContrainteSuivante; + if ( fabs( a ) < fabs( Coeff) - DELTA_MIN_REDUCTION ) { + # if TRACES == 1 + printf(" Variable entiere %d contrainte %d, remplacement de son coefficient %e par %e \n",Var,Cnt,Coeff,a); + # endif + /* Mise a jour de MaxContrainte[Cnt] */ + Bmax[Cnt] -= Coeff * Xmin[Var]; + Bmax[Cnt] += a * Xmin[Var]; /* Meme si on sait que borne inf = 0 */ + /* Modif du coefficient */ + A[ilEntier] = a; + CoeffModifie = OUI_PNE; + NbC++; + } + } + } + else if ( Coeff > 0.0 ) { + if ( Smax - Coeff < B[Cnt] - EPS_COEFF_REDUCTION ) { + /* On peut diminuer le coeff de la variable entiere */ + a = Smax - B[Cnt] + Marge; + if ( fabs( a ) < PlusPetitTerme ) { + a = PlusPetitTerme; + } + if ( a > Coeff ) goto ContrainteSuivante; + if ( fabs( a ) < fabs( Coeff) - DELTA_MIN_REDUCTION ) { + # if TRACES == 1 + printf(" Variable entiere %d contrainte %d, remplacement de son coefficient %e par %e et B %e par %e\n",Var,Cnt,Coeff,a, + B[Cnt],Smax-Coeff+Marge); + # endif + /* Mise a jour de MaxContrainte[Cnt] */ + Bmax[Cnt] -= Coeff * Xmax[Var]; + Bmax[Cnt] += a * Xmax[Var]; + /* Modif du coefficient */ + A[ilEntier] = a; + B[Cnt] = Smax - Coeff + Marge; + CoeffModifie = OUI_PNE; + NbC++; + } + } + } + ContrainteSuivante: + il = Csui[il]; + } +} +if ( CoeffModifie == OUI_PNE ) { + # if TRACES == 1 + printf("AmeliorerLesCoefficientsDesVariablesBinaires : NbIter %d\n",NbIter); + # endif + NbIter++; + if ( NbIter < NB_ITER_MX_REDUCTION ) goto Debut; +} + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + if ( NbC != 0 ) printf("%d binary coefficient(s) reduced\n",NbC); +} + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_analyse_initiale_knapsack.c b/src/ext/Sirius_Solver/pne/pne_analyse_initiale_knapsack.c new file mode 100644 index 0000000000..e96f88756d --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_analyse_initiale_knapsack.c @@ -0,0 +1,172 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Analyse initiale des contraintes de sac a dos. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_AnalyseInitialeDesKnapsack( PROBLEME_PNE * Pne ) +{ +int Cnt; int il; int ilMax; int Var; char TypeBorne; char Inf; char Sup; int NbBin; +int * MdebTrav; int * NbTermTrav; int * NuvarTrav; int * TypeDeVariableTrav; double * ATrav; +char * ContrainteKnapsack; char * SensContrainteTrav; int * TypeDeBorneTrav; +char QueDesUn; + +if ( Pne->ContrainteKnapsack == NULL ) { + Pne->ContrainteKnapsack = (char *) malloc( Pne->NombreDeContraintesAllouees * sizeof( char ) ); + if ( Pne->ContrainteKnapsack == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AnalyseInitialeDesKnapsak \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} + +SensContrainteTrav = Pne->SensContrainteTrav; +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; +ATrav = Pne->ATrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; + +ContrainteKnapsack = Pne->ContrainteKnapsack; +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + ContrainteKnapsack[Cnt] = IMPOSSIBLE; +} + +/* +printf(" sortie des contraintes dans PNE_AnalyseInitialeDesKnapsack\n"); +printf("Nombre de contraintes: %d\n",Pne->NombreDeContraintesTrav); +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + printf("Contrainte %d\n",Cnt); + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var = NuvarTrav[il]; + TypeBorne = TypeDeBorneTrav[Var]; + if ( TypeBorne != VARIABLE_FIXE ) { + if ( TypeDeVariableTrav[Var] == ENTIER ) { + printf("%e (i_%d) ",ATrav[il],Var); + } + else { + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES ) printf("%e (cb2_%d) ",ATrav[il],Var); + else if ( TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) printf("%e (cbs_%d) ",ATrav[il],Var); + else if ( TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) printf("%e (cbi_%d) ",ATrav[il],Var); + else if ( TypeBorne == VARIABLE_NON_BORNEE ) printf("%e (cnb_%d) ",ATrav[il],Var); + } + } + il++; + } + printf(" %c %e\n",SensContrainteTrav[Cnt],Pne->BTrav[Cnt]); +} +exit(0); +*/ + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + /* Limite sur le nombre de variables */ + QueDesUn = OUI_PNE; + Inf = INF_POSSIBLE; + Sup = SUP_POSSIBLE; + NbBin = 0; + # if KNAPSACK_SUR_CONTRAINTES_DEGALITE == NON_PNE + if ( SensContrainteTrav[Cnt] == '=' ) { + Inf = IMPOSSIBLE; + Sup = IMPOSSIBLE; + continue; + } + # endif + if ( SensContrainteTrav[Cnt] == '<' ) Sup = IMPOSSIBLE; + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var = NuvarTrav[il]; + TypeBorne = TypeDeBorneTrav[Var]; + if ( TypeBorne == VARIABLE_FIXE ) goto NextIl; + if ( fabs( ATrav[il] ) != 1.0 && ATrav[il] != 0.0 ) QueDesUn = NON_PNE; + if ( TypeDeVariableTrav[Var] == ENTIER ) { + NbBin++; + goto NextIl; + } + /* La variable n'est pas entiere */ + if ( ATrav[il] < 0.0 ) { + if ( Inf != IMPOSSIBLE ) { + /* Il faut monter la variable au max */ + if ( TypeBorne != VARIABLE_BORNEE_DES_DEUX_COTES && TypeBorne != VARIABLE_BORNEE_SUPERIEUREMENT ) { + Inf = IMPOSSIBLE; + } + } + if ( Sup != IMPOSSIBLE ) { + /* Il faut baisser la variable au min */ + if ( TypeBorne != VARIABLE_BORNEE_DES_DEUX_COTES && TypeBorne != VARIABLE_BORNEE_INFERIEUREMENT ) { + Sup = IMPOSSIBLE; + } + } + } + else if ( ATrav[il] > 0.0 ) { + if ( Inf != IMPOSSIBLE ) { + /* Il faut baisser la variable au min */ + if ( TypeBorne != VARIABLE_BORNEE_DES_DEUX_COTES && TypeBorne != VARIABLE_BORNEE_INFERIEUREMENT ) { + Inf = IMPOSSIBLE; + } + } + if ( Sup != IMPOSSIBLE ) { + /* Il faut monter la variable au max */ + if ( TypeBorne != VARIABLE_BORNEE_DES_DEUX_COTES && TypeBorne != VARIABLE_BORNEE_SUPERIEUREMENT ) { + Sup = IMPOSSIBLE; + } + } + } + + NextIl: + if ( Inf == IMPOSSIBLE && Sup == IMPOSSIBLE ) break; + il++; + } + + /* Synthese */ + if ( NbBin >= MIN_TERMES_POUR_KNAPSACK && NbBin <= MAX_TERMES_POUR_KNAPSACK ) { + if ( Inf == INF_POSSIBLE ) { + if ( QueDesUn == NON_PNE ) { + if ( Sup == SUP_POSSIBLE ) ContrainteKnapsack[Cnt] = INF_ET_SUP_POSSIBLE; + else ContrainteKnapsack[Cnt] = INF_POSSIBLE; + } + } + else if ( Sup == SUP_POSSIBLE ) { + if ( QueDesUn == NON_PNE ) { + ContrainteKnapsack[Cnt] = SUP_POSSIBLE; + } + } + } + +} + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_analyse_initiale_variable_bounds.c b/src/ext/Sirius_Solver/pne/pne_analyse_initiale_variable_bounds.c new file mode 100644 index 0000000000..39954616db --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_analyse_initiale_variable_bounds.c @@ -0,0 +1,199 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recherche des bornes variables. + Une borne variable est une contrainte de type + x < a * y avec x continue et y binaire. + Apres translation des bornes on a en realite + x < b + a * y + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_AnalyseInitialeDesBornesVariables( PROBLEME_PNE * Pne ) +{ +int Cnt; int il; int ilMax; int Var; int NbBin; double X; +int NbCont; int VarCont; int VarBin; double CoeffCont; double CoeffBin; int * Mdeb; int * NbTerm; +int * Nuvar; int * TypeDeVariable; double * A; int * CntDeBorneSupVariable; +int * CntDeBorneInfVariable; char * SensContrainte; int * TypeDeBorne; int ilDeb; +char YaDesBornesVariables; double * Umin; double * Umax; double * B; int Nb; +int NombreDeVariables; int NombreDeContraintes; + +if ( Pne->CntDeBorneSupVariable != NULL && Pne->CntDeBorneInfVariable != NULL ) return; + +if ( Pne->CntDeBorneSupVariable == NULL ) { + Pne->CntDeBorneSupVariable = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); + if ( Pne->CntDeBorneSupVariable == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AnalyseInitialeDesBornesVariables \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} +if ( Pne->CntDeBorneInfVariable == NULL ) { + Pne->CntDeBorneInfVariable = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); + if ( Pne->CntDeBorneInfVariable == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AnalyseInitialeDesBornesVariables \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} + +Nb = 0; +YaDesBornesVariables = NON_PNE; +CntDeBorneSupVariable = Pne->CntDeBorneSupVariable; +CntDeBorneInfVariable = Pne->CntDeBorneInfVariable; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + CntDeBorneSupVariable[Var] = -1; + CntDeBorneInfVariable[Var] = -1; +} + +SensContrainte = Pne->SensContrainteTrav; +NbTerm = Pne->NbTermTrav; +B = Pne->BTrav; +Mdeb = Pne->MdebTrav; +Nuvar = Pne->NuvarTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +Umin = Pne->UminTrav; +Umax = Pne->UmaxTrav; +A = Pne->ATrav; +CoeffBin = 0.0; +CoeffCont = 0.0; + +/* Marquage des variables continues soumises a une borne sup ou inf variable */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( SensContrainte[Cnt] != '<' ) continue; + if ( NbTerm[Cnt] != 2 ) continue; + /* Rq: il faudrait ne pas tester la nullite de BTrav car il y a eu translation + des bornes mais ca marche pas dans les MIR de Marchand-Wolsey */ + if ( B[Cnt] != 0.0 ) continue; + NbCont = 0; + NbBin = 0; + VarCont = -1; + VarBin = -1; + ilDeb = Mdeb[Cnt]; + il = ilDeb; + ilMax = il + 2; + while ( il < ilMax ) { + Var = Nuvar[il]; + if ( TypeDeBorne[Var] != VARIABLE_FIXE ) { + if ( TypeDeVariable[Var] == ENTIER ) { + NbBin++; + VarBin = Var; + CoeffBin = A[il]; + if ( CoeffBin == 0.0 ){ + NbBin = 0; + break; + } + } + else { + NbCont++; + VarCont = Var; + CoeffCont = A[il]; + if ( CoeffCont == 0.0 ) { + NbCont = 0; + break; + } + } + } + il++; + } + + /* Attention a la restriction: pour l'instant on a 1 seule variable bound par variable */ + + if ( NbCont == 1 && NbBin == 1 && VarCont != -1 && VarBin != -1 ) { + Nb++; + YaDesBornesVariables = OUI_PNE; + + Pne->ChainageTransposeeExploitable = NON_PNE; + + /* C'est une contrainte de borne variable */ + /* Pour avoir la borne on a besoin du second membre et du coeff. de la variable entiere. + Pour cela on normalise par abs(CoeffCont). On range la variable entiere en premier + pour y acceder plus vite */ + X = fabs( CoeffCont ); + A[ilDeb] = CoeffBin / X; + Nuvar[ilDeb] = VarBin; + A[ilDeb+1] = CoeffCont / X; + Nuvar[ilDeb+1] = VarCont; + B[Cnt] /= X; + if ( CoeffCont > 0.0 ) { + CntDeBorneSupVariable[VarCont] = Cnt; + if ( -A[ilDeb] >= 0.0 ) X = B[Cnt] - A[ilDeb]; + else X = B[Cnt]; + if ( TypeDeBorne[VarCont] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Umax[VarCont] = X; + TypeDeBorne[VarCont] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else if ( TypeDeBorne[VarCont] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( Umax[VarCont] > X ) Umax[VarCont] = X; + } + } + else { + CntDeBorneInfVariable[VarCont] = Cnt; + if ( A[ilDeb] >= 0.0 ) X = -B[Cnt]; + else X = -B[Cnt] + A[ilDeb]; + /* Attention a la translation des bornes si on arrive sur Umin superieur a 0 donc on met 0.0 */ + /* Il faut le faire avant de translater les bornes */ + /* + if ( TypeDeBorne[VarCont] == VARIABLE_NON_BORNEE ) { + Umin[VarCont] = X; + TypeDeBorne[VarCont] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( TypeDeBorne[VarCont] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Umin[VarCont] = X; + TypeDeBorne[VarCont] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else { + if ( Umin[VarCont] < X ) Umin[VarCont] = X; + } + */ + } + } +} + +if ( YaDesBornesVariables == NON_PNE ) { + /*printf(" ATTENTION PAS DE BORNES VARIABLES\n");*/ + free( Pne->CntDeBorneSupVariable ); + free( Pne->CntDeBorneInfVariable ); + Pne->CntDeBorneSupVariable = NULL; + Pne->CntDeBorneInfVariable = NULL; +} + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + if ( YaDesBornesVariables == OUI_PNE ) printf("Variable bounds detected in native constraints\n"); +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_archiver_la_solution_courante.c b/src/ext/Sirius_Solver/pne/pne_archiver_la_solution_courante.c new file mode 100644 index 0000000000..fea02233ba --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_archiver_la_solution_courante.c @@ -0,0 +1,183 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Appele par le branch and bound pour archiver la solution + courante lorsqu'elle est admissible et que c'est la + meilleur trouvee, et pour restituer la solution optimale + qui a ete archivee + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +void PNE_ModifierLaContrainteDeCoutMax( PROBLEME_PNE * ); + +/*----------------------------------------------------------------------------*/ + +void PNE_ModifierLaContrainteDeCoutMax( PROBLEME_PNE * Pne ) +{ +int Cnt; int Var; PROBLEME_SPX * Spx; double BCoutMax; int * TypeDeBorneSv; +double * CoutLineaire; double * X; int NombreDeVariables; int NombreDeContraintes; +double * Xopt; double * XminSv; double * XmaxSv; int CntSpx; int VarSpx; +BB * Bb; double AbsBCoutMax; + +NombreDeVariables = Pne->NombreDeVariablesTrav ; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +TypeDeBorneSv = Pne->TypeDeBorneTravSv; +CoutLineaire = Pne->LTrav; +X = Pne->UTrav; +Xopt = Pne->UOpt; +XminSv = Pne->UminTravSv; +XmaxSv = Pne->UmaxTravSv; + +Cnt = Pne->NumeroDeLaContrainteDeCoutMax; +/* Controle */ +if ( Cnt != NombreDeContraintes - 1 ) { + printf("Attention, erreur grave detectee dans PNE_ModifierLaContrainteDeCoutMax:\n"); + printf(" La contrainte de cout max n'est pas la derniere contrainte ce qui devrait etre le cas.\n"); +} +else { + /* On peut utiliser Bb->CoutDeLaMeilleureSolutionEntiere car ici on est appele par la partie + Branch and Bound */ + BCoutMax = 0.0; + Bb = (BB *) Pne->ProblemeBbDuSolveur; + if ( Bb != NULL ) { + BCoutMax = Pne->CoutOpt; + AbsBCoutMax = fabs( BCoutMax ); + if ( AbsBCoutMax > 1.e+7 ) BCoutMax -= 1.0; + else if ( AbsBCoutMax > 1.e+5 ) BCoutMax -= 0.1; + else if ( AbsBCoutMax > 1.e+3 ) BCoutMax -= 0.01; + else if ( AbsBCoutMax > 1.e+1 ) BCoutMax -= 0.001; + else if ( AbsBCoutMax > 1.e-1 ) BCoutMax -= 0.0001; + else if ( AbsBCoutMax > 1.e-3 ) BCoutMax -= 0.00001; + else if ( AbsBCoutMax > 1.e-5 ) BCoutMax -= 0.000001; + else BCoutMax -= 0.0000001; + + /*printf("CoutOpt %e BCoutMax %e ecart %e\n",Pne->CoutOpt,BCoutMax,Pne->CoutOpt-BCoutMax);*/ + Pne->BTrav[Cnt] = BCoutMax; + } + /* Attention, il faut aussi modifier dans le simplexe car le hot start standard de ce simplexe ne prend en compte + automatiquement que les changements de bornes */ + Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur; + if ( Spx != NULL ) { + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + /* La participation des variables fixes doit etre deduite de BCoutMax */ + if ( TypeDeBorneSv[Var] == VARIABLE_FIXE ) { + BCoutMax -= CoutLineaire[Var] * X[Var]; + } + } + /* On met a jour certaines valeurs dans le simplexe */ + CntSpx = Spx->CorrespondanceCntEntreeCntSimplexe[Cnt]; + if ( CntSpx >= 0 && CntSpx < Spx->NombreDeContraintesDuProblemeSansCoupes ) { + Spx->BAvantTranslationEtApresScaling[CntSpx] = BCoutMax * Spx->ScaleB[CntSpx]; + } + else { + printf("Attention, erreur grave detectee dans PNE_ModifierLaContrainteDeCoutMax:\n"); + printf(" La contrainte de cout max n'existe pas dans le simplexe.\n"); + } + } +} + +Var = Pne->NumeroDeLaVariableDEcartPourCoutMax; +/* Controle */ +if ( Var < 0 ) { + printf("Attention, erreur grave detectee dans PNE_ModifierLaContrainteDeCoutMax:\n"); + printf(" La variable d'ecart de la contrainte de cout max n'est pas la derniere variable ce qui devrait etre le cas.\n"); +} +else { + TypeDeBorneSv[Var] = VARIABLE_BORNEE_INFERIEUREMENT; + XminSv[Var] = 0.; + XmaxSv[Var] = LINFINI_PNE; + Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur; + if ( Spx != NULL ) { + VarSpx = Spx->CorrespondanceVarEntreeVarSimplexe[Var]; + if ( VarSpx >= 0 ) { + Spx->XminEntree[VarSpx] = 0.0; + } + else { + printf("Attention, erreur grave detectee dans PNE_ModifierLaContrainteDeCoutMax:\n"); + printf(" La variable d'ecart de la contrainte de cout max n'existe pas dans le simplexe.\n"); + } + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_ArchiverLaSolutionCourante( PROBLEME_PNE * Pne ) +{ +int Cnt; int Var; double * CoutLineaire; double * X; int NombreDeVariables; +int NombreDeContraintes; double * Xopt; double CoutOpt; double * VariablesDualesDesContraintes; +double * VariablesDualesDesContraintesEtDesCoupes; + +NombreDeVariables = Pne->NombreDeVariablesTrav ; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +CoutLineaire = Pne->LTrav; +X = Pne->UTrav; +Xopt = Pne->UOpt; + +Pne->YaUneSolutionEntiere = OUI_PNE; + +CoutOpt = Pne->Z0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + Xopt[Var] = X[Var]; + CoutOpt += CoutLineaire[Var] * X[Var]; +} +Pne->CoutOpt = CoutOpt; + +VariablesDualesDesContraintes = Pne->VariablesDualesDesContraintesTrav; +VariablesDualesDesContraintesEtDesCoupes = Pne->VariablesDualesDesContraintesTravEtDesCoupes; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + VariablesDualesDesContraintes[Cnt] = VariablesDualesDesContraintesEtDesCoupes[Cnt]; +} + +# if UTILISER_UNE_CONTRAINTE_DE_COUT_MAX == OUI_PNE + if ( Pne->YaDesVariablesEntieres == OUI_PNE ) { + PNE_ModifierLaContrainteDeCoutMax( Pne ); + } +# endif + +/* On fait le reduced cost fixing au noeud racine */ +if ( Pne->YaDesVariablesEntieres == OUI_PNE ) { + PNE_ReducedCostFixingAuNoeudRacine( Pne ); +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_RestituerLaSolutionArchivee( PROBLEME_PNE * Pne ) +{ +memcpy( (char *) Pne->UTrav , (char *) Pne->UOpt , Pne->NombreDeVariablesTrav * sizeof( double ) ); +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_bb_solve_pb_rlx.c b/src/ext/Sirius_Solver/pne/pne_bb_solve_pb_rlx.c new file mode 100644 index 0000000000..f64b19b066 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_bb_solve_pb_rlx.c @@ -0,0 +1,481 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Appele par le branch and bound (ou branch and cut) pour + resoudre un probleme relaxe. + +Le sous_programme recoit: + - la liste des variables entieres fixees + - les variables entieres non encore fixees + +il renvoit: + - la valeur du critere optimise + - un indicateur d'existence de solution + - un indicateur: la solution est entiere ou non + - les valeurs des variables entieres pour permettre le branchement + - les valeurs de toutes les variables + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" +# include "prs_fonctions.h" + +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_BranchAndBoundSolvePbRlx( + PROBLEME_PNE * Pne, + /* Entree */ + char PremiereResolutionAuNoeudRacine, /* Vaut OUI_PNE ou NON_PNE */ + int NumeroDePasse, + char * CalculerDesCoupes, /* Vaut OUI_PNE ou NON_PNE */ + char ChoisirLaVariableAInstancier, /* Vaut OUI_PNE ou NON_PNE */ + int * NombreDeVariablesInstanciees , + int * IndicesDesVariablesInstanciees, + char * VariableAZeroOuAUn , + /* Pour le simplexe */ + double * CoutDeLaMeilleureSolutionEntiere , /* En entree seulement */ + int * UtiliserCoutDeLaMeilleureSolutionEntiere , + int * BaseFournie , /* En entree seulement */ + int * PositionDeLaVariable , /* En entree et sortie */ + int * NbVarDeBaseComplementaires , /* En entree et sortie */ + int * ComplementDeLaBase , /* En entree et sortie */ + /* */ + /* Sortie */ + double * Critere , + int * Faisabilite , + int * LaSolutionEstEntiere , + int * VariableProposee , + double * MinorantEspereAEntierInf , + double * MinorantEspereAEntierSup , + double * ResultatSurLesVariablesEntieres , + double * ResultatSurToutesLesVariables , + /* Bases proposées associées ŕ la variable proposée pour l'instanciation */ + int * PositionDeLaVariableAEntierInf , + int * NbVarDeBaseComplementairesAEntierInf, + int * ComplementDeLaBaseAEntierInf , + int * PositionDeLaVariableAEntierSup , + int * NbVarDeBaseComplementairesAEntierSup, + int * ComplementDeLaBaseAEntierSup , + /* Indicateur de disponibilite des bases a entier sup et inf */ + int * BasesFilsDisponibles + ) +{ +int i ; int j ; NOEUD * Noeud; BB * Bb; /*int * TypeDeBorneTravSv;*/ double * UminTrav; +double * UmaxTrav; int * NumeroDeLaVariableModifiee; char * TypeDeBorneModifiee; +double * NouvelleValeurDeBorne; char RelancerUnSimplexe; double * UTrav; + +# if UTILISER_UNE_CONTRAINTE_DE_COUT_MAX == OUI_PNE + *UtiliserCoutDeLaMeilleureSolutionEntiere = NON; +# endif + +Bb = Pne->ProblemeBbDuSolveur; +Noeud = Bb->NoeudEnExamen; + +*Faisabilite = OUI_PNE ; +*LaSolutionEstEntiere = NON_PNE; +*BasesFilsDisponibles = NON_PNE; + +/* Pour les Gub */ +Pne->NbVarGauche = 0; +Pne->NbVarDroite = 0; + +memcpy( (char *) Pne->TypeDeBorneTrav , (char *) Pne->TypeDeBorneTravSv, Pne->NombreDeVariablesTrav * sizeof( int ) ); + +/* On met les bornes des variables au noeud */ +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; +UTrav = Pne->UTrav; + +memcpy( (char *) UminTrav, (char *) Pne->UminTravSv, Pne->NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char *) UmaxTrav, (char *) Pne->UmaxTravSv, Pne->NombreDeVariablesTrav * sizeof( double ) ); + +NumeroDeLaVariableModifiee = Noeud->NumeroDeLaVariableModifiee; +TypeDeBorneModifiee = Noeud->TypeDeBorneModifiee; +NouvelleValeurDeBorne = Noeud->NouvelleValeurDeBorne; + +for( i = 0 ; i < Noeud->NombreDeBornesModifiees ; i++ ) { + if ( TypeDeBorneModifiee[i] == BORNE_INF ) { + UminTrav[NumeroDeLaVariableModifiee[i]] = NouvelleValeurDeBorne[i]; + } + else if ( TypeDeBorneModifiee[i] == BORNE_SUP ) { + UmaxTrav[NumeroDeLaVariableModifiee[i]] = NouvelleValeurDeBorne[i]; + } + else { + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("PNE_BranchAndBoundSolvePbRlx: erreur dans la limitation des bornes (etape reduced cost fixing)\n"); + } + } +} + +/* Modification des types de bornes */ +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( Pne->TypeDeBorneTrav[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( Pne->UmaxTrav[i] - Pne->UminTrav[i] < PLAGE_REDUCED_COST_FIXING ) { + Pne->TypeDeBorneTrav[i] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + } + else if ( Pne->TypeDeBorneTrav[i] == VARIABLE_NON_BORNEE ) { + if ( Pne->UmaxTrav[i] - Pne->UminTrav[i] < PLAGE_REDUCED_COST_FIXING ) { + Pne->TypeDeBorneTrav[i] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else if ( Pne->UminTrav[i] > -PLAGE_REDUCED_COST_FIXING ) { + Pne->TypeDeBorneTrav[i] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( Pne->UmaxTrav[i] < PLAGE_REDUCED_COST_FIXING ) { + /* A ce stade on ne peut plus utiliser le type de borne VARIABLE_BORNEE_SUPERIEUREMENT sans trop de complication */ + /* Pne->TypeDeBorneTrav[i] = VARIABLE_BORNEE_SUPERIEUREMENT; */ + } + } +} + +for ( j = 0 ; j < *NombreDeVariablesInstanciees ; j++ ) { + i = IndicesDesVariablesInstanciees[j]; + if ( i < 0 ) { + printf("PNE_SolvePbRlxBranchAndBound: bug dans la connexion au Branch and Bound variable instanciee %d \n", i); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } + + if ( Pne->SolveurPourLeProblemeRelaxe != SIMPLEXE ) Pne->TypeDeBorneTrav[i] = VARIABLE_FIXE; + else { /* Cas du simplexe, on ne peut fixer la variable que si elle n'etait pas en base */ + /* On ne gagne pas grand chose a fixer les variables alors on laisse le type de borne inchangé et + on se contente de mettre a jour les bornes de la variable */ + /* Inhibition, maintenant on ne change plus les types des variables en cours de route */ + /*if ( PositionDeLaVariable[i] != EN_BASE ) Pne->TypeDeBorneTrav[i] = VARIABLE_FIXE;*/ + } + + if ( VariableAZeroOuAUn[j] == '0' ) { + + if ( Pne->UminTravSv[i] > 0.1 ) { + /*printf("Probleme relaxe: pas de solution des le depart\n");*/ + *Faisabilite = NON_PNE ; + goto Fin; + } + + UminTrav[i] = 0.; /* Umin est egal a 0 car il y a eu une translation des bornes en entree */ + UmaxTrav[i] = 0.; + UTrav [i] = 0.; + } + else if ( VariableAZeroOuAUn[j] == '1' ) { + + if ( Pne->UmaxTravSv[i] < 0.9 ) { + /*printf("Probleme relaxe: pas de solution des le depart\n");*/ + *Faisabilite = NON_PNE ; + goto Fin; + } + + UminTrav[i] = 1./*Pne->UmaxTrav[i]*/; + UmaxTrav[i] = 1./*Pne->UmaxTrav[i]*/; + UTrav [i] = 1./*Pne->UmaxTrav[i]*/; + } + else { + printf("PNE_SolvePbRlxBranchAndBound: bug dans la connexion au Branch and Bound \n"); + printf(" variable instanciee %d\n valeur variable instanciee %c \n",i,VariableAZeroOuAUn[j]); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} + +/* Nouvelle modification des types de bornes */ +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( Pne->TypeDeBorneTrav[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( Pne->UmaxTrav[i] - Pne->UminTrav[i] < PLAGE_REDUCED_COST_FIXING ) { + /*printf("Ancien TypeDeBorneTrav %d modifie\n",Pne->TypeDeBorneTrav[i]);*/ + Pne->TypeDeBorneTrav[i] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + } + else if ( Pne->TypeDeBorneTrav[i] == VARIABLE_NON_BORNEE ) { + if ( Pne->UmaxTrav[i] - Pne->UminTrav[i] < PLAGE_REDUCED_COST_FIXING ) { + Pne->TypeDeBorneTrav[i] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else if ( Pne->UminTrav[i] > -PLAGE_REDUCED_COST_FIXING ) { + Pne->TypeDeBorneTrav[i] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( Pne->UmaxTrav[i] < PLAGE_REDUCED_COST_FIXING ) { + /* A ce stade on ne peut plus utiliser le type de borne VARIABLE_BORNEE_SUPERIEUREMENT sans trop de complication */ + /* Pne->TypeDeBorneTrav[i] = VARIABLE_BORNEE_SUPERIEUREMENT; */ + } + } + if ( Pne->TypeDeBorneTrav[i] == VARIABLE_NON_BORNEE ) { + /* On remet l'infini */ + UminTrav[i] = -LINFINI_PNE; + UmaxTrav[i] = LINFINI_PNE; + } +} + +/* Node presolve */ +# if FAIRE_DU_NODE_PRESOLVE == OUI_PNE + if ( Pne->YaDesVariablesEntieres == OUI_PNE && NumeroDePasse == 1 ) { + /* Attention il ne faut l'appeler qu'au premier calcul */ + PNE_NodePresolve( Pne, Faisabilite ); + } +# endif + +PNE_ControleCliquesAvantResolutionProblemeRelaxe( Pne, Faisabilite ); + +if ( Pne->SolveurPourLeProblemeRelaxe == POINT_INTERIEUR ) { + /* Resolution du probleme relaxe par le point interieur */ + PNE_SolvePbRlxPi( Pne, Critere, Faisabilite ); + if ( *Faisabilite == OUI_PNE ) { + PNE_CalculerLaValeurDuCritere( Pne ); + *Critere = Pne->Critere; + } +} +else if ( Pne->SolveurPourLeProblemeRelaxe == SIMPLEXE ) { + if ( *Faisabilite == OUI_PNE ) { + SimplexeDual: + /* On essaie de restreindre les bornes des variables entieres (et donc de les fixer) */ + { int NombreDeVariablesEntieresFixees; char InfaisabiliteDetectee; char Mode; + Mode = CALCUL; + PNE_CalculerLesRestrictionsDeBornes( Pne, &NombreDeVariablesEntieresFixees, &InfaisabiliteDetectee, Mode ); + } + /* */ + /* On essaie de fixer des variables entieres */ + if ( Pne->YaDesVariablesEntieres == OUI_PNE ) { + PNE_FixationDesVariablesEntieresSurCritere( Pne ); + } + /* Resolution du probleme par le simplexe dual */ + PNE_SolvePbRlxSpxDual( Pne, PremiereResolutionAuNoeudRacine, *CoutDeLaMeilleureSolutionEntiere, + *UtiliserCoutDeLaMeilleureSolutionEntiere, *BaseFournie, PositionDeLaVariable, + NbVarDeBaseComplementaires, ComplementDeLaBase, Faisabilite ); + + if ( *Faisabilite == OUI_PNE ) { + PNE_CalculerLaValeurDuCritere( Pne ); + *Critere = Pne->Critere; + if ( Pne->YaDesVariablesEntieres == OUI_PNE ) { + if ( Pne->YaUneSolutionEntiere == OUI_PNE ) { + if ( Pne->Critere >= Pne->CoutOpt ) *Faisabilite = NON_PNE; + } + } + } + + if ( Pne->YaDesVariablesEntieres == OUI_PNE ) { + if ( *Faisabilite == OUI_PNE ) { + if ( Bb != NULL ) { + if ( Bb->NoeudEnExamen == Bb->NoeudRacine ) { + PNE_ArchivagesPourReducedCostFixingAuNoeudRacine( Pne, PositionDeLaVariable, Pne->CoutsReduits, Pne->Critere ); + } + } + } + } + + /* Reduced cost fixing */ + if ( *Faisabilite == OUI_PNE && Pne->YaUneSolutionEntiere == OUI_PNE ) { + RelancerUnSimplexe = PNE_ReducedCostFixing( Pne, PositionDeLaVariable ); + if ( RelancerUnSimplexe == OUI_PNE ) { + #if VERBOSE_PNE + printf(" ReducedCostFixing : OnAFixeDesVariablesEntieres\n"); + #endif + PremiereResolutionAuNoeudRacine = NON_PNE; + *BaseFournie = OUI_SPX; + goto SimplexeDual; + } + } + } + +} +else { + printf(" Bug dans PNE_BranchAndBoundSolvePbRlx, Pne->SolveurPourLeProblemeRelaxe mal initialise\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +if ( *Faisabilite == OUI_PNE ) { + + Pne->FaireDuStrongBranching = OUI_PNE; + + PNE_DeterminerLesVariablesFractionnaires( Pne, PositionDeLaVariable ); + + /* En test: clonage du simplexe au noeud racine pour le reactiver de temps en temps */ + /* S'il s'agit d'un probleme a variables entieres */ + # if RELANCE_PERIODIQUE_DU_SIMPLEXE_AU_NOEUD_RACINE == OUI_PNE + if ( Pne->YaDesVariablesEntieres == OUI_PNE ) { + /* S'il s'agit du dernier simplexe au noeud etudie */ + if ( ChoisirLaVariableAInstancier == OUI_PNE ) { + /* S'il s'agit du noeud racine */ + if ( Bb->NoeudEnExamen == Bb->NoeudRacine && Pne->Controls == NULL ) { + /* Si le probleme a une solution et qu'il reste des variables fractionnaires */ + if ( *Faisabilite == OUI_PNE && Pne->NombreDeVariablesAValeurFractionnaire != 0 ) { + PNE_CloneProblemeSpxDuNoeudRacine( Pne, PositionDeLaVariable, NbVarDeBaseComplementaires, ComplementDeLaBase ); + } + } + } + } + # endif + + # if UTILISER_LE_GRAPHE_DE_CONFLITS == OUI_PNE + # if PROBING_JUSTE_APRES_LE_PRESOLVE == NON_PNE + if ( Pne->YaDesVariablesEntieres == OUI_PNE && Noeud == Bb->NoeudRacine ) { + PNE_VariableProbing( Pne ); + if ( Pne->ProbingOuNodePresolve != NULL ) { + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) *Faisabilite = NON_PNE; + else PNE_CliquesConflictGraph( Pne ); + } + } + # endif + # endif + +} + +if ( *Faisabilite == OUI_PNE ) { + + PNE_StrongBranching( Pne, + /*PositionDeLaVariable,*/ + /* Choix de la variable a instancier */ + MinorantEspereAEntierInf, + MinorantEspereAEntierSup, + /* Base correspondante pour l'instanciation a 0 */ + PositionDeLaVariableAEntierInf , + NbVarDeBaseComplementairesAEntierInf, + ComplementDeLaBaseAEntierInf , + /* Base correspondante pour l'instanciation a 1 */ + PositionDeLaVariableAEntierSup , + NbVarDeBaseComplementairesAEntierSup, + ComplementDeLaBaseAEntierSup , + /* */ + BasesFilsDisponibles , + CalculerDesCoupes , + /*NumeroDePasse,*/ + ChoisirLaVariableAInstancier + ); + + if( Pne->CestTermine == OUI_PNE ) { + #if VERBOSE_PNE + printf(" Probleme relaxe: on a trouve une solution entiere \n"); + #endif + *LaSolutionEstEntiere = OUI_PNE; + if ( 0 ) { /* Pas de traces s'il y a un 0 dans le if */ + { int Nb; int Var; int NbVar; + for ( Var = 0 , NbVar = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Pne->UmaxTravSv[Var] != Pne->UminTravSv[Var] ) NbVar++; + } + for ( Var = 0 , Nb = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Pne->UmaxTravSv[Var] == Pne->UminTravSv[Var] ) { + if ( fabs( Pne->UmaxTrav[Var] - Pne->UTrav[Var] ) < 1.e-6 && Pne->LTrav[Var] != 0.0 ) Nb++; + } + } + printf("-------------------- nombre de variables a cout non nul a 1 par le presolve : %d nombre de variables %d\n",Nb,NbVar); + for ( Var = 0 , Nb = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( fabs( Pne->UmaxTrav[Var] - Pne->UTrav[Var] ) < 1.e-6 ) Nb++; + } + printf("-------------------- nombre de variables a 1 : %d nombre de variables %d\n",Nb,NbVar); + for ( Var = 0 , Nb = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( fabs( Pne->UmaxTrav[Var] - Pne->UTrav[Var] ) < 1.e-6 && Pne->LTrav[Var] != 0.0 ) Nb++; + } + printf("-------------------- nombre de variables a cout non nul a 1 : %d nombre de variables %d\n",Nb,NbVar); + for ( Var = 0 , Nb = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Pne->UmaxTravSv[Var] == Pne->UminTravSv[Var] ) continue; + if ( Pne->UmaxTrav[Var] == Pne->UminTrav[Var] ) { + if ( fabs( Pne->UmaxTrav[Var] - Pne->UTrav[Var] ) < 1.e-6 && Pne->LTrav[Var] != 0.0 ) Nb++; + } + } + printf("-------------------- nombre de variables a cout non nul a 1 par instanciation : %d nombre de variables %d\n",Nb,NbVar); + for ( Var = 0 , Nb = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Pne->UmaxTravSv[Var] == Pne->UminTravSv[Var] ) continue; + if ( Pne->UmaxTrav[Var] == Pne->UminTrav[Var] ) { + if ( fabs( Pne->UmaxTrav[Var] - Pne->UTrav[Var] ) < 1.e-6 ) Nb++; + } + } + printf("-------------------- nombre de variables a 1 par instanciation : %d nombre de variables %d\n",Nb,NbVar); + } + } + } + else { + *VariableProposee = Pne->VariableLaPlusFractionnaire; + } + + /* On recupere la sortie */ + for ( j = 0 , i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + ResultatSurToutesLesVariables[i] = Pne->UTrav[i]; + if ( Pne->TypeDeVariableTrav[i] == ENTIER ) { + ResultatSurLesVariablesEntieres[j] = Pne->UTrav[i]; + j++; + } + } + +} +else { + Pne->ResolutionDuNoeudReussie = NON_PNE; +} + +/* Calcul de coupes et stockage */ +/* On calcule les coupes, puis on relance un simplexe au meme noeud. Ensuite on ne stocke reellement + que les coupes pour lesquelles la variable d'ecart est non basique c'est ŕ dire les coupes saturees */ +if ( *Faisabilite == OUI_PNE ) { + if( ChoisirLaVariableAInstancier == OUI_PNE ) { + if ( Bb != NULL ) BB_RechercherLesCoupesViolees( Bb, Pne->UTrav ); + } + /* Init necessaire au cas ou on n'appellerait pas PNE_CalculerLesCoupes car alors les valeurs ne seraient + pas initialisees */ + Pne->NombreDeCoupesCalculeesNonEvaluees = 0; + Pne->NombreDeCoupesAjoute = 0; + if ( *CalculerDesCoupes == OUI_PNE ) { + if ( Pne->SolveurPourLeProblemeRelaxe != POINT_INTERIEUR && Pne->PremFrac >= 0 ) { + /* Identification des contraintes saturees */ + /*PNE_RechercheDesContraintesSaturees( Pne, *NbVarDeBaseComplementaires, ComplementDeLaBase );*/ + PNE_CalculerLesCoupes( Pne ); + *VariableProposee = Pne->VariableLaPlusFractionnaire; + } + } + else if ( Pne->SolveurPourLeProblemeRelaxe != POINT_INTERIEUR ) { + /* Tri des coupes */ + /* L'appel doit se faire au niveau du branch and bound + PNE_TrierLesCoupesDeGomory( *BasesFilsDisponibles , CoupeSaturee , CoupeSatureeAEntierInf , CoupeSatureeAEntierSup ); + */ + } +} +else { + /* Remise a 0 necessaire car on peut calculer des coupes et sortir ensuite par depassement du majorant */ + /* Pne->NombreDeCoupesCalculees = 0; */ +} + +/* Le calcul est termine, on tente l'heuristique */ +if ( *Faisabilite == OUI_PNE && ChoisirLaVariableAInstancier == OUI_PNE ) { + PNE_Heuristique( Pne, *CoutDeLaMeilleureSolutionEntiere, *UtiliserCoutDeLaMeilleureSolutionEntiere, + PositionDeLaVariable, *NbVarDeBaseComplementaires, ComplementDeLaBase ); + if( Pne->CestTermine == OUI_PNE ) { + *LaSolutionEstEntiere = OUI_PNE; + } +} + +Fin: + +/* On remet les bornes comme elles etaient et l'indicateur fixe ou non comme il etait */ +memcpy( (char *) Pne->TypeDeBorneTrav , (char *) Pne->TypeDeBorneTravSv, Pne->NombreDeVariablesTrav * sizeof( int ) ); + +/* Par prudence a cause du reduced cost fixing: il faut mieux repartir de UminTravSv et UmaxTravSv */ +memcpy( (char *) UminTrav, (char *) Pne->UminTravSv, Pne->NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char *) UmaxTrav, (char *) Pne->UmaxTravSv, Pne->NombreDeVariablesTrav * sizeof( double ) ); + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_calcul_coupes_dintersection.c b/src/ext/Sirius_Solver/pne/pne_calcul_coupes_dintersection.c new file mode 100644 index 0000000000..4c09301cee --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_calcul_coupes_dintersection.c @@ -0,0 +1,133 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul des coupes d'intersection (necessite d'avoir + calcule les gomory avant) + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void PNE_CalculerLesCoupesDIntersection( PROBLEME_PNE * Pne ) +{ +int i; int j; int NbPotentielDeCoupes; int NombreDeTermes; double S; double X; +double SecondMembre; double PlusGrandCoeff; char OnAEcrete; double Y; int NombreDeVariablesTrav; +double RapportMaxDesCoeffs; double ZeroPourCoeffVariablesDEcart; double ZeroPourCoeffVariablesNative; +double RelaxRhsAbs; double RelaxRhsRel; int * IndiceDeLaVariable; double * Coefficient; +double * UTrav; + +RapportMaxDesCoeffs = RAPPORT_MAX_COEFF_COUPE_INTERSECTION; +ZeroPourCoeffVariablesDEcart = ZERO_POUR_COEFF_VARIABLE_DECART_DANS_COUPE_GOMORY_OU_INTERSECTION; +ZeroPourCoeffVariablesNative = ZERO_POUR_COEFF_VARIABLE_NATIVE_DANS_COUPE_GOMORY_OU_INTERSECTION; +RelaxRhsAbs = RELAX_RHS_INTERSECTION_ABS; +RelaxRhsRel = RELAX_RHS_INTERSECTION_REL; + +IndiceDeLaVariable = Pne->IndiceDeLaVariable_CG; +Coefficient = Pne->Coefficient_CG; +NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; +UTrav = Pne->UTrav; + +/* C'est la reduction des normes qui prend le plus de temps et de loin */ +SPX_ReductionDesNormesPourCoupesDIntersection( (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur ); + +NbPotentielDeCoupes = SPX_NombrePotentielDeCoupesDIntersection( (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur ); + +/* NbPotentielDeCoupes ne joue pas sur le temps car SPX_CalculerUneCoupeDIntersection est tres rapide */ + +# if CALCULER_COUPES_DINTERSECTION == NON_PNE + SPX_TerminerLeCalculDesCoupesDIntersection( (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur ); + return; +# endif + +for ( i = 0 ; i < NbPotentielDeCoupes ; i++ ) { + SPX_CalculerUneCoupeDIntersection( + (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur, + i, + + RapportMaxDesCoeffs, + ZeroPourCoeffVariablesDEcart, + ZeroPourCoeffVariablesNative, + RelaxRhsAbs, + RelaxRhsRel, + + &NombreDeTermes, + Coefficient, + IndiceDeLaVariable, + &SecondMembre, + &OnAEcrete ); + + if ( NombreDeTermes <= 0 ) continue; + + PlusGrandCoeff = -LINFINI_PNE; + S = 0.0; + for ( j = 0 ; j < NombreDeTermes ; j++ ) { + Y = Coefficient[j]; + if ( IndiceDeLaVariable[j] < NombreDeVariablesTrav ) { + S += Y * UTrav[IndiceDeLaVariable[j]]; + if ( fabs( Y ) > PlusGrandCoeff ) PlusGrandCoeff = fabs( Y ); + } + } + + if ( S > SecondMembre ) { + X = fabs( SecondMembre - S ); + if ( X > SEUIL_VIOLATION_COUPE_DINTERSECTION ) { + + /* + printf("Coupe d'Intersection Violation %e NombreDeTermes %d (max.: %d)\n",X,NombreDeTermes,Pne->NombreDeVariablesTrav); + for ( i = 0 ; i < NombreDeTermes ; i++ ) { + printf(" %e (%d) + ",Coefficient[i],IndiceDeLaVariable[i]); + } + printf(" < %e\n",SecondMembre); + fflush( stdout ); + */ + + PNE_NormaliserUnCoupe( Pne->Coefficient_CG, &SecondMembre, NombreDeTermes, PlusGrandCoeff ); + + PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'I', NombreDeTermes, SecondMembre, X, + Coefficient, IndiceDeLaVariable ); + + # if KNAPSACK_SUR_COUPE_DINTERSECTION == OUI_SPX + /* Il faut le faire apres le stockage de la coupe car la recherche des knapsack modifie + Pne->Coefficient_CG et Pne->IndiceDeLaVariable_CG */ + /* On regarde si on peut faire une K sur la coupe */ + if ( X > VIOLATION_MIN_POUR_K_SUR_COUPE && OnAEcrete != OUI_SPX ) { + PNE_CalculerUneKnapsackSurGomoryOuIntersection( Pne, Coefficient, IndiceDeLaVariable, + SecondMembre, NombreDeTermes, PlusGrandCoeff ); + } + # endif + + } + } + +} + +SPX_TerminerLeCalculDesCoupesDIntersection( (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur ); + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_calculer_la_valeur_du_critere.c b/src/ext/Sirius_Solver/pne/pne_calculer_la_valeur_du_critere.c new file mode 100644 index 0000000000..4afbedae56 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_calculer_la_valeur_du_critere.c @@ -0,0 +1,53 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul du critere. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void PNE_CalculerLaValeurDuCritere( PROBLEME_PNE * Pne ) +{ +int i ; + +/* Calcul du critere */ +Pne->Critere = Pne->Z0; + +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) Pne->Critere+= Pne->LTrav[i] * Pne->UTrav[i]; + +#if VERBOSE_PNE + printf(" Valeur du critere apres optimisation du probleme relaxe: %lf \n",Pne->Critere); + printf(" ******************************************************** \n"); +#endif + +if ( Pne->NombreDeCoupesCalculees == 0 ) Pne->ValeurOptimaleDuProblemeCourantAvantNouvellesCoupes = Pne->Critere; + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_calculer_les_coupes.c b/src/ext/Sirius_Solver/pne/pne_calculer_les_coupes.c new file mode 100644 index 0000000000..53f1eaa939 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_calculer_les_coupes.c @@ -0,0 +1,351 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul des coupes + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define PROPORTION_DE_COUPES_INSEREES 1.0 /* Coefficient qui s'applique au nombre de coupes calculees pour determiner + le nombre max. de coupes conservees apres un tri en fonction de la + distance du point courant */ + +# define NOMBRE_MIN_DE_COUPES_INSEREES 25 /* Si la proportion du nombre de coupes inserees conduit a un nombre trop + faible de coupes, on le remplace par ce nombre */ + +# define NOMBRE_MAX_DE_COUPES_INSEREES_FIXE_A_LAVANCE NON_PNE /* Si OUI_PNE on prend NOMBRE_MAX_DE_COUPES_INSEREES + si NON_PNE on prend PROPORTION_MAX_DE_COUPES_INSEREES * nb de contraintes */ +# define NOMBRE_MAX_DE_COUPES_INSEREES 200 +# define PROPORTION_MAX_DE_COUPES_INSEREES 0.2 /*0.1*/ + +# define SEUIL_INHIB_GOMORY 1.e-5 /*1.e-4*/ + +int PNE_PartitionCoupeTriRapide( COUPE_CALCULEE ** , int , int ); +void PNE_CoupeTriRapide( COUPE_CALCULEE ** , int , int ); + +/*----------------------------------------------------------------------------*/ + +int PNE_PartitionCoupeTriRapide( COUPE_CALCULEE ** CoupesCalculees, int Deb, int Fin ) +{ +int Compt; double Pivot; int i; COUPE_CALCULEE * Coupe; +Compt = Deb; +Pivot = CoupesCalculees[Deb]->Distance; +/* Ordre decroissant */ +for ( i = Deb + 1 ; i <= Fin ; i++) { + if ( CoupesCalculees[i]->Distance > Pivot) { + Compt++; + Coupe = CoupesCalculees[Compt]; + CoupesCalculees[Compt] = CoupesCalculees[i]; + CoupesCalculees[i] = Coupe; + } +} +Coupe = CoupesCalculees[Compt]; +CoupesCalculees[Compt] = CoupesCalculees[Deb]; +CoupesCalculees[Deb] = Coupe; +return(Compt); +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CoupeTriRapide( COUPE_CALCULEE ** CoupesCalculees, int Debut, int Fin ) +{ +int Pivot; +if ( Debut < Fin ) { + Pivot = PNE_PartitionCoupeTriRapide( CoupesCalculees, Debut, Fin ); + PNE_CoupeTriRapide( CoupesCalculees, Debut , Pivot-1 ); + PNE_CoupeTriRapide( CoupesCalculees, Pivot+1, Fin ); +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CalculerLesCoupes( PROBLEME_PNE * Pne ) +{ +int i; COUPE_CALCULEE * Coupe; int NbMxCoupes; int NbI; char OnInverse ; int iMax; +int NbCoupesInserees; char ContrainteSaturee; int NbTermesMx ; int DernierIndex; +int FinDeBoucle; int NombreDeCoupesDejaCalculees; BB * Bb; int Plim; char InhiberGomory; +double SeuilAdm; double S; int Cnt; int il; int ilMax; int * MdebTrav; int * NbTermTrav; +int * NuvarTrav; double * ATrav; double * UTrav; char * SensContrainteTrav; double * BTrav; + +PNE_MiseAJourDesSeuilDeSelectionDesCoupes( Pne ); + +Bb = Pne->ProblemeBbDuSolveur; + +/* Au premier passage on alloue les vecteurs pour les coupes */ +if ( Pne->Coefficient_CG == NULL ) { + Pne->Coefficient_CG = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); + Pne->IndiceDeLaVariable_CG = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); + if ( Pne->Coefficient_CG == NULL || Pne->IndiceDeLaVariable_CG == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_CalculerLesCoupes \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} +if ( Pne->ValeurLocale == NULL ) { + Pne->ValeurLocale = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); + Pne->IndiceLocal = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); + if ( Pne->ValeurLocale == NULL || Pne->IndiceLocal == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_CalculerLesCoupes \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} + +Pne->NombreDeCoupesCalculeesNonEvaluees = 0; + +Pne->NombreDeCoupesAjoute = 0; + +NombreDeCoupesDejaCalculees = Pne->NombreDeCoupesCalculees; + +# if UTILISER_LE_GRAPHE_DE_CONFLITS == OUI_PNE + PNE_DetectionDesCliquesViolees( Pne ); + # if UTILISER_LES_COUPES_DE_PROBING == OUI_PNE + PNE_DetectionDesCoupesDeProbingViolees( Pne ); + # endif + # if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + PNE_DetectionDesContraintesDeBorneVariableViolees( Pne ); + # endif +# endif + +PNE_DetectionKnapsackNegligeesViolees( Pne ); +PNE_DetectionGomoryNegligeesViolees( Pne ); + +/* Test: pas concluant pour l'instant*/ +/* +PNE_TwoStepMirSurContrainte( Pne ); +*/ +/* Fin Test */ + +/* Calcul des coupes de Gomory */ +/* Lorsque le Gap est tres petit, la partie Branch and Bound redemande les calculs de coupe. Plim a + pour objectif d'eviter le calcul des Gomory si la profondeur est trop grande. Par contre on + calculera quand-meme les autres types de coupes */ + +Plim = 1000 /*30*/; /* Il ne faut pas trop s'opposer au calcul cyclique des coupes */ + +if ( Bb->CalculerDesCoupesDeGomory == OUI_PNE && Bb->NoeudEnExamen->ProfondeurDuNoeud <= Plim ) { + + InhiberGomory = NON_PNE; + /* On verifie au moins l'admissibilite primale sur les contraintes (hors coupes) avant de lancer + un calcul de coupes de Gomory */ + MdebTrav = Pne->MdebTrav; + NbTermTrav = Pne->NbTermTrav; + ATrav = Pne->ATrav; + UTrav = Pne->UTrav; + NuvarTrav = Pne->NuvarTrav; + SensContrainteTrav = Pne->SensContrainteTrav; + BTrav = Pne->BTrav; + SeuilAdm = SEUIL_INHIB_GOMORY; + for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + S = 0.; + while ( il < ilMax ) { + S += ATrav[il] * UTrav[NuvarTrav[il]]; + il++; + } + if ( SensContrainteTrav[Cnt] == '=' ) { + if ( fabs( S - BTrav[Cnt] ) > SeuilAdm ) { + InhiberGomory = OUI_PNE; + break; + } + } + else if ( SensContrainteTrav[Cnt] == '<' ) { + if ( S > BTrav[Cnt] + SeuilAdm ) { + InhiberGomory = OUI_PNE; + break; + } + } + else if ( SensContrainteTrav[Cnt] == '>' ) { + if ( S < BTrav[Cnt] - SeuilAdm ) { + InhiberGomory = OUI_PNE; + break; + } + } + } + # if CALCULER_COUPES_DE_GOMORY == OUI_PNE + if ( InhiberGomory == NON_PNE ) { + PNE_Gomory( Pne ); + /* Attention, pour les desactiver il faut aussi intervenir dans le simplexe */ + PNE_CalculerLesCoupesDIntersection( Pne ); + } + # endif +} + +/* Knapsack */ +/* Pas concluant */ +/* +if ( Pne->PremFrac >= 0 && 0 ) { + PNE_KnapsackSurCombinaisonsComplexesDeContraintes( Pne ); +} +*/ + +# if CALCULER_COUPES_KNAPSACK_SIMPLE == OUI_PNE + if ( Pne->PremFrac >= 0 ) { + PNE_CoverKnapsackSimple( Pne ); + } +# endif + +/* Marchand Wolsey */ +# if CALCULER_MIR_MARCHAND_WOLSEY == OUI_PNE + if ( Pne->PremFrac >= 0 ) { + PNE_MIRMarchandWolsey( Pne ); + } +# endif + +#if VERBOSE_PNE + printf("-> Pne->NombreDeCoupesCalculees %d\n",Pne->NombreDeCoupesCalculees); +#endif + +/* Maintenant, on nettoie la structure temporaire de stockage des coupes en fonction de l'ampleur + des violations de contraintes de la solution courante */ +goto AB; +OnInverse = OUI_PNE; +iMax = Pne->NombreDeCoupesCalculees - 1; +while ( OnInverse == OUI_PNE ) { + OnInverse = NON_PNE; + for ( i = NombreDeCoupesDejaCalculees ; i < iMax ; i++ ) { + if ( Pne->CoupesCalculees[i]->Distance < Pne->CoupesCalculees[i+1]->Distance ) { + OnInverse = OUI_PNE; + /* On Inverse les pointeurs */ + Coupe = Pne->CoupesCalculees[i + 1]; + Pne->CoupesCalculees[i+1] = Pne->CoupesCalculees[i]; + Pne->CoupesCalculees[i] = Coupe; + } + } +} +goto AC; +AB: +i = NombreDeCoupesDejaCalculees; +iMax = Pne->NombreDeCoupesCalculees - 1; +if ( Pne->CoupesCalculees != NULL ) PNE_CoupeTriRapide( Pne->CoupesCalculees, i, iMax ); +AC: +/* */ + +NbMxCoupes = (int) (PROPORTION_DE_COUPES_INSEREES * ( Pne->NombreDeCoupesCalculees - NombreDeCoupesDejaCalculees ) ); +if ( NbMxCoupes < NOMBRE_MIN_DE_COUPES_INSEREES ) NbMxCoupes = NOMBRE_MIN_DE_COUPES_INSEREES; + +/* Init du nombre max de termes pour conserver un creux "honorable" */ +NbTermesMx = Pne->NombreDeVariablesTrav + Pne->NombreDeContraintesDInegalite - Pne->NombreDeContraintesTrav; +NbTermesMx = (int) ceil( 0.5 * NbTermesMx ); + +if ( NbTermesMx < 100 ) NbTermesMx = 100; + +/* On verifie qu'on peut mettre au moins qq coupes */ +NbCoupesInserees = 0; +NbI = 0; +for ( i = NombreDeCoupesDejaCalculees ; NbCoupesInserees < NbMxCoupes && i < Pne->NombreDeCoupesCalculees ; i++ ) { + if ( Pne->CoupesCalculees[i]->NombreDeTermes > NbTermesMx && NbI >= NOMBRE_MIN_DE_COUPES_INSEREES ) continue; + NbI++; + NbCoupesInserees++; +} + +/* Si on ne peut pas en inserer assez, on force au nombre min */ +if ( NbCoupesInserees < 1 ) { + NbMxCoupes = 1; + NbTermesMx = Pne->NombreDeVariablesTrav; +} + +NbCoupesInserees = 0; + +DernierIndex = Pne->NombreDeCoupesCalculees - 1; +FinDeBoucle = Pne->NombreDeCoupesCalculees; + +/* Limitation du nombre de coupes ajoutees */ +# if NOMBRE_MAX_DE_COUPES_INSEREES_FIXE_A_LAVANCE == OUI_PNE + if ( NbMxCoupes > NOMBRE_MAX_DE_COUPES_INSEREES ) NbMxCoupes = NOMBRE_MAX_DE_COUPES_INSEREES; +# else + if ( NbMxCoupes > PROPORTION_MAX_DE_COUPES_INSEREES * Pne->NombreDeContraintesTrav ) { + NbMxCoupes = (int) ceil ( PROPORTION_MAX_DE_COUPES_INSEREES * Pne->NombreDeContraintesTrav ); + if ( NbMxCoupes < NOMBRE_MIN_DE_COUPES_INSEREES ) NbMxCoupes = NOMBRE_MIN_DE_COUPES_INSEREES; + } +# endif + +/*printf("Debut Insertion\n");*/ + +NbI = 0; +for ( i = NombreDeCoupesDejaCalculees ; NbCoupesInserees < NbMxCoupes && i < FinDeBoucle ; i++ ) { + if ( Pne->CoupesCalculees[i]->NombreDeTermes < NbTermesMx || NbI < NOMBRE_MIN_DE_COUPES_INSEREES ) { + + /*printf("Distance %e\n",Pne->CoupesCalculees[i]->Distance);*/ + + /* On ajoute la contrainte dans le probleme relaxe courant en vue d'une nouvelle resolution */ + Pne->CoupesCalculees[i]->NumeroDeLaContrainte = Pne->Coupes.NombreDeContraintes; + ContrainteSaturee = NON_PNE; /* C'est une nouvelle contrainte, ainsi on mettra EN_BASE la variable d'ecart */ + PNE_InsererUneContrainte( Pne, + Pne->CoupesCalculees[i]->NombreDeTermes , + Pne->CoupesCalculees[i]->Coefficient, + Pne->CoupesCalculees[i]->IndiceDeLaVariable, + Pne->CoupesCalculees[i]->SecondMembre, + ContrainteSaturee, + Pne->CoupesCalculees[i]->Type + ); + + NbI++; + + /* Informer la partie Bb qu'il faut relancer et incrementer un compteur de la partie branch and bound */ + BB_DemanderUneNouvelleResolutionDuProblemeRelaxe( Bb ); + NbCoupesInserees++; + } + else { + /* On inverse avec la derniere */ + Coupe = Pne->CoupesCalculees[DernierIndex]; + Pne->CoupesCalculees[DernierIndex] = Pne->CoupesCalculees[i]; + Pne->CoupesCalculees[i] = Coupe; + DernierIndex--; + FinDeBoucle--; + i--; + } +} + +/*printf("Nombre de coupes inserees parmi les coupes nouvellement calculees %d\n",NbCoupesInserees);*/ + +/* On libere le reste des structures */ +for ( ; i < Pne->NombreDeCoupesCalculees ; i++ ) { + free( Pne->CoupesCalculees[i]->Coefficient ); + free( Pne->CoupesCalculees[i]->IndiceDeLaVariable ); + free( Pne->CoupesCalculees[i] ); +} + +Pne->NombreDeCoupesCalculees = NombreDeCoupesDejaCalculees + NbCoupesInserees; + +Pne->NombreDeCoupesCalculeesNonEvaluees = NbCoupesInserees; +Pne->NombreDeCoupesAjouteesAuRoundPrecedent = NbCoupesInserees; + +return; +} + + + diff --git a/src/ext/Sirius_Solver/pne/pne_calculer_les_gomory.c b/src/ext/Sirius_Solver/pne/pne_calculer_les_gomory.c new file mode 100644 index 0000000000..4d32fb25c8 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_calculer_les_gomory.c @@ -0,0 +1,232 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul des coupes + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define NOMBRE_MAX_DE_COUPES_PAR_PROBLEME_RELAXE 1000000 /* Pas de limite */ /* C'est le nombre max de CG qu'on va calculer */ + +/*----------------------------------------------------------------------------*/ + +void PNE_Gomory( PROBLEME_PNE * Pne ) +{ +int i; int Var; double UTrav; int Count; int Ok; int CountMx; int CountMN; +double Fractionnalite; BB * Bb; int NbCalculs; + +NbCalculs = 0; + +#if VERBOSE_PNE + printf("-> Determination des coupes de GOMORY \n"); fflush(stdout); +#endif + +if ( Pne->PremFrac >= 0 ) { + Ok = SPX_PreparerLeCalculDesGomory( (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur, + Pne->NombreDeVariablesTrav , Pne->TypeDeVariableTrav ); + if ( Ok != 1 ) goto FinPneGomory; +} + +Bb = (BB *) Pne->ProblemeBbDuSolveur; +CountMN = (int) ( 0.5 * Bb->NombreDeVariablesEntieresDuProbleme); +if ( CountMN <= 0 ) CountMN = 1; + +CountMN = 200; + +CountMx = (int) ( 0.1 * Pne->NombreDeVariablesAValeurFractionnaire ); + +if ( CountMx < CountMN ) CountMx = CountMN; + +Count = 0; +i = Pne->PremFrac; + +while ( i >= 0 && Count < CountMx ) { + Var = i; + if ( Var < 0 || Var >= Pne->NombreDeVariablesTrav ) goto NextVar; + + /* Test supplementaire au cas ou on voudrait faire des coupes sur des variables a valeurs + presque entieres */ + UTrav = Pne->UTrav[Var]; + Fractionnalite = fabs( UTrav - floor( UTrav ) ); + if ( fabs( UTrav - ceil ( UTrav ) ) < Fractionnalite ) Fractionnalite = fabs( UTrav - ceil ( UTrav ) ); + + if( Fractionnalite < SEUIL_FRACTIONNALITE_POUR_FAIRE_UNE_COUPE_DE_GOMORY ) break; + + NbCalculs++; + PNE_CalculerUneGomoryEnVariablesMixtes( Pne, Var, Fractionnalite ); + if ( Pne->NombreDeCoupesAjoute >= NOMBRE_MAX_DE_COUPES_PAR_PROBLEME_RELAXE ) break; + + Count++; + + NextVar: + i = Pne->SuivFrac[i]; + +} + +FinPneGomory: + +#if VERBOSE_PNE + printf("-> Nombre de coupes de GOMORY ajoutees %d \n",Pne->NombreDeCoupesAjoute); +#endif +/* + printf("-> Nombre de coupes de GOMORY ajoutees %d sur %d NombreDeVariablesAValeurFractionnaire %d\n", + Pne->NombreDeCoupesAjoute,NbCalculs,Pne->NombreDeVariablesAValeurFractionnaire); +*/ +if ( Pne->PremFrac >= 0 ) SPX_TerminerLeCalculDesGomory( (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur ); + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Calcul d'une coupe de gomory en variables mixtes */ + +void PNE_CalculerUneGomoryEnVariablesMixtes( PROBLEME_PNE * Pne, int VariableFractionnaire, + double Fractionnalite ) +{ +int i; int NombreDeTermes ; double SecondMembre; double S; double PlusGrandCoeff; double X; double Y; +int NombreDeVariablesTrav; int * IndiceDeLaVariable; double * Coefficient; double * UTrav; char OnAEcrete; +double RapportMaxDesCoeffs; double ZeroPourCoeffVariablesDEcart; double ZeroPourCoeffVariablesNative; +double RelaxRhsAbs; double RelaxRhsRel; + +RapportMaxDesCoeffs = RAPPORT_MAX_COEFF_COUPE_GOMORY; +ZeroPourCoeffVariablesDEcart = ZERO_POUR_COEFF_VARIABLE_DECART_DANS_COUPE_GOMORY_OU_INTERSECTION; +ZeroPourCoeffVariablesNative = ZERO_POUR_COEFF_VARIABLE_NATIVE_DANS_COUPE_GOMORY_OU_INTERSECTION; +RelaxRhsAbs = RELAX_RHS_GOMORY_ABS; +RelaxRhsRel = RELAX_RHS_GOMORY_REL; + +IndiceDeLaVariable = Pne->IndiceDeLaVariable_CG; +Coefficient = Pne->Coefficient_CG; + +/* +printf("Coupe de Gomory sur la variable %d valeur %lf\n",VariableFractionnaire,Pne->UTrav[VariableFractionnaire]); fflush(stdout); +*/ + +SPX_CalculerUneCoupeDeGomory( + (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur, + VariableFractionnaire, + + RapportMaxDesCoeffs, + ZeroPourCoeffVariablesDEcart, + ZeroPourCoeffVariablesNative, + RelaxRhsAbs, + RelaxRhsRel, + + &NombreDeTermes, + Coefficient, + IndiceDeLaVariable, + &SecondMembre, + &OnAEcrete ); + +if ( NombreDeTermes <= 0 ) return; + +NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; +UTrav = Pne->UTrav; +PlusGrandCoeff = -LINFINI_PNE; +S = 0.0; +for ( i = 0 ; i < NombreDeTermes ; i++ ) { + Y = Coefficient[i]; + if ( IndiceDeLaVariable[i] < NombreDeVariablesTrav ) { + S += Y * UTrav[IndiceDeLaVariable[i]]; + if ( fabs( Y ) > PlusGrandCoeff ) PlusGrandCoeff = fabs( Y ); + } +} + +if ( S > SecondMembre ) { + X = fabs( SecondMembre - S ); + if ( X > SEUIL_VIOLATION_COUPE_DE_GOMORY ) { + + /* Mise a jour de la matrice pour les coupes d'intersection sauf si la coupe a trop de termes car on perd pas mal de + precision dans les coupes d'intersection. Le coeff sur le nombre de variables est totalement arbitraire */ + + if ( Fractionnalite > SEUIL_FRACTIONNALITE_POUR_COUPE_INTERSECTION /*&& NombreDeTermes < (0.95 * NombreDeVariablesTrav)*/ ) { + SPX_MatriceCoupesDIntersection( (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur ); + } + + /* + printf("Coupe de gomory Violation %e NombreDeTermes %d (max.: %d)\n",X,NombreDeTermes,Pne->NombreDeVariablesTrav); + for ( i = 0 ; i < NombreDeTermes ; i++ ) { + printf(" %e (%d) + ",Coefficient[i],IndiceDeLaVariable[i]); + } + printf(" < %e\n",SecondMembre); + fflush( stdout ); + */ + + /* On met la Gomory dans le probleme */ + + PNE_NormaliserUnCoupe( Pne->Coefficient_CG, &SecondMembre, NombreDeTermes, PlusGrandCoeff ); + + PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'G', NombreDeTermes, SecondMembre, X, Coefficient, IndiceDeLaVariable ); + + /* Test 2 MIR cuts sur le tableau du simplexe: pas concluant pour l'instant */ + /* + double ValeurDuZero; + ValeurDuZero = 1.e-11; + PNE_TwoStepMirSurTableau( Pne, VariableFractionnaire, ValeurDuZero ); + */ + /* Fin test */ + + + + # if KNAPSACK_SUR_GOMORY == OUI_SPX + /* Il faut le faire apres le stockage de la coupe car la recherche des knapsack modifie + Pne->Coefficient_CG et Pne->IndiceDeLaVariable_CG */ + /* On regarde si on peut faire une K sur la coupe */ + if ( X > VIOLATION_MIN_POUR_K_SUR_COUPE && OnAEcrete != OUI_SPX ) { + PNE_CalculerUneKnapsackSurGomoryOuIntersection( Pne, Coefficient, IndiceDeLaVariable, + SecondMembre, NombreDeTermes, PlusGrandCoeff ); + } + # endif + + } + else { + /* + printf(" -> Coupe refusee car distance au plan trop petite valeur %e valeur variable fractionnaire %e\n", + X,Pne->UTrav[VariableFractionnaire]); + */ + } + +} + +else { + /* + printf("PNE_CalculerUneGomoryEnVariablesMixtes: attention la solution courante verifie la contrainte S = %lf < SecondMembre = %lf \n", + S,SecondMembre); + + */ +} + + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_calculer_restrictions_bornes.c b/src/ext/Sirius_Solver/pne/pne_calculer_restrictions_bornes.c new file mode 100644 index 0000000000..3bb173f21a --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_calculer_restrictions_bornes.c @@ -0,0 +1,763 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On essaie de fixer des variables entieres par des tests + d'amissibilite en essayant de resserer des bornes. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define ZERO_COEFF 1.e-9 + +char PNE_AffinerUneBorne( PROBLEME_PNE * , int , char , int , double , double , char * , char * , double * , double * ); + +void PNE_MiseAJourMinMaxContraintes( PROBLEME_PNE * , int , char * , char * , double * , double * ); + +void PNE_CalculerLeMinEtLeMaxDUneContrainte( PROBLEME_PNE * , int , char * , char * , double * , double * ); + +char PNE_AffinerUneBorneSurCoupe( PROBLEME_PNE * , int , char , int , double , double , char * , double * ); + +void PNE_MiseAJourMinMaxCoupes( PROBLEME_PNE * , int , char * , char * , double * , double * ); + +void PNE_CalculerLeMinEtLeMaxDUneCoupe( PROBLEME_PNE * , int , char * , char * , double * , double * ); + +# define BORNE_MODIFIEE 1 +# define PAS_DE_SOLUTION 2 +# define RIEN_A_SIGNALER 3 + +# define NOMBRE_MAX_DE_CYCLES 10 + +# define EPSILON_BORNES 1.e-5 + +/*----------------------------------------------------------------------------*/ + +void PNE_CalculerLesRestrictionsDeBornes( PROBLEME_PNE * Pne, + int * NombreDeVariablesEntieresFixees, + char * InfaisabiliteDetectee, + char Mode ) +{ +int Var;int i ; int Cnt; int VariableTestee; int il; int ilMax; int NbVarEntieresFixees; +double B; char Sens; BB * Bb; + +/* Test */ +char OnFixe; int ic; int Var1; +/* Fin test */ + +char CodeModifBornes; char UneBorneAEteModifiee; int NombreDeCycles; + +double * UmaxSv; double * UminSv; int * TypeDeBorneSv; + +double * MinContrainte; char * MinContrainteDisponible; +double * MaxContrainte; char * MaxContrainteDisponible; + +double * MinCoupe; char * MinCoupeDisponible; +double * MaxCoupe; char * MaxCoupeDisponible; + +return; + +Bb = (BB *) Pne->ProblemeBbDuSolveur; + +/* Test */ +goto AAA; +printf("################# Fixation sur critere ############################\n"); +i = 0; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Pne->LTrav[Var] != 0.0 ) continue; + if ( Pne->UminTrav[Var] == Pne->UmaxTrav[Var] ) continue; + OnFixe = OUI_PNE; + ic = Pne->CdebTrav[Var]; + while ( ic >= 0 ) { + Cnt = Pne->NumContrainteTrav[ic]; + if ( Pne->NbTermTrav[Cnt] != 2 ) goto NextIc; + il = Pne->MdebTrav[Cnt]; + ilMax = il + Pne->NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var1 = Pne->NuvarTrav[il]; + if ( Var1 != Var ) { + if ( Pne->UmaxTrav[Var1] != 0.0 ) { + OnFixe = NON_PNE; + goto NextVar; + } + } + il++; + } + NextIc: + ic = Pne->CsuiTrav[ic]; + } + NextVar: + if ( OnFixe == OUI_PNE ) { + /* On peut fixer */ + Pne->UminTrav[Var] = 0.0; + Pne->UmaxTrav[Var] = 0.0; + printf("On peut fixer la variable %d sur critere\n",Var); + i++; + } +} + +printf(" Nombre de variables fixables sur critere: %d\n",i); +printf("################# Fin fixation sur critere ############################\n"); +return; + +AAA: +/*********************************************************************************/ + +UminSv = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +UmaxSv = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +TypeDeBorneSv = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); + +memcpy( (char *) UminSv , (char *) Pne->UminTrav , Pne->NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char *) UmaxSv , (char *) Pne->UmaxTrav , Pne->NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char *) TypeDeBorneSv , (char *) Pne->TypeDeBorneTrav , Pne->NombreDeVariablesTrav * sizeof( int ) ); + +MinContrainte = (double *) malloc( Pne->NombreDeContraintesTrav * sizeof( double ) ); +MaxContrainte = (double *) malloc( Pne->NombreDeContraintesTrav * sizeof( double ) ); +MinContrainteDisponible = (char *) malloc( Pne->NombreDeContraintesTrav * sizeof( char ) ); +MaxContrainteDisponible = (char *) malloc( Pne->NombreDeContraintesTrav * sizeof( char ) ); + +MinCoupe = (double *) malloc( Pne->Coupes.NombreDeContraintes * sizeof( double ) ); +MaxCoupe = (double *) malloc( Pne->Coupes.NombreDeContraintes * sizeof( double ) ); +MinCoupeDisponible = (char *) malloc( Pne->Coupes.NombreDeContraintes * sizeof( char ) ); +MaxCoupeDisponible = (char *) malloc( Pne->Coupes.NombreDeContraintes * sizeof( char ) ); + +/* On calcule le min et le max de chaque contrainte */ +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + PNE_CalculerLeMinEtLeMaxDUneContrainte( Pne, Cnt, MinContrainteDisponible, MaxContrainteDisponible, + MinContrainte, MaxContrainte ); +} + +/* On calcule le min et le max de chaque coupe (on n'a besoin que du min) */ +for ( Cnt = 0 ; Cnt < Pne->Coupes.NombreDeContraintes ; Cnt++ ) { + PNE_CalculerLeMinEtLeMaxDUneCoupe( Pne, Cnt, MinCoupeDisponible, MaxCoupeDisponible, + MinCoupe, MaxCoupe ); +} + +NombreDeCycles = 0; +NbVarEntieresFixees = 0; +*InfaisabiliteDetectee = NON_PNE; + +DebutAffinageDesBornes: + +UneBorneAEteModifiee = NON_PNE; + +/* On balaye les contraintes et on lance les calculs de bornes */ +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + B = Pne->BTrav[Cnt]; + il = Pne->MdebTrav[Cnt]; + ilMax = il + Pne->NbTermTrav[Cnt]; + while ( il < ilMax ) { + VariableTestee = Pne->NuvarTrav[il]; + if ( Pne->UmaxTrav[VariableTestee] - Pne->UminTrav[VariableTestee] > ZERO_VARFIXE && + Pne->TypeDeBorneTrav[VariableTestee] != VARIABLE_FIXE && Pne->ATrav[il] != 0.0 ) { + Sens = '<'; + CodeModifBornes = PNE_AffinerUneBorne( Pne, VariableTestee, Sens, Cnt , + B , Pne->ATrav[il], + MinContrainteDisponible , + MaxContrainteDisponible , + MinContrainte , + MaxContrainte ); + if ( CodeModifBornes == BORNE_MODIFIEE ) { + UneBorneAEteModifiee = OUI_PNE; + if ( Pne->TypeDeVariableTrav[VariableTestee] == ENTIER ) NbVarEntieresFixees++; + /* Recalcul des nouvelles valeurs de min max */ + PNE_MiseAJourMinMaxContraintes( Pne, VariableTestee, MinContrainteDisponible, MaxContrainteDisponible, + MinContrainte, MaxContrainte ); + PNE_MiseAJourMinMaxCoupes( Pne, VariableTestee, MinCoupeDisponible, MaxCoupeDisponible, + MinCoupe, MaxCoupe ); + } + if ( CodeModifBornes == PAS_DE_SOLUTION ) { + printf(" -----------> pas de solution \n"); + *InfaisabiliteDetectee = OUI_PNE; + goto Fin; + } + if ( Pne->SensContrainteTrav[Cnt] == '=' ) { + /* Si la contrainte est de type '=' il est possible de faire le test des bornes dans les 2 sens */ + Sens = '>'; + CodeModifBornes = PNE_AffinerUneBorne( Pne, VariableTestee, Sens , Cnt, + B , Pne->ATrav[il], + MinContrainteDisponible , + MaxContrainteDisponible , + MinContrainte , + MaxContrainte ); + if ( CodeModifBornes == BORNE_MODIFIEE ) { + UneBorneAEteModifiee = OUI_PNE; + if ( Pne->TypeDeVariableTrav[VariableTestee] == ENTIER ) NbVarEntieresFixees++; + /* Recalcul des nouvelles valeurs de min max */ + PNE_MiseAJourMinMaxContraintes( Pne, VariableTestee, MinContrainteDisponible, MaxContrainteDisponible, + MinContrainte, MaxContrainte ); + PNE_MiseAJourMinMaxCoupes( Pne, VariableTestee, MinCoupeDisponible, MaxCoupeDisponible, + MinCoupe, MaxCoupe ); + } + if ( CodeModifBornes == PAS_DE_SOLUTION ) { + /* A completer */ + printf(" -----------> pas de solution \n"); + *InfaisabiliteDetectee = OUI_PNE; + goto Fin; + } + } + } + il++; + } +} + +/* On etudie maintenant les coupes */ +for ( Cnt = 0 ; Cnt < Pne->Coupes.NombreDeContraintes ; Cnt++ ) { + + +/* +continue; +*/ + + + B = Pne->Coupes.B[Cnt]; + il = Pne->Coupes.Mdeb[Cnt]; + ilMax = il + Pne->Coupes.NbTerm[Cnt]; + while ( il < ilMax ) { + VariableTestee = Pne->Coupes.Nuvar[il]; + if ( VariableTestee >= Pne->NombreDeVariablesTrav ) exit(0); + if ( VariableTestee < 0 ) exit(0); + + if ( Pne->UmaxTrav[VariableTestee] - Pne->UminTrav[VariableTestee] > ZERO_VARFIXE && + Pne->TypeDeBorneTrav[VariableTestee] != VARIABLE_FIXE && Pne->Coupes.A[il] != 0.0 ) { + Sens = '<'; + CodeModifBornes = PNE_AffinerUneBorneSurCoupe( Pne, VariableTestee, Sens, Cnt , + B , Pne->Coupes.A[il], + MinCoupeDisponible , + MinCoupe ); + if ( CodeModifBornes == BORNE_MODIFIEE ) { + UneBorneAEteModifiee = OUI_PNE; + if ( Pne->TypeDeVariableTrav[VariableTestee] == ENTIER ) NbVarEntieresFixees++; + /* Recalcul des nouvelles valeurs de min max */ + PNE_MiseAJourMinMaxContraintes( Pne, VariableTestee, MinContrainteDisponible, MaxContrainteDisponible, + MinContrainte, MaxContrainte ); + PNE_MiseAJourMinMaxCoupes( Pne, VariableTestee, MinCoupeDisponible, MaxCoupeDisponible, + MinCoupe, MaxCoupe ); + } + if ( CodeModifBornes == PAS_DE_SOLUTION ) { + printf(" -----------> pas de solution \n"); + *InfaisabiliteDetectee = OUI_PNE; + goto Fin; + } + } + il++; + } +} + +NombreDeCycles++; +if ( NombreDeCycles < NOMBRE_MAX_DE_CYCLES ) { + if ( UneBorneAEteModifiee == OUI_PNE ) { + /* printf("On Relance un affinage de bornes Cycle %d\n",NombreDeCycles); */ + goto DebutAffinageDesBornes; + } +} + +Fin: + +free( MinContrainte ); +free( MaxContrainte ); +free( MinContrainteDisponible ); +free( MaxContrainteDisponible ); + +free( MinCoupe ); +free( MaxCoupe ); +free( MinCoupeDisponible ); +free( MaxCoupeDisponible ); + +/* Car la validite des coupes dans tout l'arbre n'est pas assuree dans la cas de variations de bornes + autres que pour les variables entieres */ +if ( Mode != SIMULATION ) { + for( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) continue; + if ( Bb->NoeudEnExamen->ProfondeurDuNoeud <= 30 /*SEUIL_PROFONDEUR_LIMITE_1*/ /* a revoir car dans la partie branch and bound */ || + Bb->NoeudEnExamen->ProfondeurDuNoeud <= 30 /*SEUIL_PROFONDEUR_LIMITE_2*/ || 1 ) { + Pne->UminTrav [Var] = UminSv[Var]; + Pne->UmaxTrav [Var] = UmaxSv[Var]; + Pne->TypeDeBorneTrav[Var] = TypeDeBorneSv[Var]; + } + } +} +else { + /* Mode simulation => on remet tout comme avant */ + for( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + Pne->UminTrav [Var] = UminSv[Var]; + Pne->UmaxTrav [Var] = UmaxSv[Var]; + Pne->TypeDeBorneTrav[Var] = TypeDeBorneSv[Var]; + } +} + +free( UminSv ); +free( UmaxSv ); +free( TypeDeBorneSv ); + +*NombreDeVariablesEntieresFixees = NbVarEntieresFixees; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* On y modifie: Pne->UminTrav, Pne->UmaxTrav, Pne->TypeDeBorneTrav */ + +char PNE_AffinerUneBorne( PROBLEME_PNE * Pne, + int VariableTestee, + char SensDeLaContrainte, int Cnt, + double B, + double A, + char * MinContrainteDisponible, + char * MaxContrainteDisponible, + double * MinContrainte, + double * MaxContrainte + ) +{ +double BMX; double BMN; double X; char CodeRetour; +double ValeurMinDeLaSomme; double ValeurMaxDeLaSomme; + +CodeRetour = RIEN_A_SIGNALER; + +if ( SensDeLaContrainte == '<' ) { + /* On cherche le max du second membre. Pour cela on lui retranche le min de la somme */ + if ( MinContrainteDisponible[Cnt] == NON_PNE ) return( CodeRetour ); + if ( A >= 0.0 ) { + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_INFERIEUREMENT ) { + ValeurMinDeLaSomme = MinContrainte[Cnt] - A * Pne->UminTrav[VariableTestee]; + } + else return( CodeRetour ); + } + else { + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + ValeurMinDeLaSomme = MinContrainte[Cnt] - A * Pne->UmaxTrav[VariableTestee]; + } + else return( CodeRetour ); + } + BMX = B - ValeurMinDeLaSomme; + if ( A > ZERO_COEFF ) { + X = BMX / A; + if ( Pne->UmaxTrav[VariableTestee] > X + EPSILON_BORNES ) { + /* On peut abaisser la borne sup */ + if ( Pne->TypeDeVariableTrav[VariableTestee] == ENTIER ) { + /* + printf("->>>>>>>>>>> Variable entiere %d X %e floor %e\n",VariableTestee,X,floor(X)); + */ + X = floor( X ); + } + /* Precaution */ + if ( X < Pne->UminTrav[VariableTestee] ) { + /* La nouvelle borne sup doit etre inferieure a la borne inf => pas de solution */ + printf("Pas de solution\n"); + CodeRetour = PAS_DE_SOLUTION; + return( CodeRetour ); + } + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_NON_BORNEE ) { + /* A revoir */ + return( CodeRetour ); + } + else if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Pne->TypeDeBorneTrav[VariableTestee] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + /* + printf(" ---> affinage de borne SUP sur variable %d: Old %e New %e type de borne %d Cnt %d B %e\n",VariableTestee, + Pne->UmaxTrav[VariableTestee],X,Pne->TypeDeBorneTrav[VariableTestee],Cnt,B); + */ + Pne->UmaxTrav[VariableTestee] = X; + CodeRetour = BORNE_MODIFIEE; + } + } + else if ( A < -ZERO_COEFF ) { + X = BMX / A; + if ( Pne->UminTrav[VariableTestee] < X - EPSILON_BORNES ) { + /* On peut remonter la borne inf */ + if ( Pne->TypeDeVariableTrav[VariableTestee] == ENTIER ) { + /* + printf("->>>>>>>>>>> Variable entiere %d X %e ceil %e\n",VariableTestee,X,ceil(X)); + */ + X = ceil( X ); + } + /* Precaution */ + if ( X > Pne->UmaxTrav[VariableTestee] ) { + /* La nouvelle borne inf doit etre superieure a la borne sup => pas de solution */ + printf("Pas de solution\n"); + CodeRetour = PAS_DE_SOLUTION; + return( CodeRetour ); + } + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_NON_BORNEE ) { + Pne->TypeDeBorneTrav[VariableTestee] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Pne->TypeDeBorneTrav[VariableTestee] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + /* + printf(" ---> affinage de borne INF sur variable %d: Old %e New %e type de borne %d Cnt %d B %e\n",VariableTestee, + Pne->UminTrav[VariableTestee],X,Pne->TypeDeBorneTrav[VariableTestee],Cnt,B); + */ + + Pne->UminTrav[VariableTestee] = X; + CodeRetour = BORNE_MODIFIEE; + } + } + return( CodeRetour ); +} + +if ( SensDeLaContrainte == '>') { + /* On cherche le min du second membre. Pour cela on lui retranche le max de la somme */ + if ( MaxContrainteDisponible[Cnt] == NON_PNE ) return( CodeRetour ); + if ( A >= 0.0 ) { + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + ValeurMaxDeLaSomme = MaxContrainte[Cnt] - A * Pne->UmaxTrav[VariableTestee]; + } + else return( CodeRetour ); + } + else { + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_INFERIEUREMENT ) { + ValeurMaxDeLaSomme = MaxContrainte[Cnt] - A * Pne->UminTrav[VariableTestee]; + } + else return( CodeRetour ); + } + BMN = B - ValeurMaxDeLaSomme; + if ( A > ZERO_COEFF ) { + X = BMN / A; + if ( Pne->UminTrav[VariableTestee] < X - EPSILON_BORNES ) { + /* On peut remonter la borne inf */ + if ( Pne->TypeDeVariableTrav[VariableTestee] == ENTIER ) X = ceil( X ); + /* Precaution */ + if ( X > Pne->UmaxTrav[VariableTestee] ) { + /* La nouvelle borne inf doit etre superieure a la borne sup => pas de solution */ + printf("Pas de solution\n"); + CodeRetour = PAS_DE_SOLUTION; + return( CodeRetour ); + } + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_NON_BORNEE ) { + Pne->TypeDeBorneTrav[VariableTestee] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Pne->TypeDeBorneTrav[VariableTestee] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + /* + printf(" ---> affinage de borne INF sur variable %d: Old %e New %e type de borne %d Cnt %d B %e\n",VariableTestee, + Pne->UminTrav[VariableTestee],X,Pne->TypeDeBorneTrav[VariableTestee],Cnt,B); + */ + Pne->UminTrav[VariableTestee] = X; + CodeRetour = BORNE_MODIFIEE; + } + } + else if ( A < -ZERO_COEFF ) { + X = BMN / A; + if ( Pne->UmaxTrav[VariableTestee] > X + EPSILON_BORNES ) { + /* On peut abaisser la borne sup */ + if ( Pne->TypeDeVariableTrav[VariableTestee] == ENTIER ) X = floor( X ); + /* Precaution */ + if ( X < Pne->UminTrav[VariableTestee] ) { + /* La nouvelle borne sup doit etre inferieure a la borne inf => pas de solution */ + printf("Pas de solution\n"); + CodeRetour = PAS_DE_SOLUTION; + return( CodeRetour ); + } + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_NON_BORNEE ) { + /* A ce stade on ne peut plus utiliser le type de borne VARIABLE_BORNEE_SUPERIEUREMENT sans trop de complication */ + /*Pne->TypeDeBorneTrav[VariableTestee] = VARIABLE_BORNEE_SUPERIEUREMENT;*/ + return( CodeRetour ); + } + else if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Pne->TypeDeBorneTrav[VariableTestee] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + /* + printf(" ---> affinage de borne SUP sur variable %d: Old %e New %e type de borne %d Cnt %d B %e\n",VariableTestee, + Pne->UmaxTrav[VariableTestee],X,Pne->TypeDeBorneTrav[VariableTestee],Cnt,B); + */ + Pne->UmaxTrav[VariableTestee] = X; + CodeRetour = BORNE_MODIFIEE; + } + } + return( CodeRetour ); +} + +return( CodeRetour ); +} + +/*----------------------------------------------------------------------------*/ +/* On y modifie: Pne->UminTrav, Pne->UmaxTrav, Pne->TypeDeBorneTrav */ +char PNE_AffinerUneBorneSurCoupe( PROBLEME_PNE * Pne, + int VariableTestee, char SensDeLaContrainte, int Cnt, + double B , double A , + char * MinCoupeDisponible, + double * MinCoupe ) +{ +double BMX; double X; char CodeRetour; double ValeurMinDeLaSomme; + +CodeRetour = RIEN_A_SIGNALER; + +if ( SensDeLaContrainte == '<' ) { + /* On cherche le max du second membre. Pour cela on lui retranche le min de la somme */ + if ( MinCoupeDisponible[Cnt] == NON_PNE ) return( CodeRetour ); + if ( A >= 0.0 ) { + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_INFERIEUREMENT ) { + ValeurMinDeLaSomme = MinCoupe[Cnt] - A * Pne->UminTrav[VariableTestee]; + } + else return( CodeRetour ); + } + else { + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + ValeurMinDeLaSomme = MinCoupe[Cnt] - A * Pne->UmaxTrav[VariableTestee]; + } + else return( CodeRetour ); + } + BMX = B - ValeurMinDeLaSomme; + if ( A > ZERO_COEFF ) { + X = BMX / A; + if ( Pne->UmaxTrav[VariableTestee] > X + EPSILON_BORNES ) { + /* On peut abaisser la borne sup */ + if ( Pne->TypeDeVariableTrav[VariableTestee] == ENTIER ) { + X = floor( X ); + } + /* Precaution */ + if ( X < Pne->UminTrav[VariableTestee] ) { + /* La nouvelle borne sup doit etre inferieure a la borne inf => pas de solution */ + printf("Pas de solution\n"); + CodeRetour = PAS_DE_SOLUTION; + return( CodeRetour ); + } + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_NON_BORNEE ) { + /* A revoir */ + return( CodeRetour ); + } + else if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Pne->TypeDeBorneTrav[VariableTestee] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + Pne->UmaxTrav[VariableTestee] = X; + CodeRetour = BORNE_MODIFIEE; + } + } + else if ( A < -ZERO_COEFF ) { + X = BMX / A; + if ( Pne->UminTrav[VariableTestee] < X - EPSILON_BORNES ) { + /* On peut remonter la borne inf */ + if ( Pne->TypeDeVariableTrav[VariableTestee] == ENTIER ) { + X = ceil( X ); + } + /* Precaution */ + if ( X > Pne->UmaxTrav[VariableTestee] ) { + /* La nouvelle borne inf doit etre superieure a la borne sup => pas de solution */ + printf("Pas de solution\n"); + CodeRetour = PAS_DE_SOLUTION; + return( CodeRetour ); + } + if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_NON_BORNEE ) { + Pne->TypeDeBorneTrav[VariableTestee] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( Pne->TypeDeBorneTrav[VariableTestee] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Pne->TypeDeBorneTrav[VariableTestee] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + Pne->UminTrav[VariableTestee] = X; + CodeRetour = BORNE_MODIFIEE; + } + } + return( CodeRetour ); +} + +return( CodeRetour ); +} + +/*----------------------------------------------------------------------------*/ + +void PNE_MiseAJourMinMaxContraintes( PROBLEME_PNE * Pne, int Var, + char * MinContrainteDisponible, + char * MaxContrainteDisponible, + double * MinContrainte, + double * MaxContrainte + ) +{ +int ic; int Cnt; +ic = Pne->CdebTrav[Var]; +while ( ic >= 0 ) { + Cnt = Pne->NumContrainteTrav[ic]; + PNE_CalculerLeMinEtLeMaxDUneContrainte( Pne, Cnt, MinContrainteDisponible, MaxContrainteDisponible, + MinContrainte, MaxContrainte ); + ic = Pne->CsuiTrav[ic]; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_MiseAJourMinMaxCoupes( PROBLEME_PNE * Pne, int Var, + char * MinCoupeDisponible, + char * MaxCoupeDisponible, + double * MinCoupe, + double * MaxCoupe + ) +{ +int il; int ilMax; int Cnt; + +for ( Cnt = 0 ; Cnt < Pne->Coupes.NombreDeContraintes ; Cnt++ ) { + il = Pne->Coupes.Mdeb[Cnt]; + ilMax = il + Pne->Coupes.NbTerm[Cnt]; + while ( il < ilMax ) { + if ( Pne->Coupes.Nuvar[il] == Var ) { + PNE_CalculerLeMinEtLeMaxDUneCoupe( Pne, Cnt, MinCoupeDisponible, MaxCoupeDisponible, + MinCoupe, MaxCoupe ); + break; + } + il++; + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CalculerLeMinEtLeMaxDUneContrainte( PROBLEME_PNE * Pne, int Cnt, + char * MinContrainteDisponible, + char * MaxContrainteDisponible, + double * MinContrainte, + double * MaxContrainte + ) +{ +double X; int il; int ilMax; int Var; + +MinContrainteDisponible[Cnt] = OUI_PNE; +MaxContrainteDisponible[Cnt] = OUI_PNE; +MinContrainte[Cnt] = 0.0; +MaxContrainte[Cnt] = 0.0; +il = Pne->MdebTrav[Cnt]; +ilMax = il + Pne->NbTermTrav[Cnt]; +while ( il < ilMax ) { + if ( MinContrainteDisponible[Cnt] == NON_PNE && MaxContrainteDisponible[Cnt] == NON_PNE ) break; + Var = Pne->NuvarTrav[il]; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) { + MinContrainteDisponible[Cnt] = NON_PNE; + MaxContrainteDisponible[Cnt] = NON_PNE; + break; + } + X = Pne->ATrav[il]; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_FIXE ) { + MaxContrainte[Cnt]+= X * Pne->UTrav[Var]; + MinContrainte[Cnt]+= X * Pne->UTrav[Var]; + } + else { + if ( X >= 0.0 ) { + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + MaxContrainte[Cnt]+= X * Pne->UmaxTrav[Var]; + } + else MaxContrainteDisponible[Cnt] = NON_PNE; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + MinContrainte[Cnt]+= X * Pne->UminTrav[Var]; + } + else MinContrainteDisponible[Cnt] = NON_PNE; + } + else { + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + MaxContrainte[Cnt]+= X * Pne->UminTrav[Var]; + } + else MaxContrainteDisponible[Cnt] = NON_PNE; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + MinContrainte[Cnt]+= X * Pne->UmaxTrav[Var]; + } + else MinContrainteDisponible[Cnt] = NON_PNE; + } + } + il++; +} + +return; + +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CalculerLeMinEtLeMaxDUneCoupe( PROBLEME_PNE * Pne, int Cnt, + char * MinCoupeDisponible, + char * MaxCoupeDisponible, + double * MinCoupe, + double * MaxCoupe + ) +{ +double X; int il; int ilMax; int Var; + +MinCoupeDisponible[Cnt] = OUI_PNE; +MaxCoupeDisponible[Cnt] = OUI_PNE; +MinCoupe[Cnt] = 0.0; +MaxCoupe[Cnt] = 0.0; +il = Pne->Coupes.Mdeb[Cnt]; +ilMax = il + Pne->Coupes.NbTerm[Cnt]; +while ( il < ilMax ) { + if ( MinCoupeDisponible[Cnt] == NON_PNE && MaxCoupeDisponible[Cnt] == NON_PNE ) break; + Var = Pne->Coupes.Nuvar[il]; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) { + MinCoupeDisponible[Cnt] = NON_PNE; + MaxCoupeDisponible[Cnt] = NON_PNE; + break; + } + X = Pne->Coupes.A[il]; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_FIXE ) { + MaxCoupe[Cnt]+= X * Pne->UTrav[Var]; + MinCoupe[Cnt]+= X * Pne->UTrav[Var]; + } + else { + if ( X >= 0.0 ) { + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + MaxCoupe[Cnt]+= X * Pne->UmaxTrav[Var]; + } + else MaxCoupeDisponible[Cnt] = NON_PNE; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + MinCoupe[Cnt]+= X * Pne->UminTrav[Var]; + } + else MinCoupeDisponible[Cnt] = NON_PNE; + } + else { + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + MaxCoupe[Cnt]+= X * Pne->UminTrav[Var]; + } + else MaxCoupeDisponible[Cnt] = NON_PNE; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + MinCoupe[Cnt]+= X * Pne->UmaxTrav[Var]; + } + else MinCoupeDisponible[Cnt] = NON_PNE; + } + } + il++; +} + +return; + +} diff --git a/src/ext/Sirius_Solver/pne/pne_chainage_transposee.c b/src/ext/Sirius_Solver/pne/pne_chainage_transposee.c new file mode 100644 index 0000000000..fb5ed99a7c --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_chainage_transposee.c @@ -0,0 +1,127 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Chainage de la transposee. On stocke les contraintes + d'egalite avant les contraintes d'inegalite. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_ConstruireLeChainageDeLaTransposee( PROBLEME_PNE * Pne ) +{ +int i; int il; int ilMax; int ilk; int Ligne; int * CderTrav; int * CdebTrav; +int * MdebTrav; int * NbTermTrav; int * NuvarTrav; int * NumContrainteTrav; +int * CsuiTrav; char * SensContrainteTrav; int * CNbTermTrav; + +CdebTrav = Pne->CdebTrav; +CNbTermTrav = Pne->CNbTermTrav; +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; +NumContrainteTrav = Pne->NumContrainteTrav; +CsuiTrav = Pne->CsuiTrav; +SensContrainteTrav = Pne->SensContrainteTrav; + +CderTrav = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +if ( CderTrav == NULL ) { + printf(" Pne, memoire insuffisante dans le sous programme PNE_ConstruireLeChainageDeLaTransposee \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) CdebTrav[i] = -1; + +/* Contraintes d'egalite en premier */ +for ( i = 0 ; i < Pne->NombreDeContraintesTrav ; i++ ) { + if ( SensContrainteTrav[i] != '=' ) continue; + il = MdebTrav[i]; + ilMax = il + NbTermTrav[i]; + while ( il < ilMax ) { + Ligne = NuvarTrav[il]; + if ( CdebTrav[Ligne] < 0 ) { + CdebTrav [Ligne] = il; + NumContrainteTrav[il] = i; + CsuiTrav [il] = -1; + CderTrav [Ligne] = il; + } + else { + ilk = CderTrav[Ligne]; + CsuiTrav [ilk] = il; + NumContrainteTrav[il] = i; + CsuiTrav [il] = -1; + CderTrav [Ligne] = il; + } + il++; + } +} +/* Contraintes d'inegalite ensuite */ +for ( i = 0 ; i < Pne->NombreDeContraintesTrav ; i++ ) { + if ( SensContrainteTrav[i] == '=' ) continue; + il = MdebTrav[i]; + ilMax = il + NbTermTrav[i]; + while ( il < ilMax ) { + Ligne = NuvarTrav[il]; + if ( CdebTrav[Ligne] < 0 ) { + CdebTrav [Ligne] = il; + NumContrainteTrav[il] = i; + CsuiTrav [il] = -1; + CderTrav [Ligne] = il; + } + else { + ilk = CderTrav[Ligne]; + CsuiTrav [ilk] = il; + NumContrainteTrav[il] = i; + CsuiTrav [il] = -1; + CderTrav [Ligne] = il; + } + il++; + } +} + +free( CderTrav ); + +/* Decompte nombre de termes de chaque colonne */ +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + il = CdebTrav[i]; + ilk = 0; + while ( il >= 0 ) { + ilk++; + il = CsuiTrav[il]; + } + CNbTermTrav[i] = ilk; +} + +Pne->ChainageTransposeeExploitable = OUI_PNE; + +return; +} + + + diff --git a/src/ext/Sirius_Solver/pne/pne_changer_types_de_variables.c b/src/ext/Sirius_Solver/pne/pne_changer_types_de_variables.c new file mode 100644 index 0000000000..4fcbf514b7 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_changer_types_de_variables.c @@ -0,0 +1,190 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +char PNE_IsInteger( double ); + +/*----------------------------------------------------------------------------*/ + +char PNE_IsInteger( double a ) +{ +char Entier; +Entier = OUI_PNE; +if ( ceil( a ) != floor( a ) ) Entier = NON_PNE; +return( Entier ); +} + +/*----------------------------------------------------------------------------*/ + +void PNE_ChangerLesTypesDeVariables( PROBLEME_PNE * Pne ) +{ +int Cnt; int il; int ilMax; int Var; int * Mdeb; int * NbTerm; int * Nuvar; +int * TypeDeVariable; double * A; double * X; char * SensContrainte; +int * TypeDeBorne; double a; double b; double * SecondMembre; +char ContrainteEntiere; int ic; int * Cdeb; int * Csui; int * NumContrainte; +int Cnt1; int il1; int il1Max; char KnapsackPossible; int Var1; +char TypeDeVariableChange; int NbVarEntieres; int NbVarCont; int VarCont; +double MinPartieEntiere; double MaxPartieEntiere; double * Xmin; double * Xmax; +double aCont; double mn; double mx; + +X = Pne->UTrav; +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; +SensContrainte = Pne->SensContrainteTrav; +SecondMembre = Pne->BTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + if ( SensContrainte[Cnt] != '=' ) continue; + NbVarEntieres = 0; + NbVarCont = 0; + VarCont = -1; + aCont = 0.0001; + ContrainteEntiere = OUI_PNE; + MinPartieEntiere = 0; + MaxPartieEntiere = 0; + b = SecondMembre[Cnt]; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Nuvar[il]; + a = A[il]; + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) { + b -= a * X[Var]; + goto NextIl_1; + } + if ( TypeDeVariable[Var] != ENTIER ) { + NbVarCont++; + if ( NbVarCont > 1 ) { + ContrainteEntiere = NON_PNE; + break; + } + VarCont = Var; + aCont = a; + } + else { + NbVarEntieres++; + if ( PNE_IsInteger( a ) != OUI_PNE ) { + ContrainteEntiere = NON_PNE; + break; + }; + if ( a > 0 ) MaxPartieEntiere += a * Xmax[Var]; + else MinPartieEntiere += a * Xmax[Var]; + } + NextIl_1: + il++; + } + + if ( ContrainteEntiere == NON_PNE || VarCont < 0 ) continue; + if ( aCont != 1 && aCont != -1 ) continue; + /* Le second membre est entier ? */ + + if ( PNE_IsInteger( b ) != OUI_PNE ) continue; + + mn = b-MaxPartieEntiere; + mx = b-MinPartieEntiere; + if ( aCont < 0 ) { + mn = (b-MinPartieEntiere)/aCont; + mx = (b-MaxPartieEntiere)/aCont; + + } + + printf("Contrainte entier avec 1 variable continue Cnt = %d aCont = %e VarCont = %d %e %e et min = %e max = %e\n", + Cnt,aCont,VarCont,mn,mx,Xmin[VarCont],Xmax[VarCont]); + + + if ( Xmin[VarCont] == 0.0 && Xmax[VarCont] == 1.0 ) { + TypeDeVariable[VarCont] = ENTIER; + } + + continue; + + + /* On evite de decreter continue une variable entiere qui + intervient potentiellement dans une knapsack a coeffs entiers */ + TypeDeVariableChange = NON_PNE; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Nuvar[il]; + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) goto NextIl_2; + /* On va essayer de changer le type de la variable */ + /* Balayage vertical */ + ic = Cdeb[Var]; + while ( ic >= 0 ) { + Cnt1 = NumContrainte[ic]; + if ( Cnt1 == Cnt ) goto NextIc; + KnapsackPossible = NON_PNE; + if ( SensContrainte[Cnt1] != '=' ) { + /* Knapsack potentielle ? */ + KnapsackPossible = OUI_PNE; + il1 = Mdeb[Cnt1]; + il1Max = il1 + NbTerm[Cnt1]; + while ( il1 < il1Max ) { + Var1 = Nuvar[il1]; + if ( TypeDeBorne[Var1] == VARIABLE_FIXE ) goto NextElm; + if ( TypeDeVariable[Var1] != ENTIER ) { + KnapsackPossible = NON_PNE; + break; + } + NextElm: + il1++; + } + } + if ( KnapsackPossible == NON_PNE ) { + /* On peut changer le type */ + printf("On change le type de la variable %d\n",Var); + TypeDeVariable[Var] = REEL; + TypeDeVariableChange = OUI_PNE; + break; + } + NextIc: + ic = Csui[ic]; + } + if ( TypeDeVariableChange == OUI_PNE ) break; + NextIl_2: + il++; + } + +} + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_choix_des_variables_a_instancier.c b/src/ext/Sirius_Solver/pne/pne_choix_des_variables_a_instancier.c new file mode 100644 index 0000000000..9c3a90f634 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_choix_des_variables_a_instancier.c @@ -0,0 +1,62 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Determination des variables a instancier. + SP appele par la partie Branch and Bound. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +/*----------------------------------------------------------------------------*/ + +void PNE_ChoixDesVariablesAInstancier( PROBLEME_PNE * Pne, + int * ValeurDInstanciationAGauche, + int * NombreDeVariablesAInstancierAGauche, + int ** NumerosDesVariablesAInstancierAGauche, + int * ValeurDInstanciationADroite, + int * NombreDeVariablesAInstancierADroite, + int ** NumerosDesVariablesAInstancierADroite + ) +{ + +/* S'il y a des Gub on les prend en priorite */ +if ( Pne->NbVarGauche <= 0 || Pne->NbVarDroite <= 0 ) { + Pne->ValeurAGauche = 0; + Pne->NbVarGauche = 1; + Pne->PaquetDeGauche[0] = Pne->VariableLaPlusFractionnaire; + Pne->ValeurADroite = 1; + Pne->NbVarDroite = 1; + Pne->PaquetDeDroite[0] = Pne->VariableLaPlusFractionnaire; +} + +*ValeurDInstanciationAGauche = Pne->ValeurAGauche; +*NombreDeVariablesAInstancierAGauche = Pne->NbVarGauche; +*NumerosDesVariablesAInstancierAGauche = Pne->PaquetDeGauche; + +*ValeurDInstanciationADroite = Pne->ValeurADroite; +*NombreDeVariablesAInstancierADroite = Pne->NbVarDroite; +*NumerosDesVariablesAInstancierADroite = Pne->PaquetDeDroite; + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_classer_coeff_contraintes_ordre_decroissant.c b/src/ext/Sirius_Solver/pne/pne_classer_coeff_contraintes_ordre_decroissant.c new file mode 100644 index 0000000000..2055e84c55 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_classer_coeff_contraintes_ordre_decroissant.c @@ -0,0 +1,103 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Dans chaque contrainte on classe les coefficients dans + l'ordre decroissant des valeurs absolues. + Ca sert a calculer les min max contraintes en utilisant + les cliques. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +int PNE_PartitionCoeffContraintesTriRapide( double * , int * , int , int ); +void PNE_ClasserCoeffContraintesTriRapide( double * , int * , int , int ); + +/*----------------------------------------------------------------------------*/ + +int PNE_PartitionCoeffContraintesTriRapide( double * A, int * Nuvar, int Debut, int Fin ) +{ +int Compt; double Pivot; int i; double a; int v; +Compt = Debut; +Pivot = fabs( A[Debut] ); +/* Ordre decroissant */ +for ( i = Debut + 1 ; i <= Fin ; i++) { + if ( fabs( A[i] ) > Pivot) { + Compt++; + a = A[Compt]; + A[Compt] = A[i]; + A[i] = a; + v = Nuvar[Compt]; + Nuvar[Compt] = Nuvar[i]; + Nuvar[i] = v; + } +} +a = A[Compt]; +A[Compt] = A[Debut]; +A[Debut] = a; +v = Nuvar[Compt]; +Nuvar[Compt] = Nuvar[Debut]; +Nuvar[Debut] = v; +return(Compt); +} + +/*----------------------------------------------------------------------------*/ + +void PNE_ClasserCoeffContraintesTriRapide( double * A, int * Nuvar, int Debut, int Fin ) +{ +int Pivot; +if ( Debut < Fin ) { + Pivot = PNE_PartitionCoeffContraintesTriRapide( A, Nuvar, Debut, Fin ); + PNE_ClasserCoeffContraintesTriRapide( A, Nuvar, Debut, Pivot-1 ); + PNE_ClasserCoeffContraintesTriRapide( A, Nuvar, Pivot+1, Fin ); +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_ClasserLesCoefficientsDesContraintesOrdreDecroissant( PROBLEME_PNE * Pne ) +{ +int * Mdeb; int * NbTerm; int * Nuvar; double * A; int NombreDeContraintes; +int Debut; int Fin; int Cnt; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( NbTerm[Cnt] <= 0 ) continue; + Debut = Mdeb[Cnt]; + if ( Debut < 0 ) continue; + Fin = Debut + NbTerm[Cnt] - 1; + PNE_ClasserCoeffContraintesTriRapide( A, Nuvar, Debut, Fin ); +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_cliques_controle_avant_resolution.c b/src/ext/Sirius_Solver/pne/pne_cliques_controle_avant_resolution.c new file mode 100644 index 0000000000..3b3a9fb628 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_cliques_controle_avant_resolution.c @@ -0,0 +1,108 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Controle des cliques soit avant le strong branching + soit avant la resolution d'un probleme relaxe sur la + base des variables instancees. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_ControleCliquesAvantResolutionProblemeRelaxe( PROBLEME_PNE * Pne, int * Faisabilite ) +{ +double S; CLIQUES * Cliques; int c; int * First; int * NbElements; int il; int ilMax; +double * Coeff; int * Indice; int Pivot; char * LaCliqueEstDansLePool; int * NoeudDeClique; +double * Xmin; double * Xmax; + +/* Remarque: je constate qu'il est tres rare que des cliques soient violees avant la resolution du noeud, +donc il n'est pas prouve que ca vaille le coup */ + +return; + +if ( Pne->Cliques == NULL ) return; + +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; +Cliques = Pne->Cliques; +First = Cliques->First; +NbElements = Cliques->NbElements; +NoeudDeClique = Cliques->Noeud; +LaCliqueEstDansLePool = Cliques->LaCliqueEstDansLePool; +Pivot = Pne->ConflictGraph->Pivot; + +Coeff = Pne->Coefficient_CG; +Indice = Pne->IndiceDeLaVariable_CG; + +for ( c = 0 ; c < Cliques->NombreDeCliques ; c++ ) { + if ( LaCliqueEstDansLePool[c] == OUI_PNE ) continue; + il = First[c]; + if ( il < 0 ) continue; /* On ne sait jamais ... */ + ilMax = il + NbElements[c]; + S = 0; + while ( il < ilMax ) { + if ( NoeudDeClique[il] < Pivot ) { + S += Xmin[NoeudDeClique[il]]; + } + else { + S += 1 - Xmax[NoeudDeClique[il]-Pivot]; + } + il++; + } + if ( S > 1.0001 ) { + /* La clique est violee des le depart */ + printf("!!!! clique violee avant la resolution du pb relaxe !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + *Faisabilite = NON_PNE; + return; + } +} + +printf("pas de clique violee avant la resolution du pb relaxe\n"); + +return; +} + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_cliques_determination.c b/src/ext/Sirius_Solver/pne/pne_cliques_determination.c new file mode 100644 index 0000000000..6175a43eac --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_cliques_determination.c @@ -0,0 +1,567 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Conflict graph et cliques. + Determination des cliques a partir du conflict graph en + utilisant l'algorithme de Bron-Kerbosch . + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define VERBOSE_TOUTES_LES_CLIQUES_TROUVEE NON_PNE + +# define DUREE_DE_RECHERCHE_DE_CLIQUES 1800 /*1*/ /* En secondes */ + +# define INCREMENT_ALLOC_CLIQUES 10000 /*1000*/ +# define INCREMENT_ALLOC_TAILLE_CLIQUES (5*INCREMENT_ALLOC_CLIQUES) +# define NOMBRE_MAX_DE_CLIQUES 100000 /*50000*/ +# define DIVISEUR_POUR_NOMBRE_MAX_DE_CLIQUES 4. +# define MAX_LOCAL_EDGES 20000 + +void PNE_AllocCliques( PROBLEME_PNE * ); +void PNE_ReallocNbCliques( PROBLEME_PNE * ); +void PNE_ReallocTailleCliques( PROBLEME_PNE * ); +void PNE_MaxClique( PROBLEME_PNE * , int * , int * , int * , int , int * , int , int * , int , int * , char * ); + +/*----------------------------------------------------------------------------*/ + +void PNE_AllocCliques( PROBLEME_PNE * Pne ) +{ +CLIQUES * Cliques; int i; +Pne->Cliques = (CLIQUES *) malloc( sizeof( CLIQUES ) ); +if ( Pne->Cliques == NULL ) return; +Cliques = Pne->Cliques; +Cliques->NbCliquesAllouees = INCREMENT_ALLOC_CLIQUES; +Cliques->First = (int *) malloc( Cliques->NbCliquesAllouees * sizeof( int ) ); +if ( Cliques->First == NULL ) { + free( Cliques->First ); Pne->Cliques = NULL; + return; +} +Cliques->NbElements = (int *) malloc( Cliques->NbCliquesAllouees * sizeof( int ) ); +if ( Cliques->NbElements == NULL ) { + free( Cliques->First ); Cliques->First = NULL; + free( Pne->Cliques ); Pne->Cliques = NULL; + return; +} +Cliques->TailleCLiquesAllouee = INCREMENT_ALLOC_TAILLE_CLIQUES; +Cliques->Noeud = (int *) malloc( Cliques->TailleCLiquesAllouee * sizeof( int ) ); +if ( Cliques->Noeud == NULL ) { + free( Cliques->First ); Cliques->First = NULL; + free( Cliques->NbElements ); Cliques->NbElements = NULL; + free( Pne->Cliques ); Pne->Cliques = NULL; + return; +} + +Cliques->LaCliqueEstDansLePool = (char *) malloc( Cliques->NbCliquesAllouees * sizeof( char ) ); +if ( Cliques->LaCliqueEstDansLePool == NULL ) { + free( Cliques->First ); Cliques->First = NULL; + free( Cliques->NbElements ); Cliques->NbElements = NULL; + free( Cliques->Noeud ); Cliques->Noeud = NULL; + free( Pne->Cliques ); Pne->Cliques = NULL; + return; +} + +Cliques->CliqueDeTypeEgalite = (char *) malloc( Cliques->NbCliquesAllouees * sizeof( char ) ); +if ( Cliques->CliqueDeTypeEgalite == NULL ) { + free( Cliques->First ); Cliques->First = NULL; + free( Cliques->NbElements ); Cliques->NbElements = NULL; + free( Cliques->Noeud ); Cliques->Noeud = NULL; + free( Cliques->LaCliqueEstDansLePool ); Cliques->LaCliqueEstDansLePool = NULL; + free( Pne->Cliques ); Pne->Cliques = NULL; + return; +} + +Cliques->NumeroDeCliqueDuNoeud = (int *) malloc( 2 * Pne->NombreDeVariablesTrav * sizeof( int ) ); +if ( Cliques->NumeroDeCliqueDuNoeud == NULL ) { + free( Cliques->First ); Cliques->First = NULL; + free( Cliques->NbElements ); Cliques->NbElements = NULL; + free( Cliques->Noeud ); Cliques->Noeud = NULL; + free( Cliques->LaCliqueEstDansLePool ); Cliques->LaCliqueEstDansLePool = NULL; + free( Cliques->CliqueDeTypeEgalite ); Cliques->CliqueDeTypeEgalite = NULL; + free( Pne->Cliques ); Pne->Cliques = NULL; + return; +} + +Cliques->NombreDeCliques = 0; +Cliques->Full = NON_PNE; + +for ( i = 0 ; i < 2 * Pne->NombreDeVariablesTrav ; i++ ) Cliques->NumeroDeCliqueDuNoeud[i] = -1; + +return; +} + +/*----------------------------------------------------------------------------*/ +void PNE_ReallocNbCliques( PROBLEME_PNE * Pne ) +{ +int i; int * pt; char * ptc; CLIQUES * Cliques; +Cliques = Pne->Cliques; +i = Cliques->NbCliquesAllouees + INCREMENT_ALLOC_CLIQUES; +pt = (int *) realloc( Cliques->First , i * sizeof( int ) ); +if ( pt == NULL ) { Cliques->Full = OUI_PNE; return; } +Cliques->First = pt; +pt = (int *) realloc( Cliques->NbElements , i * sizeof( int ) ); +if ( pt == NULL ) { Cliques->Full = OUI_PNE; return; } +Cliques->NbElements = pt; +ptc = (char *) realloc( Cliques->LaCliqueEstDansLePool , i * sizeof( char ) ); +if ( ptc == NULL ) { Cliques->Full = OUI_PNE; return; } +Cliques->LaCliqueEstDansLePool = ptc; +ptc = (char *) realloc( Cliques->CliqueDeTypeEgalite , i * sizeof( char ) ); +if ( ptc == NULL ) { Cliques->Full = OUI_PNE; return; } +Cliques->CliqueDeTypeEgalite = ptc; +Cliques->NbCliquesAllouees = i; +return; +} +/*----------------------------------------------------------------------------*/ +void PNE_ReallocTailleCliques( PROBLEME_PNE * Pne ) +{ +int i; int * pt; CLIQUES * Cliques; +Cliques = Pne->Cliques; +i = Cliques->TailleCLiquesAllouee + INCREMENT_ALLOC_TAILLE_CLIQUES; +pt = (int *) realloc( Cliques->Noeud , i * sizeof( int ) ); +if ( pt == NULL ) { Cliques->Full = OUI_PNE; return; } +Cliques->Noeud = pt; +Cliques->TailleCLiquesAllouee = i; +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_ArchiverMaxClique( PROBLEME_PNE * Pne, int NbElemDansK, int * K ) +{ +int i; CLIQUES * Cliques; int c; int Index; int * Noeud; int j; int Pivot; +int * NumeroDeCliqueDuNoeud; + +Pivot = Pne->ConflictGraph->Pivot; + +/* Finalement on ne retient pas les cliques a 2 elements car elles sont dans les implications */ +if ( NbElemDansK <= 2 ) return; + +/* Controle: si la clique ne contient que 2 termes on regarde si c'est une variable et + sont complement. Si c'est le cas on ne la regarde pas */ +if ( NbElemDansK == 2 ) { + i = K[0]; + j = K[1]; + if ( j == i + Pivot ) return; + if ( i == j + Pivot ) return; +} +if ( Pne->Cliques == NULL ) { + PNE_AllocCliques( Pne ); +} +if ( Pne->Cliques == NULL ) return; + +Cliques = Pne->Cliques; +Noeud = Cliques->Noeud; +NumeroDeCliqueDuNoeud = Cliques->NumeroDeCliqueDuNoeud; + +c = Cliques->NombreDeCliques - 1; +if ( c >= 0 ) Index = Cliques->First[c] + Cliques->NbElements[c]; +else Index = 0; +c++; + +if ( c == Cliques->NbCliquesAllouees ) { + PNE_ReallocNbCliques( Pne ); + if ( Cliques->Full == OUI_PNE ) return; +} + +Cliques->First[c] = Index; +for ( i = 0 ; i < NbElemDansK ; i++ ) { + if ( Index == Cliques->TailleCLiquesAllouee ) { + /*printf("ReallocTailleCliques\n");*/ + PNE_ReallocTailleCliques( Pne ); + if ( Cliques->Full == OUI_PNE ) return; + Noeud = Cliques->Noeud; + } + Noeud[Index] = K[i]; + /* Affectation d'un numero de clique a la variable */ + if ( NumeroDeCliqueDuNoeud[K[i]] < 0 ) NumeroDeCliqueDuNoeud[K[i]] = c; + else { + if ( Cliques->NbElements[NumeroDeCliqueDuNoeud[K[i]]] < NbElemDansK ) { + NumeroDeCliqueDuNoeud[K[i]] = c; + } + } + Index++; +} + +Cliques->NbElements[c] = NbElemDansK; +Cliques->LaCliqueEstDansLePool[c] = NON_PNE; +Cliques->CliqueDeTypeEgalite[c] = NON_PNE; +Cliques->NombreDeCliques++; + +if ( Pne->Cliques->NombreDeCliques > NOMBRE_MAX_DE_CLIQUES ) { + Cliques->Full = OUI_PNE; + /*printf("Attention Cliques->Full = OUI_PNE \n");*/ +} + +# if VERBOSE_TOUTES_LES_CLIQUES_TROUVEE == OUI_PNE + printf("Clique maximale \n"); + for ( i = 0 ; i < NbElemDansK ; i++ ) printf(" %d ",K[i]); + printf("\n"); +# endif + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_MaxClique( PROBLEME_PNE * Pne, int * First, int * Adjacent, int * NbEdges, + int NbElemDansK, int * K, int NbElemDansC, int * C, + int NbElemDansA, int * A, char * LeNoeudEstDansC ) +{ +int i; int j; int n; int k; int Edge; int NbDansC; int * Cbuff; int * Abuff; +int u; int Maximal; int NbDansA; int EdgeMx; + +if (Pne->Cliques != NULL ) { + if ( Pne->Cliques->Full == OUI_PNE ) { + return; + } +} + +/* Si C est vide on a une clique maximale */ +if ( NbElemDansC == 0 ) { + /* On test si la clique est violee */ + PNE_ArchiverMaxClique( Pne, NbElemDansK, K ); + return; +} + +/* Recherche de u dans C tel que C inter V(u) est maximal */ +/* Attention, cette sequence peut etre tres couteuse en temps de calcul */ + +/*for ( n = 0 ; n < NbElemDansC ; n++ ) LeNoeudEstDansC[C[n]] = OUI_PNE;*/ + +Maximal = -1; +u = 1; +for ( n = 0 ; n < NbElemDansC ; n++ ) { + i = C[n]; + NbDansC = 0; + Edge = First[i]; + EdgeMx = Edge + NbEdges[i]; + while ( Edge < EdgeMx ) { + if ( LeNoeudEstDansC[Adjacent[Edge]] == OUI_PNE ) { NbDansC++; break; } + Edge++; + } + if ( NbDansC > Maximal ) { + Maximal = NbDansC; + u = i; + } +} + +for ( n = 0 ; n < NbElemDansC ; n++ ) LeNoeudEstDansC[C[n]] = NON_PNE; + +if ( Maximal < 0 ) { + return; +} +/* Fin de la sequence couteuse en temps de calcul */ + +for ( n = 0 ; n < NbElemDansA ; n++ ) { + + /* i doit etre dans A */ + i = A[n]; + /* i doit etre dans A - V(u) i.e pas dans V(u) */ + k = 1; + Edge = First[u]; + EdgeMx = Edge + NbEdges[u]; + while ( Edge < EdgeMx ) { + if ( Adjacent[Edge] == i ) { k = 0; break; } + Edge++; + } + if ( k == 0 ) continue; + + /* Alloc de Cbuff et de Abuff */ + Cbuff = (int *) malloc( ( NbElemDansC + NbElemDansA ) * sizeof( int ) ); + if ( Cbuff == NULL ) continue; + Abuff = (int *) &Cbuff[NbElemDansC]; + + /* Construction de C inter Voisins(i) et de A inter Voisins(i) */ + NbDansC = 0; + NbDansA = 0; + Edge = First[i]; + EdgeMx = Edge + NbEdges[i]; + while ( Edge < EdgeMx ) { + j = Adjacent[Edge]; + for ( k = 0 ; k < NbElemDansC ; k++ ) { + /* Ajouter j au nouveau C */ + if ( C[k] == j ) { Cbuff[NbDansC] = j; LeNoeudEstDansC[j] = OUI_PNE; NbDansC++; break; } + } + for ( k = 0 ; k < NbElemDansA ; k++ ) { + /* Ajouter j au nouveau A */ + if ( A[k] == j ) { Abuff[NbDansA] = j; NbDansA++; break; } + } + Edge++; + } + + K[NbElemDansK] = i; + NbElemDansK += 1; + + PNE_MaxClique( Pne, First, Adjacent, NbEdges, NbElemDansK, K, NbDansC, Cbuff, NbDansA, Abuff, LeNoeudEstDansC ); + + NbElemDansK -= 1; + + /* On enleve i de l'ensemble A */ + A[n] = A[NbElemDansA-1]; + NbElemDansA--; + n--; + + free( Cbuff ); + + if ( Pne->Cliques != NULL ) { + if ( Pne->Cliques->Full == OUI_PNE ) break; + } + + if ( Pne->ArreterCliquesEtProbing == NON_PNE ) { + time( &(Pne->HeureDeCalendrierCourantCliquesEtProbing) ); + Pne->TempsEcoule = difftime( Pne->HeureDeCalendrierCourantCliquesEtProbing, Pne->HeureDeCalendrierDebutCliquesEtProbing ); + if ( Pne->Controls == NULL || 1 ) { + if ( Pne->TempsEcoule > DUREE_DE_RECHERCHE_DE_CLIQUES ) { + Pne->ArreterCliquesEtProbing = OUI_PNE; + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Cliques computation was stopped. Timeout is %d elapsed is %e\n",DUREE_DE_RECHERCHE_DE_CLIQUES,Pne->TempsEcoule); + } + } + } + else { + /* On est dans une heuristique */ + if ( Pne->TempsEcoule > 1 ) Pne->ArreterCliquesEtProbing = OUI_PNE; + } + } + + if ( Pne->ArreterCliquesEtProbing == OUI_PNE ) break; + +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CliquesConflictGraph( PROBLEME_PNE * Pne ) +{ +int i; int NombreDeVariablesTrav; int * Adjacent; int * Next; int * First; +CONFLICT_GRAPH * ConflictGraph; int * K; int * C; int * A; int NbElemDansK; +int NbElemDansC; int NbElemDansA; PROBING_OU_NODE_PRESOLVE * Prb; +int NbNoeudsDuGraphe; char * LeNoeudEstDansC; int * PremiereArete; int * NombreAretes; +int * NoeudAdjacent; char * NoeudDejaExamine; int * NbEdgesParNoeud; int N; int NbN; +int Node; int Cpt; int * NoeudLocal; int j; int * Pile; int NbAretes; int Nb; int Edge; + +if ( Pne->Controls != NULL ) { + if ( Pne->Controls->RechercherLesCliques == NON_PNE ) { + return; + } +} + +Prb = Pne->ProbingOuNodePresolve; +ConflictGraph = Pne->ConflictGraph; +if ( ConflictGraph == NULL ) return; + +if ( ConflictGraph->NbEdges <= ConflictGraph->NbEdgesLast ) return; +ConflictGraph->NbEdgesLast = ConflictGraph->NbEdges; + +NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; +NbNoeudsDuGraphe = ConflictGraph->NbNoeudsDuGraphe; +Adjacent = ConflictGraph->Adjacent; +Next = ConflictGraph->Next; +First = ConflictGraph->First; + +/* On reinitialise les cliques car sinon on peut empiler plusieurs cliques identiques */ +if ( Pne->Cliques != NULL ) { + /* S'il y avait deja trop de cliques, on arrete */ + if ( Pne->Cliques->Full == OUI_PNE ) return; + + Pne->Cliques->NombreDeCliques = 0; + Pne->Cliques->Full = NON_PNE; + for ( i = 0 ; i < 2 * Pne->NombreDeVariablesTrav ; i++ ) Pne->Cliques->NumeroDeCliqueDuNoeud[i] = -1; +} + +K = (int *) malloc( NbNoeudsDuGraphe * sizeof( int ) ); +C = (int *) malloc( NbNoeudsDuGraphe * sizeof( int ) ); +A = (int *) malloc( NbNoeudsDuGraphe * sizeof( int ) ); +LeNoeudEstDansC = (char *) malloc( NbNoeudsDuGraphe * sizeof( char ) ); + +Pile = (int *) malloc( ConflictGraph->NbEdges * sizeof( int ) ); +NbEdgesParNoeud = (int *) malloc( NbNoeudsDuGraphe * sizeof( int ) ); +NoeudLocal = (int *) malloc( NbNoeudsDuGraphe * sizeof( int ) ); +PremiereArete = (int *) malloc( NbNoeudsDuGraphe * sizeof( int ) ); +NombreAretes = (int *) malloc( NbNoeudsDuGraphe * sizeof( int ) ); +NoeudAdjacent = (int *) malloc( ConflictGraph->NbEdges * sizeof( int ) ); +NoeudDejaExamine = (char *) malloc( NbNoeudsDuGraphe * sizeof( char ) ); + +if ( K == NULL || C == NULL || A == NULL || LeNoeudEstDansC == NULL || + Pile == NULL || NbEdgesParNoeud == NULL || NoeudLocal == NULL || + PremiereArete == NULL || NombreAretes == NULL || NoeudAdjacent == NULL || + NoeudDejaExamine == NULL ) { + free( K ); free( C ); free( A ); free( LeNoeudEstDansC ); + free( Pile ); free( NbEdgesParNoeud ); free( NoeudLocal ); free( PremiereArete ); + free( NombreAretes ); free( NoeudAdjacent ); free( NoeudDejaExamine ); + return; +} + +for ( N = 0 ; N < NbNoeudsDuGraphe ; N++ ) { + NoeudDejaExamine[N] = NON_PNE; + NbAretes = 0; + Edge = First[N]; + while ( Edge >= 0 ) { + NbAretes++; + Edge = Next[Edge]; + } + NbEdgesParNoeud[N] = NbAretes; +} + +for ( N = 0 ; N < NbNoeudsDuGraphe ; N++ ) { + if ( NoeudDejaExamine[N] == OUI_PNE ) continue; + if ( First[N] < 0 ) continue; + NbN = 0; + Cpt = 0; + Node = N; + NbAretes = 0; + DepartNoeud: + NoeudLocal[NbN] = Node; + + NbAretes += NbEdgesParNoeud[Node]; + if ( NbAretes > MAX_LOCAL_EDGES ) goto GrapheUtile; + + NbN++; + NoeudDejaExamine[Node] = OUI_PNE; + /* Construction de la liste des noeuds de la composante connexe */ + Edge = First[Node]; + DepartEdge: + while ( Edge >= 0 ) { + j = Adjacent[Edge]; + if ( NoeudDejaExamine[j] == NON_PNE ) { + /* On met j dans la pile et on examine ses voisins */ + Pile[Cpt] = Edge; + Cpt++; + Node = j; + goto DepartNoeud; + } + Edge = Next[Edge]; + } + Cpt--; + if ( Cpt >= 0 ) { + Edge = Pile[Cpt]; + goto DepartEdge; + } + GrapheUtile: + + if ( NbN <= 4 ) continue; + /* Transfert du graphe utile */ + NbAretes = 0; + for ( j = 0 ; j < NbN ; j++ ) { + Node = NoeudLocal[j]; + Nb = 0; + Edge = First[Node]; + PremiereArete[Node] = NbAretes; + while ( Edge >= 0 ) { + NoeudAdjacent[NbAretes] = Adjacent[Edge]; + NbAretes++; + Nb++; + Edge = Next[Edge]; + } + NombreAretes[Node] = Nb; + } + + if ( NbAretes <= 3 ) continue; + + NbElemDansK = 0; + NbElemDansC = 0; + NbElemDansA = 0; + + /* C et A : tous noeuds */ + for ( j = 0 ; j < NbN ; j++ ) { + Node = NoeudLocal[j]; + LeNoeudEstDansC[Node] = NON_PNE; + if ( NombreAretes[Node] < 0 ) continue; + C[NbElemDansC] = Node; + LeNoeudEstDansC[Node] = OUI_PNE; + NbElemDansC++; + A[NbElemDansA] = Node; + NbElemDansA++; + } + + Pne->ArreterCliquesEtProbing = NON_PNE; + time( &(Pne->HeureDeCalendrierDebutCliquesEtProbing) ); + + PNE_MaxClique( Pne, PremiereArete, NoeudAdjacent, NombreAretes, NbElemDansK, K, NbElemDansC, C, NbElemDansA, A, LeNoeudEstDansC ); + + if ( Pne->Cliques != NULL ) Pne->Cliques->Full = NON_PNE; + Pne->ArreterCliquesEtProbing = NON_PNE; + +} + +free( K ); +free( C ); +free( A ); +free( LeNoeudEstDansC ); + +free( Pile ); +free( NbEdgesParNoeud ); +free( NoeudLocal ); +free( PremiereArete ); +free( NombreAretes ); +free( NoeudAdjacent ); +free( NoeudDejaExamine ); + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + if ( Pne->Cliques != NULL ) { + if ( Pne->Cliques->NombreDeCliques > 0 ) { + printf("Found %d clique(s) using the conflict graph\n",Pne->Cliques->NombreDeCliques); + } + } +} + +if ( Pne->Cliques != NULL && 0 ) { + if ( Pne->Cliques->NombreDeCliques > 0 ) { + /* Apres essais je n'ai jamais trouve de cas ou on pouvait transformer en egalites. + Donc inutile d'y passer du temps. */ + /*PNE_TransformerCliquesEnEgalites( Pne );*/ + /* + printf("Exit dans cliques determination\n"); + exit(0); + */ + } +} + + + +return; +} + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_cliques_egalite.c b/src/ext/Sirius_Solver/pne/pne_cliques_egalite.c new file mode 100644 index 0000000000..ed911a5a7c --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_cliques_egalite.c @@ -0,0 +1,418 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On essaie de transformer les cliques en contraintes d'egalite. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +void PNE_TesterFaisabiliteClique( PROBLEME_PNE * , int , int , int * , char * , double * , + double * , int * , int * , double * , int * , + double * , char * , int * , int * , int * , + char * , char * , double * , double * , + double * , double * , double * , double * , + int * ); + +/*----------------------------------------------------------------------------*/ + +void PNE_TesterFaisabiliteClique( PROBLEME_PNE * Pne , int NombreDeContraintes, + int NombreDeVariables, int * TypeDeVariable, + char * BorneInfConnue, double * ValeurDeBorneInf, + double * ValeurDeBorneSup, + int * Mdeb, int * NbTerm, double * A, int * Nuvar, + double * B, char * SensContrainte, + int * Cdeb, int * Csui, int * NumContrainte, + char * BminValide, char * BmaxValide, double * Bmin, double * Bmax, + double * XminSv, double * Xmin, double * XmaxSv, double * Xmax, + int * Faisabilite ) +{ +int Cnt; int Var1; char BrnInfConnue; int Var; int il; int ilMax; char XsValide; char XiValide; +double S; double Xi; double Xs; double Ai; double BminNew; double BmaxNew; double Xs0; double Xi0; +double BCnt; char BmnValide; char BmxValide; double Bmn; double Bmx; char SensCnt; +int ic; double NouvelleValeur; char BorneMiseAJour; char UneVariableAEteFixee; int Nb; + +/* Contraintes a une seule variable: on essaie de les fixer ou d'ameliorer la borne de + la variable sans la distinction du type entier ou continu */ + +*Faisabilite = OUI_PNE; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + +continue; + + Nb = 0; + Var1 = -1; + S = 0.0; + Ai = 1; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( A[il] == 0.0 ) goto NextElement; + Var = Nuvar[il]; + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) { + S += A[il] * ValeurDeBorneInf[Var]; + goto NextElement; + } + Nb++; + if ( Nb > 1 ) break; + Var1 = Var; + Ai = A[il]; + NextElement: + il++; + } + if ( Nb != 1 ) continue; + Var = Var1; + XsValide = NON_PNE; + XiValide = NON_PNE; + Xi = ValeurDeBorneInf[Var]; + Xs = ValeurDeBorneSup[Var]; + S = B[Cnt] - S; + if ( SensContrainte[Cnt] == '=' ) { + XiValide = OUI_PNE; + XsValide = OUI_PNE; + Xi = S / Ai; + Xs = Xi; + } + else { + if ( Ai > 0 ) { Xs = S / Ai; XsValide = OUI_PNE; } + else { Xi = -S / fabs( Ai ); XiValide = OUI_PNE; } + } + UneVariableAEteFixee = NON_PNE; + BorneMiseAJour = NON_PNE; + PNE_ModifierLaBorneDUneVariable( Pne, Var, SensContrainte[Cnt], XsValide, Xs, XiValide, Xi, &NouvelleValeur, + &BorneMiseAJour, &UneVariableAEteFixee, Faisabilite ); + if ( *Faisabilite == NON_PNE ) { + return; + } + + /* Si la variable a ete fixee ou une borne mise a jour on modifie les bornes des contraintes */ + if ( UneVariableAEteFixee != NON_PNE || BorneMiseAJour != NON_PNE ) { + PNE_NodePresolveGrapheDeConflit( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, XminSv, + XmaxSv, Xmin, Xmax, Var, NouvelleValeur, Faisabilite ); + if ( *Faisabilite == NON_PNE ) { + return; + } + } +} + +/* Apres avoir balaye les contraintes a une seule variable, on examine les variables + colonne par colonne et on essaie de les fixer */ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeVariable[Var] != ENTIER ) continue; + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) continue; + ic = Cdeb[Var]; + while ( ic >= 0 ) { + Ai = A[ic]; + if ( Ai == 0.0 ) goto NextIc; + Cnt = NumContrainte[ic]; + SensCnt = SensContrainte[Cnt]; + BmnValide = BminValide[Cnt]; + BmxValide = BmaxValide[Cnt]; + Bmn = Bmin[Cnt]; + Bmx = Bmax[Cnt]; + BCnt = B[Cnt]; + if ( SensCnt == '<' ) { + if ( BmxValide == OUI_PNE ) { + if ( Bmx <= BCnt + SEUIL_DADMISSIBILITE ) goto NextIc; + } + } + + XsValide = NON_PNE; + XiValide = NON_PNE; + Xs = ValeurDeBorneSup[Var]; + Xi = ValeurDeBorneInf[Var]; + Xs0 = Xs; + Xi0 = Xi; + + UneVariableAEteFixee = NON_PNE; + BorneMiseAJour = NON_PNE; + + if ( SensCnt == '=' ) { + /* On regarde le min et le max */ + if ( BmnValide == OUI_PNE ) { + BminNew = Bmn; + if ( Ai > 0.0 ) BminNew -= Ai * Xi0; /* On avait pris le min */ + else BminNew -= Ai * Xs0; /* On avait pris le mas */ + S = BCnt - BminNew; + if ( Ai > 0 ) { Xs = S / Ai; XsValide = OUI_PNE; } + else { Xi = -S / fabs( Ai ); XiValide = OUI_PNE; } + } + if ( BmxValide == OUI_PNE ) { + BmaxNew = Bmx; + if ( Ai > 0.0 ) BmaxNew -= Ai * Xs0; /* On avait pris le max */ + else BmaxNew -= Ai * Xi0; /* On avait pris le min */ + S = BCnt - BmaxNew; + if ( Ai > 0 ) { Xi = S / Ai; XiValide = OUI_PNE; } + else { Xs = -S / fabs( Ai ); XsValide = OUI_PNE; } + } + } + else { /* SensContrainte est '<' */ + /* On peut calculer un majorant */ + if ( BmnValide == OUI_PNE ) { + BminNew = Bmn; + if ( Ai > 0.0 ) BminNew -= Ai * Xi0; /* On avait pris le min */ + else BminNew -= Ai * Xs0; /* On avait pris le max */ + S = BCnt - BminNew; + if ( Ai > 0 ) { Xs = S / Ai; XsValide = OUI_PNE; } + else { Xi = -S / fabs( Ai ); XiValide = OUI_PNE; } + } + } + + /* Que si Xi ou Xs sont valides et si une des 2 bornes est plus petite ou plus grande */ + if ( XiValide != OUI_PNE && XsValide != OUI_PNE ) goto NextIc; + if ( Xi <= Xi0 && Xs >= Xs0 ) goto NextIc; + PNE_ModifierLaBorneDUneVariable( Pne, Var, SensCnt, XsValide, Xs, XiValide, Xi, &NouvelleValeur, + &BorneMiseAJour, &UneVariableAEteFixee, Faisabilite ); + if ( *Faisabilite == NON_PNE ) { + return; + } + goto NextIc; + + /* Si la variable a ete fixee ou une borne mise a jour on modifie les bornes des contraintes */ + if ( UneVariableAEteFixee != NON_PNE || BorneMiseAJour != NON_PNE ) { + *Faisabilite = OUI_PNE; + PNE_NodePresolveGrapheDeConflit( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, XminSv, + XmaxSv, Xmin, Xmax, Var, NouvelleValeur, Faisabilite ); + if ( *Faisabilite == NON_PNE ) { + return; + } + } + NextIc: + ic = Csui[ic]; + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_TransformerCliquesEnEgalites( PROBLEME_PNE * Pne ) +{ +int NombreDeVariables; double * X; double * Xmin; double * Xmax; char BorneMiseAJour; +CLIQUES * Cliques; int c; int NombreDeContraintes; double ValeurDeVar; int ilDeb; +int * First; int * NbElements; int il; int ilMax; int Faisabilite; int Pivot; +int Var; int * NoeudDeClique; int * TypeDeBorne; char Ok; double * Bmin; double * Bmax; +double * BminSv; double * BmaxSv; double * XminSv; double * XmaxSv; int * Cdeb; +int * Csui; int * NumContrainte; double * A; int * TypeDeVariable; +char * BorneInfConnue; double * ValeurDeBorneInf; double * ValeurDeBorneSup; +char * BminValide; char * BmaxValide; int * Mdeb; int * NbTerm; int * Nuvar; +double * B; char * SensContrainte; + +if ( Pne->ConflictGraph == NULL ) return; +if ( Pne->Cliques == NULL ) return; + +if ( Pne->ChainageTransposeeExploitable == NON_PNE ) PNE_ConstruireLeChainageDeLaTransposee( Pne ); + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +X = Pne->UTrav; +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; +XminSv = Pne->UminTravSv; +XmaxSv = Pne->UmaxTravSv; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; + +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +B = Pne->BTrav; +SensContrainte = Pne->SensContrainteTrav; + +Cliques = Pne->Cliques; +First = Cliques->First; +NbElements = Cliques->NbElements; +NoeudDeClique = Cliques->Noeud; +Pivot = Pne->ConflictGraph->Pivot; + +BminValide = Pne->ProbingOuNodePresolve->BminValide; +BmaxValide = Pne->ProbingOuNodePresolve->BmaxValide; +Bmin = Pne->ProbingOuNodePresolve->Bmin; +Bmax = Pne->ProbingOuNodePresolve->Bmax; +BminSv = Pne->ProbingOuNodePresolve->BminSv; +BmaxSv = Pne->ProbingOuNodePresolve->BmaxSv; + +BorneInfConnue = Pne->ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInf = Pne->ProbingOuNodePresolve->ValeurDeBorneInf; +ValeurDeBorneSup = Pne->ProbingOuNodePresolve->ValeurDeBorneSup; + +/* Calcul des bornes sur les contraintes */ + +memcpy( (char * ) XminSv, (char * ) Xmin, NombreDeVariables * sizeof( double ) ); +memcpy( (char * ) XmaxSv, (char * ) Xmax, NombreDeVariables * sizeof( double ) ); + +PNE_InitBorneInfBorneSupDesVariables( Pne ); +PNE_CalculMinEtMaxDesContraintes( Pne, &Faisabilite ); +if ( Faisabilite == NON_PNE ) return; + +/* Et on sauvegarde le resultat comme point de depart pour les noeuds suibvants */ +memcpy( (char *) BminSv, (char *) Bmin, NombreDeContraintes * sizeof( double ) ); +memcpy( (char *) BmaxSv, (char *) Bmax, NombreDeContraintes * sizeof( double ) ); + +/* On initialise a 0 toutes les variables de la clique inferieures a Pivot + et a 1 toutes les variables de la clique superieures ou egal a pivot. + S'il n'y a pas de solution admissibles alors la clique peut etre transformee + en contraintes d'egalite */ + +for ( c = 0 ; c < Cliques->NombreDeCliques ; c++ ) { + + ilDeb = First[c]; + if ( ilDeb < 0 ) continue; /* On ne sait jamais ... */ + + Pne->ProbingOuNodePresolve->Faisabilite = OUI_PNE; + Pne->ProbingOuNodePresolve->NombreDeVariablesFixees = 0; + + /* On remet des bornes inf et sup des variables */ + memcpy( (char *) Xmin, (char *) XminSv, NombreDeVariables * sizeof( double ) ); + memcpy( (char *) Xmax, (char *) XmaxSv, NombreDeVariables * sizeof( double ) ); + + il = ilDeb; + ilMax = il + NbElements[c]; + Ok = OUI_PNE; + while ( il < ilMax ) { + if ( NoeudDeClique[il] < Pivot ) { + if ( TypeDeBorne[NoeudDeClique[il]] == VARIABLE_FIXE ) { + Ok = NON_PNE; + break; + } + /* On initialise a 0 */ + Var = NoeudDeClique[il]; + Xmin[Var] = 0.0; + Xmax[Var] = 0.0; + } + else { + if ( TypeDeBorne[NoeudDeClique[il]-Pivot] == VARIABLE_FIXE ) { + Ok = NON_PNE; + break; + } + /* On initialise a 1 */ + Var = NoeudDeClique[il]-Pivot; + Xmin[Var] = 1.0; + Xmax[Var] = 1.0; + } + il++; + } + + if ( Ok == NON_PNE ) continue; + + PNE_InitBorneInfBorneSupDesVariables( Pne ); + + /* On recupere les bornes des contraintes au noeud racine */ + memcpy( (char *) Bmin, (char *) BminSv, NombreDeContraintes * sizeof( double ) ); + memcpy( (char *) Bmax, (char *) BmaxSv, NombreDeContraintes * sizeof( double ) ); + + il = ilDeb; + while ( il < ilMax ) { + if ( NoeudDeClique[il] < Pivot ) { + /* On initialise a 0 */ + Var = NoeudDeClique[il]; + ValeurDeVar = 0; + BorneMiseAJour = MODIF_BORNE_SUP; + } + else { + /* On initialise a 1 */ + Var = NoeudDeClique[il]-Pivot; + ValeurDeVar = 1; + BorneMiseAJour = MODIF_BORNE_INF; + } + + /* On met a jour les contraintes dans lesquelles la variable intervient */ + PNE_NodePresolveMajBminBmax( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, XminSv, XmaxSv, + Var, ValeurDeVar, BorneMiseAJour ); + + il++; + } + + /* On applique le graphe de conflits */ + il = ilDeb; + while ( il < ilMax ) { + if ( NoeudDeClique[il] < Pivot ) { + /* On initialise a 0 */ + Var = NoeudDeClique[il]; + ValeurDeVar = 0; + } + else { + /* On initialise a 1 */ + Var = NoeudDeClique[il]-Pivot; + ValeurDeVar = 1; + } + Faisabilite = OUI_PNE; + PNE_NodePresolveGrapheDeConflit( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, XminSv, + XmaxSv, Xmin, Xmax, Var, ValeurDeVar, &Faisabilite ); + if ( Faisabilite == NON_PNE ) { + printf("Pas de solution apres NodePresolveGrapheDeConflit \n"); + Cliques->CliqueDeTypeEgalite[c] = OUI_PNE; + Ok = NON_PNE; + break; + } + il++; + } + /* On verifie la faisabilite */ + if ( Ok == OUI_PNE ) { + Faisabilite = OUI_PNE; + PNE_TesterFaisabiliteClique( Pne , NombreDeContraintes, NombreDeVariables, TypeDeVariable, + BorneInfConnue, ValeurDeBorneInf, ValeurDeBorneSup, + Mdeb, NbTerm, A, Nuvar, B, SensContrainte, + Cdeb, Csui, NumContrainte, BminValide, BmaxValide, Bmin, Bmax, + XminSv, Xmin, XmaxSv, Xmax, + &Faisabilite ); + + if ( Faisabilite == NON_PNE ) { + printf("Pas de solution apres TesterFaisabiliteClique \n"); + Cliques->CliqueDeTypeEgalite[c] = OUI_PNE; + } + else printf("solution\n"); + + } + +} + +Pne->ProbingOuNodePresolve->Faisabilite = OUI_PNE; + +memcpy( (char *) Xmin, (char *) XminSv, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) Xmax, (char *) XmaxSv, NombreDeVariables * sizeof( double ) ); + +memcpy( (char *) Bmin, (char *) BminSv, NombreDeContraintes * sizeof( double ) ); +memcpy( (char *) Bmax, (char *) BmaxSv, NombreDeContraintes * sizeof( double ) ); + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_cliques_violees.c b/src/ext/Sirius_Solver/pne/pne_cliques_violees.c new file mode 100644 index 0000000000..d343df1ae8 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_cliques_violees.c @@ -0,0 +1,262 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Detection des cliques violees. + Les cliques ont ete determinees a partir du conflict graph. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define PROFONDEUR_LIMITE_CLIQUES 1000000 /*10*/ + +/*----------------------------------------------------------------------------*/ + +void PNE_DetectionDesCliquesViolees( PROBLEME_PNE * Pne ) +{ +double S; int NombreDeVariablesTrav; double * UTrav; CLIQUES * Cliques; int c; +int * First; int * NbElements; double NormeV; int il; int ilMax; +double * Coeff; int * Indice; double B; int NbT; double X; char ControleCliques; +char ControleImplications; CONFLICT_GRAPH * ConflictGraph; int Noeud; +int NbNoeudsDuGraphe; int Pivot; int * Adjacent; int * Next; double S0; double B0; +int Var; int Complement; int Edge; int Nv; char * LaCliqueEstDansLePool; double Sec; +int * NoeudDeClique; int * TypeDeBorne; BB * Bb; int NbCliquesViolees; char Ok; +char * CliqueDeTypeEgalite; int NbImplicationsViolees; double Seuil; + +if ( Pne->ConflictGraph == NULL ) return; +if ( Pne->Cliques == NULL ) return; + +Bb = Pne->ProblemeBbDuSolveur; +if ( Bb->NoeudEnExamen->ProfondeurDuNoeud > PROFONDEUR_LIMITE_CLIQUES ) return; + +NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +UTrav = Pne->UTrav; +Cliques = Pne->Cliques; +First = Cliques->First; +NbElements = Cliques->NbElements; +NoeudDeClique = Cliques->Noeud; +LaCliqueEstDansLePool = Cliques->LaCliqueEstDansLePool; +CliqueDeTypeEgalite = Cliques->CliqueDeTypeEgalite; +Pivot = Pne->ConflictGraph->Pivot; + +Coeff = Pne->Coefficient_CG; +Indice = Pne->IndiceDeLaVariable_CG; + +ControleCliques = OUI_PNE /*OUI_PNE*/; +ControleImplications = NON_PNE; +if ( Pne->Cliques->Full == OUI_PNE ) ControleImplications = OUI_PNE; + +ControleImplications = OUI_PNE; + +if ( ControleCliques != OUI_PNE ) goto Implications; + +/* Attention: la partie simplexe considere que les variables intervenant dans les coupes ne + sont jamais de type fixe, c'est a dire qu'il y a toujours une correspondance des + les variables du simplexe. Il faut donc ne pas mettre ces coupes. */ +NormeV = 0.0; +NbCliquesViolees = 0; + +PNE_MiseAJourSeuilCoupes( Pne, COUPE_CLIQUE, &Seuil ); + +for ( c = 0 ; c < Cliques->NombreDeCliques ; c++ ) { + if ( LaCliqueEstDansLePool[c] == OUI_PNE ) continue; + il = First[c]; + if ( il < 0 ) continue; /* On ne sait jamais ... */ + ilMax = il + NbElements[c]; + S = 0; + Sec = 1; + Ok = OUI_PNE; + while ( il < ilMax ) { + if ( NoeudDeClique[il] < Pivot ) { + if ( TypeDeBorne[NoeudDeClique[il]] == VARIABLE_FIXE ) { + Ok = NON_PNE; + break; + } + S += UTrav[NoeudDeClique[il]]; + } + else { + if ( TypeDeBorne[NoeudDeClique[il]-Pivot] == VARIABLE_FIXE ) { + Ok = NON_PNE; + break; + } + S -= UTrav[NoeudDeClique[il]-Pivot]; + Sec -= 1; + } + il++; + } + if ( Ok == OUI_PNE ) { + + if ( S - Sec > Seuil ) { + Pne->SommeViolationsCliques += S - Sec; + Pne->NombreDeCliques++; + } + + if ( S - Sec > Pne->SeuilDeViolationCliques ) { + X = fabs( S - Sec ); + NormeV += X; + /* On Stocke la coupe */ + il = First[c]; + NbT = 0; + while ( il < ilMax ) { + if ( NoeudDeClique[il] < Pivot ) { + Coeff[NbT] = 1; + Indice[NbT] = NoeudDeClique[il]; + } + else { + Coeff[NbT] = -1; + Indice[NbT] = NoeudDeClique[il] - Pivot; + } + NbT++; + il++; + } + NbCliquesViolees++; + B = Sec; + PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'K', NbT, B, X, Coeff , Indice ); + Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees-1]->IndexDansCliques = c; + if ( CliqueDeTypeEgalite[c] == OUI_PNE ) { + for ( il = 0 ; il < NbT ; il++ ) Coeff[il] *= -1; + B *= -1; + PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'K', NbT, B, X, Coeff , Indice ); + Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees-1]->IndexDansCliques = c; + /*printf("ajout clique egalite %d\n",c);*/ + } + } + } +} + +if ( NbCliquesViolees <= 0 ) ControleImplications = OUI_PNE; + +Implications: + +if ( ControleImplications != OUI_PNE ) goto FinControles; + +/* Maintenant on regarde les implications du graphe */ + +PNE_MiseAJourSeuilCoupes( Pne, COUPE_IMPLICATION, &Seuil ); + +NbImplicationsViolees = 0; +NormeV = 0.0; +ConflictGraph = Pne->ConflictGraph; +if ( ConflictGraph == NULL ) return; + +NbNoeudsDuGraphe = ConflictGraph->NbNoeudsDuGraphe; +Pivot = ConflictGraph->Pivot; +Adjacent = ConflictGraph->Adjacent; +Next = ConflictGraph->Next; +First = ConflictGraph->First; + +/* Attention: la partie simplexe considere que les variables intervenant dans les coupes ne + sont jamais de type fixe, c'est a dire qu'il y a toujours une correspondance des + les variables du simplexe. Il faut donc ne pas mettre ces coupes. */ + +for ( Noeud = 0 ; Noeud < NbNoeudsDuGraphe ; Noeud++ ) { + if ( First[Noeud] < 0 ) continue; + if ( Noeud < Pivot ) { + Var = Noeud; + Complement = Pivot + Noeud; + S0 = UTrav[Var]; + Coeff[0] = 1; + B0 = 1.; + } + else { + Var = Noeud - Pivot; + Complement = Noeud - Pivot; + S0 = -UTrav[Var]; + B0 = 0.0; + Coeff[0] = -1; + } + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) continue; + Indice[0] = Var; + NbT = 1; + + Edge = First[Noeud]; + while ( Edge >= 0 ) { + Nv = Adjacent[Edge]; + if ( Nv == Complement ) goto NextEdge; + if ( Nv < Pivot ) { + Var = Nv; + S = S0 + UTrav[Var]; + Coeff[1] = 1; + B = B0; + } + else { + Var = Nv - Pivot; + S = S0 - UTrav[Var]; + B = B0 - 1; + Coeff[1] = -1; + } + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) goto NextEdge; + Indice[1] = Var; + NbT = 2; + + if ( S - B > Seuil ) { + Pne->SommeViolationsImplications += S - B; + Pne->NombreDImplications++; + } + + if ( S - B > Pne->SeuilDeViolationCliques ) { + /* + printf("Noeud=%d Implication violee %e (%d=%e) %e (%d=%e) < %e\n", + Noeud, + Coeff[0],Indice[0],UTrav[Indice[0]], + Coeff[1],Indice[1],UTrav[Indice[1]], + B); + */ + X = S - B; + NormeV += X; + /* On Stocke la coupe */ + PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'K', NbT, B, X, Coeff , Indice ); + NbImplicationsViolees++; + } + NextEdge: + Edge = Next[Edge]; + } +} + +FinControles: +return; +} + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_clone_spx_noeud_racine.c b/src/ext/Sirius_Solver/pne/pne_clone_spx_noeud_racine.c new file mode 100644 index 0000000000..053a388786 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_clone_spx_noeud_racine.c @@ -0,0 +1,318 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Clone du simplexe du noeud racine pour utilisation ulterieure. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_constantes_externes.h" +# include "spx_definition_arguments.h" +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ +void PNE_LibererMatriceDeContraintesDuSimplexeAuNoeudRacine( MATRICE_DE_CONTRAINTES * Contraintes ) +{ +if ( Contraintes == NULL ) return; +free( Contraintes->IndexDebut ); +free( Contraintes->NombreDeTermes ); +free( Contraintes->SecondMembre ); +free( Contraintes->Sens ); +free( Contraintes->Colonne ); +free( Contraintes->Coefficient ); +free( Contraintes->X ); +free( Contraintes->CoutsReduits ); +free( Contraintes->PositionDeLaVariable ); +free( Contraintes->PositionDeLaVariableSV ); +free( Contraintes->ComplementDeLaBase ); +free( Contraintes->ComplementDeLaBaseSV ); +free( Contraintes ); +return; +} +/*----------------------------------------------------------------------------*/ + +MATRICE_DE_CONTRAINTES * PNE_ConstruireMatriceDeContraintesDuSimplexeAuNoeudRacine( PROBLEME_PNE * Pne, + int * PositionDeLaVariable, + int NbVarDeBaseComplementaires, + int * ComplementDeLaBase ) +{ +int NombreDeContraintesNatives; int NbTermesNecessaires; int * IndexDebut; int * NombreDeTermes; +int NombreDeVariablesNatives; int il; int NbTermesNatif; int Nb; int NombreDeContraintes; +int NbContraintesNecessaires; double * SecondMembre; char * Sens; int * Colonne; double * Coefficient; +int * PositionVariable; int * ComplementBase; int * PositionVariableSV; int * ComplementBaseSV; +double * X; double * CoutsReduits; int Cnt; int ilC; int ilCmax; +MATRICE_DE_CONTRAINTES * Contraintes; + +Contraintes = NULL; +/* Allocation */ +Contraintes = (MATRICE_DE_CONTRAINTES *) malloc( sizeof( MATRICE_DE_CONTRAINTES ) ); +if ( Contraintes == NULL ) return( NULL ); + +NombreDeContraintesNatives = Pne->NombreDeContraintesTrav; +NombreDeVariablesNatives = Pne->NombreDeVariablesTrav; +NbContraintesNecessaires = NombreDeContraintesNatives; +NbContraintesNecessaires += Pne->Coupes.NombreDeContraintes; + +/* Attention on suppose que les contraintes sont rangees dans l'ordre */ +NbTermesNatif = Pne->MdebTrav[NombreDeContraintesNatives-1] + Pne->NbTermTrav[NombreDeContraintesNatives-1]; +NbTermesNecessaires = NbTermesNatif; +if ( Pne->YaUneSolutionEntiere == OUI_PNE ) { + /* Pour la borne sur le cout */ + NbTermesNecessaires += NombreDeVariablesNatives; +} + +/* Les coupes */ +for ( Cnt = 0 ; Cnt < Pne->Coupes.NombreDeContraintes ; Cnt++ ) NbTermesNecessaires += Pne->Coupes.Mdeb[Cnt] + Pne->Coupes.NbTerm[Cnt]; + +IndexDebut = (int *) malloc( NbContraintesNecessaires * sizeof( int ) ); +NombreDeTermes = (int *) malloc( NbContraintesNecessaires * sizeof( int ) ); +SecondMembre = (double *) malloc( NbContraintesNecessaires * sizeof( double ) ); +Sens = (char *) malloc( NbContraintesNecessaires * sizeof( char ) ); +Colonne = (int *) malloc( NbTermesNecessaires * sizeof( int ) ); +Coefficient = (double *) malloc( NbTermesNecessaires * sizeof( double ) ); +/* Donnees complementaires */ +X = (double *) malloc( NombreDeVariablesNatives * sizeof( double ) ); +CoutsReduits = (double *) malloc( NombreDeVariablesNatives * sizeof( double ) ); +PositionVariable = (int *) malloc( NombreDeVariablesNatives * sizeof( int ) ); +PositionVariableSV = (int *) malloc( NombreDeVariablesNatives * sizeof( int ) ); +ComplementBase = (int *) malloc( NbContraintesNecessaires * sizeof( int ) ); +ComplementBaseSV = (int *) malloc( NbContraintesNecessaires * sizeof( int ) ); + +if ( IndexDebut == NULL || NombreDeTermes == NULL || SecondMembre == NULL || Sens == NULL || Colonne == NULL || Coefficient == NULL || + X == NULL || CoutsReduits == NULL || PositionVariable == NULL || ComplementBase == NULL || PositionVariableSV == NULL || ComplementBaseSV == NULL +) { + free( IndexDebut ); free( NombreDeTermes ); free( SecondMembre ); free( Sens ); free( Colonne ); free( Coefficient ); + free( X ); free( CoutsReduits ); free( PositionVariable ); free( ComplementBase ); + free( PositionVariableSV ); free( ComplementBaseSV ); + free( Contraintes ); + return( NULL ); +} + +Contraintes->IndexDebut = IndexDebut; +Contraintes->NombreDeTermes = NombreDeTermes; +Contraintes->SecondMembre = SecondMembre; +Contraintes->Sens = Sens; +Contraintes->Colonne = Colonne; +Contraintes->Coefficient = Coefficient; +Contraintes->X = X; +Contraintes->CoutsReduits = CoutsReduits; +Contraintes->PositionDeLaVariable = PositionVariable; +Contraintes->PositionDeLaVariableSV = PositionVariableSV; +Contraintes->ComplementDeLaBase = ComplementBase; +Contraintes->ComplementDeLaBaseSV = ComplementBaseSV; + +/* Recopie de la matrice des contraintes natives */ +/* Attention on suppose que les contraintes sont rangees dans l'ordre */ +memcpy( (char *) IndexDebut, (char *) Pne->MdebTrav, NombreDeContraintesNatives * sizeof( int ) ); +memcpy( (char *) NombreDeTermes, (char *) Pne->NbTermTrav, NombreDeContraintesNatives * sizeof( int ) ); +memcpy( (char *) SecondMembre, (char *) Pne->BTrav, NombreDeContraintesNatives * sizeof( double ) ); +memcpy( (char *) Sens, (char *) Pne->SensContrainteTrav, NombreDeContraintesNatives * sizeof( char ) ); +memcpy( (char *) Colonne, (char *) Pne->NuvarTrav, NbTermesNatif * sizeof( int ) ); +memcpy( (char *) Coefficient, (char *) Pne->ATrav, NbTermesNatif * sizeof( double ) ); + +memcpy( (char *) X, (char *) Pne->UTrav, NombreDeVariablesNatives * sizeof( double ) ); +memcpy( (char *) PositionVariable, (char *) PositionDeLaVariable, NombreDeVariablesNatives * sizeof( int ) ); +memcpy( (char *) ComplementBase, (char *) ComplementDeLaBase, NbVarDeBaseComplementaires * sizeof( int ) ); +Contraintes->NbVarDeBaseComplementaires = NbVarDeBaseComplementaires; + +NombreDeContraintes = NombreDeContraintesNatives; +il = NbTermesNatif; + +/* Les coupes */ +for ( Cnt = 0 ; Cnt < Pne->Coupes.NombreDeContraintes ; Cnt++ ) { + /* Si la variable d'ecart est EN_BASE, on ne recopie pas la contrainte ce qui evite de mettre a jour + ComplementBase */ + if ( Pne->Coupes.PositionDeLaVariableDEcart[Cnt] == EN_BASE ) continue; + ilC = Pne->Coupes.Mdeb[Cnt] ; + ilCmax = ilC + Pne->Coupes.NbTerm[Cnt]; + Nb = 0; + IndexDebut[NombreDeContraintes] = il; + while ( ilC < ilCmax ) { + Colonne[il] = Pne->Coupes.Nuvar[ilC]; + Coefficient[il] = Pne->Coupes.A[ilC]; + il++; Nb++; + ilC++; + } + NombreDeTermes[NombreDeContraintes] = Nb; + SecondMembre[NombreDeContraintes] = Pne->Coupes.B[Cnt]; + Sens[NombreDeContraintes] = '<'; + NombreDeContraintes++; +} + +Contraintes->NombreDeContraintes = NombreDeContraintes; + +return( Contraintes ); + +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CloneProblemeSpxDuNoeudRacine( PROBLEME_PNE * Pne, + int * PositionDeLaVariable, /* Information en Entree et Sortie */ + int * NbVarDeBaseComplementaires, /* Information en Entree et Sortie */ + int * ComplementDeLaBase /* Information en Entree et Sortie */ + ) +{ +int BaseDeDepartFournie; int Contexte; int ExistenceDUneSolution; int ChoixDeLAlgorithme; +int NombreMaxDIterations; char PremiereResolutionAuNoeudRacine; +PROBLEME_SIMPLEXE Probleme; PROBLEME_SPX * Spx; + +Pne->MatriceDesContraintesAuNoeudRacine = PNE_ConstruireMatriceDeContraintesDuSimplexeAuNoeudRacine( Pne, + PositionDeLaVariable, *NbVarDeBaseComplementaires, ComplementDeLaBase ); +if ( Pne->MatriceDesContraintesAuNoeudRacine == NULL ) return; + +PremiereResolutionAuNoeudRacine = OUI_PNE; +BaseDeDepartFournie = OUI_SPX; +ChoixDeLAlgorithme = SPX_DUAL; +Pne->ProblemeSpxDuNoeudRacine = NULL; /* Par precaution mais c'est deja fait */ + +if ( PremiereResolutionAuNoeudRacine == OUI_PNE ) { + if ( Pne->NombreDeVariablesEntieresTrav <= 0 ) { + /* Si pas de variables entieres, alors simplexe seul */ + Contexte = SIMPLEXE_SEUL; + } + else { + /* Premiere resolution du noeud racine dans le cas du branch and bound */ + Contexte = BRANCH_AND_BOUND_OU_CUT; + } +} +else { + /* Resolutions suivantes dans le cas du branch and bound */ + Contexte = BRANCH_AND_BOUND_OU_CUT_NOEUD; +} + +/* Normalement ca converge en 1 iteration */ +NombreMaxDIterations = 100; + +Probleme.Contexte = Contexte; +Probleme.NombreMaxDIterations = NombreMaxDIterations; +Probleme.DureeMaxDuCalcul = -1.; + +Probleme.CoutLineaire = Pne->LTrav; +Probleme.X = Pne->MatriceDesContraintesAuNoeudRacine->X; +Probleme.Xmin = Pne->UminTrav; +Probleme.Xmax = Pne->UmaxTrav; +Probleme.NombreDeVariables = Pne->NombreDeVariablesTrav; +Probleme.TypeDeVariable = Pne->TypeDeBorneTrav; + +Probleme.NombreDeContraintes = Pne->MatriceDesContraintesAuNoeudRacine->NombreDeContraintes; +Probleme.IndicesDebutDeLigne = Pne->MatriceDesContraintesAuNoeudRacine->IndexDebut; +Probleme.NombreDeTermesDesLignes = Pne->MatriceDesContraintesAuNoeudRacine->NombreDeTermes; +Probleme.IndicesColonnes = Pne->MatriceDesContraintesAuNoeudRacine->Colonne; +Probleme.CoefficientsDeLaMatriceDesContraintes = Pne->MatriceDesContraintesAuNoeudRacine->Coefficient; +Probleme.Sens = Pne->MatriceDesContraintesAuNoeudRacine->Sens; +Probleme.SecondMembre = Pne->MatriceDesContraintesAuNoeudRacine->SecondMembre; + +Probleme.ChoixDeLAlgorithme = ChoixDeLAlgorithme; + +Probleme.TypeDePricing = PRICING_STEEPEST_EDGE; +Probleme.FaireDuScaling = OUI_SPX; +Probleme.StrategieAntiDegenerescence = AGRESSIF; + +Probleme.BaseDeDepartFournie = BaseDeDepartFournie; +Probleme.PositionDeLaVariable = Pne->MatriceDesContraintesAuNoeudRacine->PositionDeLaVariable; +Probleme.NbVarDeBaseComplementaires = Pne->MatriceDesContraintesAuNoeudRacine->NbVarDeBaseComplementaires; +Probleme.ComplementDeLaBase = Pne->MatriceDesContraintesAuNoeudRacine->ComplementDeLaBase; + +Probleme.LibererMemoireALaFin = NON_SPX; + +Probleme.CoutMax = LINFINI_PNE; +Probleme.UtiliserCoutMax = NON_SPX; + +Probleme.NombreDeContraintesCoupes = 0; /* Car integrees dans les contraintes */ +Probleme.BCoupes = NULL; +Probleme.PositionDeLaVariableDEcartCoupes = NULL; +Probleme.MdebCoupes = NULL; +Probleme.NbTermCoupes = NULL; +Probleme.NuvarCoupes = NULL; +Probleme.ACoupes = NULL; + +Probleme.CoutsMarginauxDesContraintes = NULL; + +Probleme.CoutsReduits = NULL; + +Probleme.AffichageDesTraces = OUI_SPX /*Pne->AffichageDesTraces*/; + +Pne->ProblemeSpxDuNoeudRacine = SPX_Simplexe( &Probleme , Pne->ProblemeSpxDuNoeudRacine ); + +/* On renseigne le Simplexe pour qu'il sache qui l'appelle */ +Spx = NULL; +if ( Pne->ProblemeSpxDuNoeudRacine != NULL ) { + Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuNoeudRacine; + Spx->ProblemePneDeSpx = (void *) Pne; +} + +ExistenceDUneSolution = Probleme.ExistenceDUneSolution; + +if ( ExistenceDUneSolution == OUI_PNE ) { + /* On recupere la base optimale pour la passer aux problemes suivant comme base de depart */ + Pne->MatriceDesContraintesAuNoeudRacine->BaseDeDepartFournie = OUI_SPX; /* Pret pour les coups suivants */ + memcpy( (char *) Pne->MatriceDesContraintesAuNoeudRacine->PositionDeLaVariableSV, + (char *) Pne->MatriceDesContraintesAuNoeudRacine->PositionDeLaVariable, + Pne->NombreDeVariablesTrav * sizeof( int ) ); + + Pne->MatriceDesContraintesAuNoeudRacine->NbVarDeBaseComplementairesSV = Probleme.NbVarDeBaseComplementaires; + + memcpy( (char *) Pne->MatriceDesContraintesAuNoeudRacine->ComplementDeLaBaseSV, + (char *) Pne->MatriceDesContraintesAuNoeudRacine->ComplementDeLaBase, + Pne->MatriceDesContraintesAuNoeudRacine->NbVarDeBaseComplementairesSV * sizeof( int ) ); + + if ( Pne->AffichageDesTraces == OUI_PNE ) { + /* Mettre une trace */ + } +} +else { + if ( Pne->ProblemeSpxDuNoeudRacine != NULL ) { + SPX_LibererProbleme( (PROBLEME_SPX *) Pne->ProblemeSpxDuNoeudRacine ); + Pne->ProblemeSpxDuNoeudRacine = NULL; + } +} + +return; +} + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_compacter_matrice_des_contraintes.c b/src/ext/Sirius_Solver/pne/pne_compacter_matrice_des_contraintes.c new file mode 100644 index 0000000000..92da9c17d5 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_compacter_matrice_des_contraintes.c @@ -0,0 +1,123 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On compacte la matrice des contraintes en enlevant les + termes qui correspondent a des variables fixes ou de + borne inf et sup identiques. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_CompacterLaMatriceDesContraintes( PROBLEME_PNE * Pne ) +{ +int Cnt; double S; int il; int ilMax; int Var; int NombreDeContraintes; int NbT; +int * Mdeb; int * NbTerm; int * Nuvar; int * TypeDeBorne; char ChainageTransposeeExploitable; +double * A; double * X; double * Xmin ; double * Xmax; double * B; int * CntDeBorneSupVariable; +int * CntDeBorneInfVariable; int NombreDeVariables; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +B = Pne->BTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +X = Pne->UTrav; +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; +ChainageTransposeeExploitable = Pne->ChainageTransposeeExploitable; + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + S = 0; + il = Mdeb[Cnt]; + NbT = NbTerm[Cnt]; + ilMax = il + NbT; + while ( il < ilMax ) { + /* Pour eviter de supprimer une contrainte en entier */ + if ( NbT <= 1 ) break; + Var = Nuvar[il]; + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) { + S += A[il] * X[Var]; + Nuvar[il] = Nuvar[ilMax-1]; + A[il] = A[ilMax-1]; + il--; + ilMax--; + NbT--; + } + else if ( Xmin[Var] == Xmax[Var] ) { + S += A[il] * Xmin[Var]; + Nuvar[il] = Nuvar[ilMax-1]; + A[il] = A[ilMax-1]; + il--; + ilMax--; + NbT--; + } + else if ( A[il] == 0.0 ) { + Nuvar[il] = Nuvar[ilMax-1]; + A[il] = A[ilMax-1]; + il--; + ilMax--; + NbT--; + } + il++; + } + B[Cnt] -= S; + if ( NbT != NbTerm[Cnt] ) ChainageTransposeeExploitable = NON_PNE; + NbTerm[Cnt] = NbT; +} +Pne->ChainageTransposeeExploitable = ChainageTransposeeExploitable; + +/* On cree la transposee si besoin */ +if ( Pne->ChainageTransposeeExploitable == NON_PNE ) PNE_ConstruireLeChainageDeLaTransposee( Pne ); + +CntDeBorneSupVariable = Pne->CntDeBorneSupVariable; +CntDeBorneInfVariable = Pne->CntDeBorneInfVariable; +if ( CntDeBorneSupVariable == NULL && CntDeBorneInfVariable == NULL ) goto Fin; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( CntDeBorneSupVariable != NULL ) { + Cnt = CntDeBorneSupVariable[Var]; + if ( Cnt >= 0 ) { + if ( NbTerm[Cnt] != 2 ) CntDeBorneSupVariable[Var] = -1; + } + } + if ( CntDeBorneInfVariable != NULL ) { + Cnt = CntDeBorneInfVariable[Var]; + if ( Cnt >= 0 ) { + if ( NbTerm[Cnt] != 2 ) CntDeBorneInfVariable[Var] = -1; + } + } +} + +Fin: + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_conflict_graph_MAJ.c b/src/ext/Sirius_Solver/pne/pne_conflict_graph_MAJ.c new file mode 100644 index 0000000000..f5d0933fda --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_conflict_graph_MAJ.c @@ -0,0 +1,233 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Variable probing + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define VERBOSE_CREATION_GRAPHE NON_PNE +# define AJOUTER_COMPLEMENT 1 /* Vaut imperativement 1 */ + +/*----------------------------------------------------------------------------*/ +/* Mise a jour du conflict graph */ +void PNE_MajConflictGraph( PROBLEME_PNE * Pne, int VariableInstanciee, double ValeurDeVariableInstanciee ) +{ +int i; int VariableFixee; int * NumeroDesVariablesFixees; int Edge; int * Adjacent; +int * Next; int * First; int NbEdges; char * BorneInfConnue; char Exist; +CONFLICT_GRAPH * ConflictGraph; PROBING_OU_NODE_PRESOLVE * Prb; int Complement; +int Noeud_1; int Noeud_2; int Pivot; + +/* Attention on ne doit creer le complement que s'il n'existe pas. S'il existe il faut verifier que la liaison + egalite existe */ + +Prb = Pne->ProbingOuNodePresolve; +if ( Pne->ConflictGraph == NULL ) PNE_AllocConflictGraph( Pne ); +ConflictGraph = Pne->ConflictGraph; +if ( ConflictGraph == NULL ) return; +if ( ConflictGraph->Full == OUI_PNE ) return; + +NumeroDesVariablesFixees = Prb->NumeroDesVariablesFixees; +BorneInfConnue = Prb->BorneInfConnue; +Adjacent = ConflictGraph->Adjacent; +Next = ConflictGraph->Next; +First = ConflictGraph->First; +NbEdges = ConflictGraph->NbEdges; +Pivot = ConflictGraph->Pivot; + +# if VERBOSE_CREATION_GRAPHE == OUI_PNE + printf("Instanciation de la variable %d a %e\n",VariableInstanciee,ValeurDeVariableInstanciee); +# endif + +if ( ValeurDeVariableInstanciee == 0.0 ) { + Noeud_1 = Pivot + VariableInstanciee; + Complement = VariableInstanciee; +} +else { + Noeud_1 = VariableInstanciee; + Complement = Pivot + VariableInstanciee; +} + +/* Si on examine VariableInstanciee pour la premiere fois on cree la liaison avec son complement */ + +if ( First[Noeud_1] == -1 && AJOUTER_COMPLEMENT == 1 ) { + if ( NbEdges >= ConflictGraph->TailleAllouee ) { + PNE_ReallocConflictGraph( Pne ); + if ( ConflictGraph->Full == OUI_PNE ) { ConflictGraph->NbEdges = NbEdges; return; } + Adjacent = ConflictGraph->Adjacent; + Next = ConflictGraph->Next; + } + Adjacent[NbEdges] = Complement; + Next[NbEdges] = First[Noeud_1]; + First[Noeud_1] = NbEdges; + NbEdges++; +} +if ( First[Complement] == -1 && AJOUTER_COMPLEMENT == 1 ) { + if ( NbEdges >= ConflictGraph->TailleAllouee ) { + PNE_ReallocConflictGraph( Pne ); + if ( ConflictGraph->Full == OUI_PNE ) { ConflictGraph->NbEdges = NbEdges; return; } + Adjacent = ConflictGraph->Adjacent; + Next = ConflictGraph->Next; + } + Adjacent[NbEdges] = Noeud_1; + Next[NbEdges] = First[Complement]; + First[Complement] = NbEdges; + NbEdges++; +} + +for ( i = 0 ; i < Prb->NombreDeVariablesFixees ; i++ ) { + # if VERBOSE_CREATION_GRAPHE == OUI_PNE + printf("Variables fixee % d a %e\n",NumeroDesVariablesFixees[i],Prb->ValeurDeBorneInf[NumeroDesVariablesFixees[i]]); + # endif + /* les variables a 1 du graphe vont de 0 a Pivot-1, les variables a 0 vont de Pivot + a 2*Pivot -1 . Remarque on pourra avantageusement reduire la taille en indicant + sur les variables eniteres uniquement */ + + VariableFixee = NumeroDesVariablesFixees[i]; + if ( VariableFixee == VariableInstanciee ) continue; + + if ( BorneInfConnue[VariableFixee] == FIXATION_SUR_BORNE_SUP ) { + /* Le lien de conflit ira vers la valeur 0 */ + Noeud_2 = Pivot + VariableFixee; + Complement = VariableFixee; + } + else if ( BorneInfConnue[VariableFixee] == FIXATION_SUR_BORNE_INF ) { + /* Le lien de conflit ira vers la valeur 1 */ + Noeud_2 = VariableFixee; + Complement = Pivot + VariableFixee; + } + else { + printf("Bug dans PNE_MajConflictGraph: indicateur BorneInfConnue faux\n"); + continue; + } + + /* Si on examine VariableFixee pour la premiere fois on cree la liaison avec son complement */ + if ( First[Noeud_2] == -1 && AJOUTER_COMPLEMENT == 1 ) { + if ( NbEdges >= ConflictGraph->TailleAllouee ) { + PNE_ReallocConflictGraph( Pne ); + if ( ConflictGraph->Full == OUI_PNE ) { ConflictGraph->NbEdges = NbEdges; return; } + Adjacent = ConflictGraph->Adjacent; + Next = ConflictGraph->Next; + } + Adjacent[NbEdges] = Complement; + Next[NbEdges] = First[Noeud_2]; + First[Noeud_2] = NbEdges; + NbEdges++; + } + if ( First[Complement] == -1 && AJOUTER_COMPLEMENT == 1 ) { + if ( NbEdges >= ConflictGraph->TailleAllouee ) { + PNE_ReallocConflictGraph( Pne ); + if ( ConflictGraph->Full == OUI_PNE ) { ConflictGraph->NbEdges = NbEdges; return; } + Adjacent = ConflictGraph->Adjacent; + Next = ConflictGraph->Next; + } + Adjacent[NbEdges] = Noeud_2; + Next[NbEdges] = First[Complement]; + First[Complement] = NbEdges; + NbEdges++; + } + + /* On veut ajouter l'arc a la liste des arc de VariableInstanciee */ + /* On verifie que l'arc n'existe pas deja */ + Exist = 0; + Edge = First[Noeud_1]; + while ( Edge >= 0 ) { + /* L'arc existe deja ? */ + if ( Adjacent[Edge] == Noeud_2 ) { + /* L'arc existe deja */ + Exist = 1; + break; + } + Edge = Next[Edge]; + } + if ( Exist == 0 ) { + /* Il faut verifier s'il y a de la place */ + if ( NbEdges >= ConflictGraph->TailleAllouee ) { + PNE_ReallocConflictGraph( Pne ); + if ( ConflictGraph->Full == OUI_PNE ) { ConflictGraph->NbEdges = NbEdges; return; } + Adjacent = ConflictGraph->Adjacent; + Next = ConflictGraph->Next; + } + /* On ajoute l'arc a la liste des arc de VariableInstanciee */ + Adjacent[NbEdges] = Noeud_2; + Next[NbEdges] = First[Noeud_1]; + First[Noeud_1] = NbEdges; + NbEdges++; + } + + /* On veut ajouter l'arc a la liste des arc de VariableFixee */ + Exist = 0; + Edge = First[Noeud_2]; + while ( Edge >= 0 ) { + /* L'arc existe deja ? */ + if ( Adjacent[Edge] == Noeud_1 ) { + /* L'arc existe deja */ + Exist = 1; + break; + } + Edge = Next[Edge]; + } + if ( Exist == 0 ) { + /* Il faut verifier s'il y a de la place */ + if ( NbEdges >= ConflictGraph->TailleAllouee ) { + PNE_ReallocConflictGraph( Pne ); + if ( ConflictGraph->Full == OUI_PNE ) { ConflictGraph->NbEdges = NbEdges; return; } + Adjacent = ConflictGraph->Adjacent; + Next = ConflictGraph->Next; + } + /* On ajoute l'arc a la liste des arc de VariableFixee */ + Adjacent[NbEdges] = Noeud_1; + Next[NbEdges] = First[Noeud_2]; + First[Noeud_2] = NbEdges; + NbEdges++; + } +} +ConflictGraph->NbEdges = NbEdges; + +return; +} + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_conflict_graph_alloc.c b/src/ext/Sirius_Solver/pne/pne_conflict_graph_alloc.c new file mode 100644 index 0000000000..fdb76911c4 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_conflict_graph_alloc.c @@ -0,0 +1,118 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Variable probing + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define VERBOSE_CREATION_GRAPHE NON_PNE +# define AJOUTER_COMPLEMENT 1 /* Vaut 0 ou 1 */ + +/*----------------------------------------------------------------------------*/ +void PNE_AllocConflictGraph( PROBLEME_PNE * Pne ) +{ +int TailleAllouee_1; int TailleAllouee_2; int * First; int i; +CONFLICT_GRAPH * ConflictGraph; +Pne->ConflictGraph = (CONFLICT_GRAPH *) malloc( sizeof( CONFLICT_GRAPH ) ); +if ( Pne->ConflictGraph == NULL ) return; +ConflictGraph = Pne->ConflictGraph; + +TailleAllouee_1 = Pne->NombreDeVariablesTrav << 1; +TailleAllouee_2 = Pne->NombreDeVariablesTrav + Pne->NombreDeContraintesTrav; +ConflictGraph->First = (int *) malloc( TailleAllouee_1 * sizeof( int ) ); +if ( ConflictGraph->First == NULL ) { + free( Pne->ConflictGraph ); Pne->ConflictGraph = NULL; + return; +} +ConflictGraph->Adjacent = (int *) malloc( TailleAllouee_2 * sizeof( int ) ); +if ( ConflictGraph->Adjacent == NULL ) { + free( ConflictGraph->First ); ConflictGraph->First = NULL; + free( Pne->ConflictGraph ); Pne->ConflictGraph = NULL; + return; +} +ConflictGraph->Next = (int *) malloc( TailleAllouee_2 * sizeof( int ) ); +if ( ConflictGraph->Next == NULL ) { + free( ConflictGraph->First ); ConflictGraph->First = NULL; + free( ConflictGraph-> Adjacent); ConflictGraph->Adjacent = NULL; + free( Pne->ConflictGraph ); Pne->ConflictGraph = NULL; + return; +} +First = ConflictGraph->First; +for ( i = 0 ; i < TailleAllouee_1 ; i++ ) First[i] = -1; + +ConflictGraph->NbNoeudsDuGraphe = Pne->NombreDeVariablesTrav << 1; +ConflictGraph->Pivot = Pne->NombreDeVariablesTrav; +ConflictGraph->NbEdges = 0; +ConflictGraph->NbEdgesLast = 0; +ConflictGraph->TailleAllouee = TailleAllouee_2; +ConflictGraph->IncrementDAllocation = TailleAllouee_2; +ConflictGraph->Full = NON_PNE; +return; +} +/*----------------------------------------------------------------------------*/ +/* A revoir pour controler un peu mieux la taille */ +void PNE_ReallocConflictGraph( PROBLEME_PNE * Pne ) +{ +int * pt; CONFLICT_GRAPH * ConflictGraph; +ConflictGraph = Pne->ConflictGraph; +ConflictGraph->TailleAllouee += ConflictGraph->IncrementDAllocation; +pt = (int *) realloc( ConflictGraph->Adjacent, ConflictGraph->TailleAllouee * sizeof( int ) ); +if ( pt == NULL ) { + ConflictGraph->Full = OUI_PNE; + return; +} +ConflictGraph->Adjacent = pt; +pt = (int *) realloc( ConflictGraph->Next, ConflictGraph->TailleAllouee * sizeof( int ) ); +if ( ConflictGraph->Next == NULL ) { + ConflictGraph->Full = OUI_PNE; + return; +} +ConflictGraph->Next = pt; +return; +} + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_conflict_graph_extensions.c b/src/ext/Sirius_Solver/pne/pne_conflict_graph_extensions.c new file mode 100644 index 0000000000..71b7f8a5b0 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_conflict_graph_extensions.c @@ -0,0 +1,136 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Extensions du graphe de conflit: on ajoute des arcs et on + fixe des variables. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ +/* Extension du graphe du conflict graphe: pour chaque arc d'egalite, on cree + un arc entre les voisins des extremites de chaque arc d'egalite */ + +void PNE_ExtendConflictGraph( PROBLEME_PNE * Pne ) +{ +int Pivot; int NbNoeudsAExaminer; int Noeud; int Edge; int Complement; +int V_Complement; int ArcNoeud; int V_Noeud; int ArcV_Noeud; int NbEdges; +int * Adjacent;int * Next;int * First; char ConflictGraphExtended; +CONFLICT_GRAPH * ConflictGraph; + +if ( Pne->ConflictGraph == NULL ) return; +ConflictGraph = Pne->ConflictGraph; +if ( ConflictGraph->Full == OUI_PNE ) return; +Adjacent = ConflictGraph->Adjacent; +Next = ConflictGraph->Next; +First = ConflictGraph->First; +Pivot = ConflictGraph->Pivot; +NbNoeudsAExaminer = Pivot; + +/* Pour chaque arc d'egalite, on ajoute un arc entre les paires de noeuds dont + 1 est lie a 1 noeud de l'egalite et l'autre est lie a l'autre noeud de l'egalite */ +ExtendConflictGraph: +ConflictGraphExtended = NON_PNE; +/* Il suffit de balayer les noeuds a 1 */ +for ( Noeud = 0 ; Noeud < NbNoeudsAExaminer ; Noeud++ ) { + Complement = Pivot + Noeud; + Edge = First[Noeud]; + /* On verifie la presence du complement */ + while ( Edge >= 0 ) { + if ( Adjacent[Edge] == Complement ) goto TestFixationDeVariable; + Edge = Next[Edge]; + } + continue; + TestFixationDeVariable: + /* Il y a une egalite entre Noeud et Complement */ + /* On balaye la liste des voisins de Complement */ + Edge = First[Complement]; + while ( Edge >= 0 ) { + V_Complement = Adjacent[Edge]; + if ( V_Complement == Noeud ) goto NextEdge; + /* On cree un arc entre V_Complement et tous les adjacents de Noeud */ + ArcNoeud = First[Noeud]; + while ( ArcNoeud >= 0 ) { + V_Noeud = Adjacent[ArcNoeud]; + if ( V_Noeud == Complement || V_Noeud == V_Complement ) goto NextArcNoeud; + /* Creation d'un arc entre V_Complement et V_Noeud */ + ArcV_Noeud = First[V_Noeud]; + while ( ArcV_Noeud >= 0 ) { + if ( Adjacent[ArcV_Noeud] == V_Complement ) goto NextArcNoeud; /* L'arc existe deja */ + ArcV_Noeud = Next[ArcV_Noeud]; + } + /* V_Noeud et V_Complement ne sont pas voisins: on cree un arc */ + NbEdges = ConflictGraph->NbEdges; + if ( NbEdges + 2 >= ConflictGraph->TailleAllouee ) { + PNE_ReallocConflictGraph( Pne ); + if ( ConflictGraph->Full == OUI_PNE ) { ConflictGraph->NbEdges = NbEdges; return; } + Adjacent = ConflictGraph->Adjacent; + Next = ConflictGraph->Next; + } + /* On ajoute l'arc vers V_Complement a la liste des arc de V_Noeud */ + Adjacent[NbEdges] = V_Complement; + Next[NbEdges] = First[V_Noeud]; + First[V_Noeud] = NbEdges; + NbEdges++; + /* On ajoute l'arc vers V_Noeud a la liste des arc de V_Complement */ + Adjacent[NbEdges] = V_Noeud; + Next[NbEdges] = First[V_Complement]; + First[V_Complement] = NbEdges; + NbEdges++; + ConflictGraph->NbEdges = NbEdges; + /* MAJ de l'indicateur d'extension */ + ConflictGraphExtended = OUI_PNE; + NextArcNoeud: + ArcNoeud = Next[ArcNoeud]; + } + NextEdge: + Edge = Next[Edge]; + } +} + +if ( ConflictGraphExtended == OUI_PNE ) { + /*printf("Le graphe de conflit a ete etendu \n");*/ + goto ExtendConflictGraph; +} + +return; +} + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_conflict_graph_fixer_les_voisins_dun_noeud.c b/src/ext/Sirius_Solver/pne/pne_conflict_graph_fixer_les_voisins_dun_noeud.c new file mode 100644 index 0000000000..dba704396f --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_conflict_graph_fixer_les_voisins_dun_noeud.c @@ -0,0 +1,136 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On fixe des variables du conflict graph. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_ConflictGraphFixerLesNoeudsVoisinsDunNoeud( PROBLEME_PNE * Pne, int Noeud ) +{ +int * Adjacent; int * Next; int * First; int Edge; int Nv; int Var; double * UminTrav; +double * UmaxTrav; double * UTrav; int Pivot; int Complement; char BorneMiseAJour; +char UneVariableAEteFixee; double ValeurDeVar; + +if ( Pne->ConflictGraph == NULL ) return; + +/*printf("ConflictGraphFixerLesNoeudsVoisinsDunNoeud Noeud %d\n",Noeud);*/ + +Adjacent = Pne->ConflictGraph->Adjacent; +Next = Pne->ConflictGraph->Next; +First = Pne->ConflictGraph->First; +Pivot = Pne->ConflictGraph->Pivot; + +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; +UTrav = Pne->UTrav; + +if ( Noeud < Pivot ) { + /* C'est a valeur Max qui est imposee */ + Var = Noeud; + ValeurDeVar = UmaxTrav[Var]; + UminTrav[Var] = ValeurDeVar; + UTrav[Var] = ValeurDeVar; + UneVariableAEteFixee = FIXE_AU_DEPART; +} +else { + /* C'est a valeur Min qui est imposee */ + Var = Noeud - Pivot; + ValeurDeVar = UminTrav[Var]; + UmaxTrav[Var] = ValeurDeVar ; + UTrav[Var] = ValeurDeVar; + UneVariableAEteFixee = FIXE_AU_DEPART; +} + +BorneMiseAJour = NON_PNE; + +PNE_ProbingMajBminBmax( Pne, Var, UTrav[Var], BorneMiseAJour ); +if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + +PNE_MajIndicateursDeBornes( Pne, Pne->ProbingOuNodePresolve->ValeurDeBorneInf, Pne->ProbingOuNodePresolve->ValeurDeBorneSup, + Pne->ProbingOuNodePresolve->BorneInfConnue, Pne->ProbingOuNodePresolve->BorneSupConnue, + ValeurDeVar, Var, UneVariableAEteFixee, BorneMiseAJour ); + +if ( Noeud < Pivot ) Complement = Pivot + Noeud; +else Complement = Noeud - Pivot; +/* S'il y a des implications pour l'instanciation, on les applique */ +Edge = First[Noeud]; +while ( Edge >= 0 ) { + Nv = Adjacent[Edge]; + /* Attention a ne pas prendre le complement */ + if ( Nv == Complement ) goto NextEdge; + if ( Nv < Pivot ) { + Var = Nv; + if ( UminTrav[Var] == UmaxTrav[Var] ) goto NextEdge; + /* La valeur borne sup est interdite pour la variable */ + /* On doit donc fixer la variable a Umin et fixer les voisins de ce noeud */ + Nv = Pivot + Nv; + /* On fixe la variable correspondant a Nv */ + PNE_ConflictGraphFixerLesNoeudsVoisinsDunNoeud( Pne, Nv ); + /* On redemarre au debut de Noeud car le chainage a pu changer */ + Edge = First[Noeud]; + continue; /* Pour ne pas faire Edge = Next[Edge] */ + } + else { + /* La valeur borne inf est interdite pour la variable */ + /* On doit donc fixer la variable a Umax et fixer les voisins de ce noeud */ + Nv = Nv - Pivot; + Var = Nv; + if ( UminTrav[Var] == UmaxTrav[Var] ) goto NextEdge; + /* On fixe la variable correspondant a Nv */ + PNE_ConflictGraphFixerLesNoeudsVoisinsDunNoeud( Pne, Nv ); + Edge = First[Noeud]; + continue; /* Pour ne pas faire Edge = Next[Edge] */ + } + NextEdge: + Edge = Next[Edge]; +} +/* On elimine l'entree du noeud dans le graphe */ +PNE_ConflictGraphSupprimerUnNoeud( Noeud, First, Adjacent, Next ); + +/* On elimine l'entree du complement */ +PNE_ConflictGraphSupprimerUnNoeud( Complement, First, Adjacent, Next ); + +return; +} + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_conflict_graph_fixer_variables.c b/src/ext/Sirius_Solver/pne/pne_conflict_graph_fixer_variables.c new file mode 100644 index 0000000000..1b4f3b6a27 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_conflict_graph_fixer_variables.c @@ -0,0 +1,144 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On fixe des variables du conflict graph. + Si un noeud et son complement on un meme noeud voisin, + ce noeud voisin est fixe a la valeur de son complement. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ +/* Pour chaque arc d'egalite, si un noeud est voisin de chaque extremite de l'arc, + on peut fixer sa valeur et supprimer tous les arcs qui partent du noeud */ + +void PNE_ConflictGraphFixerVariables( PROBLEME_PNE * Pne ) +{ +int Pivot; int NbNoeudsAExaminer; int Noeud; int Edge; int Complement; int V_Noeud; +int * Adjacent;int * Next;int * First; int * T; CONFLICT_GRAPH * ConflictGraph; +double * UminTrav; double * UmaxTrav; int Var; double ValeurDeVar; + +if ( Pne->ConflictGraph == NULL ) return; +ConflictGraph = Pne->ConflictGraph; +if ( ConflictGraph->Full == OUI_PNE ) return; +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; +Adjacent = ConflictGraph->Adjacent; +Next = ConflictGraph->Next; +First = ConflictGraph->First; +Pivot = ConflictGraph->Pivot; +NbNoeudsAExaminer = Pivot; + +T = (int *) malloc( (NbNoeudsAExaminer*2) * sizeof( int ) ); +if ( T == NULL ) return; +memset( (char *) T, 0, (NbNoeudsAExaminer*2) * sizeof( int ) ); + +/* Il suffit de balayer les noeuds a 1 */ +for ( Noeud = 0 ; Noeud < NbNoeudsAExaminer ; Noeud++ ) { + Complement = Pivot + Noeud; + Edge = First[Noeud]; + /* On verifie la presence du complement */ + while ( Edge >= 0 ) { + if ( Adjacent[Edge] == Complement ) goto TestFixationDeVariable; + Edge = Next[Edge]; + } + continue; + TestFixationDeVariable: + /* Il y a une egalite entre Noeud et Complement */ + /* On marque la liste des voisins de Complement */ + Edge = First[Complement]; + while ( Edge >= 0 ) { + T[Adjacent[Edge]] = 1; + Edge = Next[Edge]; + } + T[Noeud] = 0; /* Pour ne pas prendre en compte l'arc d'egalite */ + /* On parcours la liste des voisins de Noeud. Si T = 1 alors le noeud doit etre fixe */ + Edge = First[Noeud]; + while ( Edge >= 0 ) { + V_Noeud = Adjacent[Edge]; + if ( T[V_Noeud] == 1 ) { + T[V_Noeud] = 0; /* Comme il peut y avoir changement du chainage, on ne veut pas etudier 2 fois le meme noeud */ + /*printf("Fixation du noeud %d\n",V_Noeud);*/ + /* PNE_ConflictGraphFixerLesNoeudsVoisinsDunNoeud va egalement supprimer du graphe le noeud + et son complement */ + if ( V_Noeud < Pivot ) { + /* C'est la valeur 1 qui est interdite, on fixe la variable a 0 et on en tire + les consequences pour ses voisins dans le graphe */ + Var = V_Noeud; + /*if ( UminTrav[Var] == UmaxTrav[Var] ) continue;*/ /* Pour ne pas faire Edge = Next[Edge] */ + ValeurDeVar = 0; + /* Mise a jour des indicateurs de variables a instancier a nouveau */ + PNE_ProbingMajFlagVariablesAInstancier( Pne, Var, ValeurDeVar ); + /* Cette fonction va aussi supprimer du graphe les noeuds "Pivot + V_Noeud" et "V_Noeud" */ + PNE_ConflictGraphFixerLesNoeudsVoisinsDunNoeud( Pne, Pivot + V_Noeud ); + /* On redemarre au debut de Noeud car le chainage a pu changer */ + Edge = First[Noeud]; + continue; /* Pour ne pas faire Edge = Next[Edge] */ + } + else { + /* C'est la valeur 0 qui est interdite, on fixe la variable a 1 et on en tire + les consequences pour ses voisins dans le graphe */ + Var = V_Noeud - Pivot; + /*if ( UminTrav[Var] == UmaxTrav[Var] ) continue;*/ /* Pour ne pas faire Edge = Next[Edge] */ + ValeurDeVar = 1; + /* Mise a jour des indicateurs de variables a instancier a nouveau */ + PNE_ProbingMajFlagVariablesAInstancier( Pne, Var, ValeurDeVar ); + /* Cette fonction va aussi supprimer du graphe les noeuds "V_Noeud - Pivot" et "V_Noeud" */ + PNE_ConflictGraphFixerLesNoeudsVoisinsDunNoeud( Pne, V_Noeud - Pivot ); + /* On redemarre au debut de Noeud car le chainage a pu changer */ + Edge = First[Noeud]; + continue; /* Pour ne pas faire Edge = Next[Edge] */ + } + } + /*NextEdge:*/ + Edge = Next[Edge]; + } + Edge = First[Complement]; + while ( Edge >= 0 ) { + T[Adjacent[Edge]] = 0; + Edge = Next[Edge]; + } +} + +free( T ); +return; +} + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_conflict_graph_supprimer_un_noeud.c b/src/ext/Sirius_Solver/pne/pne_conflict_graph_supprimer_un_noeud.c new file mode 100644 index 0000000000..864e6cad26 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_conflict_graph_supprimer_un_noeud.c @@ -0,0 +1,91 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Suppression d'un noeud dans le conflict graph. + On ne recupere pas la place car trop couteux en temps + de calcul. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ +/* Suppression de l'arc partant de Nv vers Noeud */ +void PNE_ConflictGraphSupprimerUnArc( int Nv, int Noeud, int * First, int * Adjacent, int * Next ) +{ +int PreviousEdge; int Edge; char Found; +Found = NON_PNE; +PreviousEdge = -1; +Edge = First[Nv]; +while ( Edge >= 0 ) { + if ( Adjacent[Edge] == Noeud ) { + if ( PreviousEdge >= 0 ) Next[PreviousEdge] = Next[Edge]; + else First[Nv] = Next[Edge]; + Found = OUI_PNE; + break; + } + PreviousEdge = Edge; + Edge = Next[Edge]; +} +if ( Found == NON_PNE ) { + printf("BUG arc partant du noeud %d vers le noeud %d pas trouve\n",Nv,Noeud); + exit(0); +} +return; +} + +/*----------------------------------------------------------------------------*/ +/* Pour chaque arc d'egalite, si un noeud est voisin de chaque extremite de l'arc, + on peut fixer sa valeur et supprimer tous les arcs qui partent du noeud */ + +void PNE_ConflictGraphSupprimerUnNoeud( int Noeud, int * First, int * Adjacent, int * Next ) +{ +int Edge; int Nv; +/*printf("Suppression noeud %d\n",Noeud);*/ +Edge = First[Noeud]; +while ( Edge >= 0 ) { + Nv = Adjacent[Edge]; + PNE_ConflictGraphSupprimerUnArc( Nv, Noeud, First, Adjacent, Next ); + Edge = Next[Edge]; +} +First[Noeud] = -1; +return; +} + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_constantes_externes.h b/src/ext/Sirius_Solver/pne/pne_constantes_externes.h new file mode 100644 index 0000000000..d3c811b230 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_constantes_externes.h @@ -0,0 +1,52 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef CONSTANTES_EXTERNES_PNE_DEJA_DEFINIES +/*******************************************************************************************/ +/* Coix de l'algorithme */ +# define SIMPLEXE 2 +# define POINT_INTERIEUR 1 + +/* Les codes de sorties retournes par le solveur: */ +# define PAS_DE_SOLUTION_TROUVEE 0 +# define SOLUTION_OPTIMALE_TROUVEE 1 +# define SOLUTION_OPTIMALE_TROUVEE_MAIS_QUELQUES_CONTRAINTES_SONT_VIOLEES 2 +# define PROBLEME_INFAISABLE 3 +# define PROBLEME_NON_BORNE 4 +# define ARRET_PAR_LIMITE_DE_TEMPS_AVEC_SOLUTION_ADMISSIBLE_DISPONIBLE 5 +# define ARRET_CAR_ERREUR_INTERNE 6 + +/* Constantes symboliques du OUI et du NON */ +# define OUI_PNE 1 +# define NON_PNE 0 + +/* Type de bornes sur les variables fournies en entree */ +# define VARIABLE_FIXE 1 +# define VARIABLE_BORNEE_DES_DEUX_COTES 2 +# define VARIABLE_BORNEE_INFERIEUREMENT 3 +# define VARIABLE_BORNEE_SUPERIEUREMENT 4 +# define VARIABLE_NON_BORNEE 5 + +# define REEL 1 +# define ENTIER 2 /* Uniquement variables 0 1 pour l'instant */ + +# define LINFINI_PNE 1.e+75 + +/*******************************************************************************************/ +# define CONSTANTES_EXTERNES_PNE_DEJA_DEFINIES +# endif + + diff --git a/src/ext/Sirius_Solver/pne/pne_constantes_internes.h b/src/ext/Sirius_Solver/pne/pne_constantes_internes.h new file mode 100644 index 0000000000..df6d691196 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_constantes_internes.h @@ -0,0 +1,208 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef CONSTANTES_INTERNES_PNE_DEJA_DEFINIES +/*******************************************************************************************/ + +# define VERBOSE_PNE 0 +# define DEBUG_PNE 0 + +# define PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE +# undef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + +# define MODE_PNE 1 +# define MODE_PRESOLVE 2 + +# define MPCC_DANS_PI NON_PNE + +# define VALEUR_NON_INITIALISEE 1.e+75 + +# define TOLERANCE_SUR_LES_ENTIERS 1.e-6 + +# define ZERO_PRESOLVE 1.e-12 /* Valeur du ZERO pour le Presolve */ +# define ZERO_VARFIXE 1.e-8 +# define ZERO_COUT_REDUIT 1.e-8 + +# define VALEUR_DE_FRACTIONNALITE_NULLE 1.e-8 + +# define SEUIL_DADMISSIBILITE 1.e-6 /* Tolerance sur la satifaction des contraintes */ + +# define INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_VARIABLES_PNE 256 /* 256 variables */ +# define INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_CONTRAINTES_PNE 256 /* 256 contraintes */ +# define INCREMENT_DALLOCATION_POUR_LA_MATRICE_DES_CONTRAINTES_PNE 4096 /* 4096 termes */ + +# define STRONG_BRANCHING_NON_DEFINI 0 +# define STRONG_BRANCHING_MXITER_OU_REFACT 1 +# define STRONG_BRANCHING_REFACTORISATION 2 +# define STRONG_BRANCHING_OPTIMALITE 3 +# define STRONG_BRANCHING_COUT_MAX_DEPASSE 4 +# define STRONG_BRANCHING_PAS_DE_SOLUTION 5 + +# define PENTE_DE_LA_VARIATION 1 +# define VALEUR_ABSOLUE_DE_LA_VARIATION 2 + +# define PLAGE_REDUCED_COST_FIXING 1.e+15 +# define REDUCED_COST_FIXING_QUE_SUR_VARIABLES_ENTIERES OUI_PNE /*OUI_PNE*/ + +# define SIMULATION 1 +# define CALCUL 2 + +# define IMPOSSIBLE 0 +# define INF_POSSIBLE 1 +# define SUP_POSSIBLE 2 +# define INF_ET_SUP_POSSIBLE 3 + +# define SEUIL_EVITEMENT_MIR_MARCHAND_WOLSEY 15 +# define NB_ECHECS_INHIB_MIR 3 + +# define NB_TERMES_FORCE_CALCUL_DE_K 200 +# define SEUIL_VARIABLE_DUALE_POUR_CALCUL_DE_COUPE 1.e-6 + +/* Constantes pour les coupes de Gomory: on se base sur une etude de Cornuejols Margot et Nannicini: + On the Safety of Gomory cut generators */ +# define NORMALISER_LES_COUPES_SUR_LES_G_ET_I NON_PNE /*NON_PNE*/ +# define SEUIL_POUR_NORMALISER_LES_COUPES_SUR_LES_G_ET_I 1.e-6 /*1.e-6*/ +/* Valeurs utilisees dans le simplexe */ +# define RAPPORT_MAX_COEFF_COUPE_GOMORY 1.e+6 /*1.e+6*/ +# define RAPPORT_MAX_COEFF_COUPE_INTERSECTION 1.e+6 /*1.e+6*/ +# define ZERO_POUR_COEFF_VARIABLE_DECART_DANS_COUPE_GOMORY_OU_INTERSECTION 1.e-13 /*13*/ +# define ZERO_POUR_COEFF_VARIABLE_NATIVE_DANS_COUPE_GOMORY_OU_INTERSECTION 1.e-11 /*11*/ +# define RELAX_RHS_GOMORY_ABS 0.e-9 /*0.e-9*/ +# define RELAX_RHS_GOMORY_REL 0.e-10 /*0.e-10*/ +# define RELAX_RHS_INTERSECTION_ABS 1.e-7 /*1.e-8*/ /******************************************/ +# define RELAX_RHS_INTERSECTION_REL 1.e-8 /*1.e-9*/ /******************************************/ + +# define SEUIL_FRACTIONNALITE_POUR_FAIRE_UNE_COUPE_DE_GOMORY 1.e-4 /*1.e-4*/ +# define SEUIL_FRACTIONNALITE_POUR_COUPE_INTERSECTION 1.e-4 /*1.e-4*/ + +# define CALCULER_COUPES_DE_GOMORY OUI_PNE +# define CALCULER_COUPES_DINTERSECTION OUI_PNE /* On ne peut pas calculer de coupes d'intersection sans les gomory */ +# define CALCULER_COUPES_KNAPSACK_SIMPLE OUI_PNE +# define CALCULER_MIR_MARCHAND_WOLSEY OUI_PNE +# define UTILISER_LE_GRAPHE_DE_CONFLITS OUI_PNE /*OUI_PNE*/ +# define FAIRE_DU_NODE_PRESOLVE OUI_PNE +# define REDUCED_COST_FIXING_AU_NOEUD_RACINE OUI_PNE +# define REDUCED_COST_FIXING_AUX_NOEUD_DANS_ARBRE OUI_PNE +# define RELANCE_PERIODIQUE_DU_SIMPLEXE_AU_NOEUD_RACINE NON_PNE /* Necessite une mise au point complementaire */ +# define UTILISER_LES_COUPES_DE_PROBING OUI_PNE +# define CONSTRUIRE_BORNES_VARIABLES OUI_PNE /* Contraintes de bornes variable qui decoulent du variable probing */ + +# define UTILISER_UNE_CONTRAINTE_DE_COUT_MAX NON_PNE /* Pour eviter de recalculer le cout de la solution dans le simplexe et la comparer + au cout de la meilleure solution pour eventuellement arreter les iteration */ + +# define SEUIL_VIOLATION_COUPE_DE_GOMORY 1.e-6 /*1.e-6*/ +# define SEUIL_VIOLATION_COUPE_DINTERSECTION 1.e-5 /*1.e-4*/ +# define SEUIL_VIOLATION_KNAPSACK 1.e-3 /*1.e-6*/ /**************************/ +# define SEUIL_VIOLATION_MIR_MARCHAND_WOLSEY 1.e-2 /*1.e-6*/ /*1.e-5*/ /**************************/ +# define SEUIL_VIOLATION_CLIQUES 1.e-3 /*SEUIL_DADMISSIBILITE*/ +# define SEUIL_VIOLATION_IMPLICATIONS 1.e-3 /*SEUIL_DADMISSIBILITE*/ +# define SEUIL_VIOLATION_COUPES_DE_PROBING 1.e-1 /* On met un seuil eleve car il y a generalement beaucoup de coupes de probing */ +# define SEUIL_VIOLATION_BORNES_VARIABLES 1.e-2 + +# define COUPE_KNAPSACK 1 +# define COUPE_MIR_MARCHAND_WOLSEY 2 +# define COUPE_CLIQUE 3 +# define COUPE_IMPLICATION 4 +# define COUPE_DE_BORNE_VARIABLE 5 + +# define UTILISER_LE_GRAPHE_DE_CONFLITS_DANS_REDUCED_COST_FIXING_AU_NOEUD_RACINE NON_PNE /*NON_PNE*/ +# define UTILISER_LE_GRAPHE_DE_CONFLITS_DANS_REDUCED_COST_FIXING NON_PNE /*NON_PNE*/ + +# define UTILISER_LES_GUB OUI_PNE +# define MIN_TERMES_GUB 4 +# define MAX_TERMES_GUB 10 /* 10 */ +# define PROFONDEUR_LIMITE_POUR_UTILISATION_DES_GUB 100000 /*10*/ + +# define VIOLATION_MIN_POUR_K_SUR_COUPE 1.e-2 /* 1.e-2 */ +# define KNAPSACK_SUR_GOMORY OUI_PNE /*OUI_PNE*/ /* Experimentalement le K sur Gomory sont interesantes mais dans certains cas */ + /* cela pose des problemes numeriques: en particulier c'est incompatible avec + l'option UTILISER_UNE_CONTRAINTE_DE_COUT_MAX car cette contrainte peut etre tres + pleine si beaucoup de variables ont un cout non nul */ +# define KNAPSACK_SUR_COUPE_DINTERSECTION NON_PNE /*NON_PNE*/ + +# define KNAPSACK_SUR_COMBINAISONS_DE_CONTRAINTES NON_PNE /*NON_PNE*/ + +# define CALCULS_SUR_MIXED_0_1_KNAPSACK NON_PNE + +# define KNAPSACK_SUR_CONTRAINTES_DEGALITE NON_PNE /*NON_PNE*/ + +# define MIN_TERMES_POUR_KNAPSACK 3 +# define MAX_TERMES_POUR_KNAPSACK 10000 /* Il faut limiter car si la contrainte a trop de termes + la recherche des K est trop longue */ +# define MAX_TERMES_POUR_KNAPSACK_COMBINEES 10000 /* Il faut limiter car si la contrainte a trop de termes + la recherche des K est trop longue */ +# define SEUIL_POUR_PROGRAMMATION_DYNAMIQUE 256 /* Pour le calcul de Knapsack */ +/* Malgre beaucoup de test on n'a pas vu de cas ou la programmation dynamique faisait mieux */ +# define UTILISER_AUSSI_LA_PROGRAMMATION_DYNAMIQUE NON_PNE /* Pour le calcul de Knapsack */ +# define COEFFS_ENTIERS_DANS_KNAPSACK NON_PNE +# define DECROISSANT 1 +# define CROISSANT 2 + +# define DUMALGE_MENDELSON_PNE NON_PNE + +# define PNE_ACTIVATION_SUPPRESSION_PETITS_TERMES NON_PNE /*OUI_PNE*/ + +/************************************************************************/ +/* Pour les heuristiques */ + +# define CYCLE_HEURISTIQUES 3 +# define NB_MAX_ECHECS_SUCCESSIFS_HEURISTIQUE 3 +# define NB_MAX_REFUS_SUCCESSIFS 2 +# define NB_MAX_REACTIVATION_SANS_SUCCES 3 /* Quand on depasse ce seuil sans trouver de solution on arrete l'heuristique */ + +# define UTILISER_LES_COUPES NON_PNE + + +/************************************************************************/ +/* Pour la reduction des coeff des variables entieres */ +# define EPS_COEFF_REDUCTION 1.e-3 +# define DELTA_MIN_REDUCTION 1.e-1 +# define MARGE_REDUCTION 1.e-3 /*1.e-3*/ +# define NB_ITER_MX_REDUCTION 5 + +/************************************************************************/ +/* Pour le node presolve et le probing */ + +# define PROBING_JUSTE_APRES_LE_PRESOLVE OUI_PNE + +# define FIXE_AU_DEPART 10 +# define FIXATION_SUR_BORNE_INF 11 +# define FIXATION_SUR_BORNE_SUP 12 +# define FIXATION_A_UNE_VALEUR 13 +# define PROFONDEUR_MIN_POUR_NODE_PRESOLVE 2 /* 10 */ +# define CYCLE_NODE_PRESOLVE 1 +# define PRESOLVE_SIMPLIFIE_POUR_NODE_PRESOLVE 1 +# define PRESOLVE_SIMPLIFIE_POUR_REDUCED_COST_FIXING_AU_NOEUD_RACINE 2 + +# define MODIF_BORNE_INF 1 +# define MODIF_BORNE_SUP 2 + +# define MARGE_INITIALE 1.e-6 +# define ZERO_NP_PROB 1.e-8 /* 1.e-7 */ +/************************************************************************/ + +# define MARGE_EN_FIN_DE_CONTRAINTE 5 /*5*/ /* Nombre de termes qu'on peut ajouter a chaque contrainte */ + +/*******************************************************************************************/ +# define CONSTANTES_INTERNES_PNE_DEJA_DEFINIES +# endif +# ifdef __cplusplus + } +# endif diff --git a/src/ext/Sirius_Solver/pne/pne_contraintes_de_borne_variable_violees.c b/src/ext/Sirius_Solver/pne/pne_contraintes_de_borne_variable_violees.c new file mode 100644 index 0000000000..959a338768 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_contraintes_de_borne_variable_violees.c @@ -0,0 +1,210 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Detection des contraintes de borne variable de probing violees. + Les contraintes de borne variable sont crees a la creation du conflict graph. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define PROFONDEUR_LIMITE_CONTRAINTES_DE_BORNE_VARIABLE 1000000 /*10*/ +# define MAX_COUPES_DE_BORNE_VARIABLE 1000 + +# define TESTER_LE_CONDITIONNEMENT OUI_PNE +# define RAPPORT_MAX 1.e+4 + +# define TRACES NON_PNE + +# if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + +/*----------------------------------------------------------------------------*/ + +void PNE_DetectionDesContraintesDeBorneVariableViolees( PROBLEME_PNE * Pne ) +{ +double S; int Cnt; double E; int * First; int NbV; double NormeV; int il; int ilMax; double * Coeff; +int * Indice; double B; int NbT; double * X; int * Colonne; double * SecondMembre; int * TypeDeBorne; +BB * Bb; double * Coefficient; char * LaContrainteDeBorneVariableEstDansLePool; +CONTRAITES_DE_BORNE_VARIABLE * ContraintesDeBorneVariable; int NombreDeContraintesDeBorne; double Seuil; +# if TESTER_LE_CONDITIONNEMENT == OUI_PNE + PROBLEME_SPX * Spx; double PlusPetitTermeDeLaMatrice; double PlusGrandTermeDeLaMatrice; + double * ScaleX; int * CorrespondanceVarEntreeVarSimplexe; int VarSpx; double ValeurMin; + double ValeurMax; double RapportDeScaling; double Valeur; double RapportCoupe; +# endif + +# if UTILISER_LE_GRAPHE_DE_CONFLITS == OUI_PNE + # if PROBING_JUSTE_APRES_LE_PRESOLVE == NON_PNE + return; + # endif +# endif + +if ( Pne->ContraintesDeBorneVariable == NULL ) return; + +Bb = Pne->ProblemeBbDuSolveur; +if ( Bb->NoeudEnExamen->ProfondeurDuNoeud > PROFONDEUR_LIMITE_CONTRAINTES_DE_BORNE_VARIABLE ) return; + +# if TESTER_LE_CONDITIONNEMENT == OUI_PNE + Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur; + if ( Spx == NULL ) return; + CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; + PlusPetitTermeDeLaMatrice = Spx->PlusPetitTermeDeLaMatrice; + PlusGrandTermeDeLaMatrice = Spx->PlusGrandTermeDeLaMatrice; + ScaleX = Spx->ScaleX; + RapportDeScaling = Spx->RapportDeScaling; + if ( RapportDeScaling < RAPPORT_MAX ) RapportDeScaling = RAPPORT_MAX; +# endif + +ContraintesDeBorneVariable = Pne->ContraintesDeBorneVariable; + +PNE_MiseAJourSeuilCoupes( Pne, COUPE_DE_BORNE_VARIABLE, &Seuil ); + +TypeDeBorne = Pne->TypeDeBorneTrav; +X = Pne->UTrav; +Coeff = Pne->Coefficient_CG; +Indice = Pne->IndiceDeLaVariable_CG; + +First = ContraintesDeBorneVariable->First; +LaContrainteDeBorneVariableEstDansLePool = ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool; +SecondMembre = ContraintesDeBorneVariable->SecondMembre; +Colonne = ContraintesDeBorneVariable->Colonne; +Coefficient = ContraintesDeBorneVariable->Coefficient; + +/* Attention: la partie simplexe considere que les variables intervenant dans les coupes ne + sont jamais de type fixe, c'est a dire qu'il y a toujours une correspondance des + les variables du simplexe. Il faut donc ne pas mettre ces coupes. */ + +NbV = 0; +NormeV = 0.0; +NombreDeContraintesDeBorne = ContraintesDeBorneVariable->NombreDeContraintesDeBorne; + +for ( Cnt = 0 ; Cnt < NombreDeContraintesDeBorne ; Cnt++ ) { + if ( NbV >= MAX_COUPES_DE_BORNE_VARIABLE ) break; + if ( LaContrainteDeBorneVariableEstDansLePool[Cnt] == OUI_PNE ) continue; + if ( First[Cnt] < 0 ) continue; + il = First[Cnt]; + ilMax = il + 2; + S = 0; + NbT = 0; + B = SecondMembre[Cnt]; + # if TESTER_LE_CONDITIONNEMENT == OUI_PNE + ValeurMin = LINFINI_PNE; + ValeurMax = -LINFINI_PNE; + # endif + while ( il < ilMax ) { + if ( TypeDeBorne[Colonne[il]] != VARIABLE_FIXE ) { + /* Car sinon il n'y a pas de variable correspondante dans le simplexe */ + /* Test de conditionnement */ + # if TESTER_LE_CONDITIONNEMENT == OUI_PNE + VarSpx = CorrespondanceVarEntreeVarSimplexe[Colonne[il]]; + if ( VarSpx < 0 ) { + NbT = 0; + break; + } + Valeur = fabs( Coefficient[il] * ScaleX[VarSpx] ); + if ( Valeur > ValeurMax ) ValeurMax = Valeur; + if ( Valeur < ValeurMin ) ValeurMin = Valeur; + # endif + /* */ + S += Coefficient[il] * X[Colonne[il]]; + Coeff[NbT] = Coefficient[il]; + Indice[NbT] = Colonne[il]; + NbT++; + } + else { + NbT = 0; /* Pour qu'elle ne soit pas violee */ + break; + } + il++; + } + if ( NbT != 2 ) continue; + + if ( S - B > Seuil ) { + Pne->SommeViolationsBornesVariables += S - B; + Pne->NombreDeBornesVariables++; + } + + if ( S - B > Pne->SeuilDeViolationBornesVariables ) { + E = S - B; + + # if TESTER_LE_CONDITIONNEMENT == OUI_PNE + RapportCoupe = ValeurMax / ValeurMin; + if ( RapportCoupe > RapportDeScaling ) continue; + RapportCoupe = 1.; + # ifdef ON_COMPILE + if ( ValeurMax > PlusGrandTermeDeLaMatrice ) { + /* On fait une homothetie vers PlusGrandTermeDeLaMatrice */ + RapportCoupe = PlusGrandTermeDeLaMatrice / ValeurMax; + } + else if ( ValeurMin < PlusPetitTermeDeLaMatrice ) { + /* On fait une homothetie vers PlusPetitTermeDeLaMatrice */ + RapportCoupe = PlusPetitTermeDeLaMatrice / ValeurMin; + } + # endif + + if ( ValeurMax > PlusGrandTermeDeLaMatrice ) { + /* On fait une homothetie vers PlusGrandTermeDeLaMatrice */ + RapportCoupe = PlusGrandTermeDeLaMatrice / ValeurMax; + } + + if ( RapportCoupe != 1. ) { + /*SPX_ArrondiEnPuissanceDe2( &RapportCoupe );*/ + for ( NbT = 0 ; NbT < 2 ; NbT++ ) Coeff[NbT] *= RapportCoupe; + B *= RapportCoupe; + } + # endif + + NormeV += E; + /* On Stocke la coupe */ + NbV++; + # if TRACES == OUI_PNE + printf("Ajout de la contrainte de borne variable %d : \n",Cnt); + printf("valeur des variables: var. continue %e (%d) var. binaire %e (%d)\n",X[Indice[0]],Indice[0],X[Indice[1]],Indice[1]); + printf("%e (%d) + %e (%d) < %e violation: %e\n",Coeff[0],Indice[0],Coeff[1],Indice[1],B,E); + # endif + PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'K', NbT, B, E, Coeff, Indice ); + Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees-1]->IndexDansContraintesDeBorneVariable = Cnt; + } +} + +if ( Pne->AffichageDesTraces == OUI_PNE && NbV > 0 ) { + /* + printf("Adding %d variable bound constraint violated by %e\n",NbV,NormeV); + fflush( stdout ); + */ +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +# endif diff --git a/src/ext/Sirius_Solver/pne/pne_coupe_de_probing.c b/src/ext/Sirius_Solver/pne/pne_coupe_de_probing.c new file mode 100644 index 0000000000..4ca58f22da --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_coupe_de_probing.c @@ -0,0 +1,474 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Creation des coupes de probing. Une coupe est cree lorsque + l'instanciation d'une variable rend une contrainte toujours + satisfaite. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 0 + +# define CONTRAINTE_NATIVE 1 +# define COUPE_DE_PROBING 2 + +# define RMAX 1.e+5 +# define ZERO_NOUVEAU_COEFF 1.e-15 + +# define SIZE_ALLOC_COUPES 100 /* Nombre de coupes de probing allouees */ +# define SIZE_ALLOC_TERMES_COUPES (SIZE_ALLOC_COUPES*25) + +void PNE_AllocCoupesDeProbing( PROBLEME_PNE * ); +void PNE_AugmenterNombreDeCoupesDeProbing( PROBLEME_PNE * ); +void PNE_AugmenterLaTailleDesCoupesDeProbing( PROBLEME_PNE * ); + +/*----------------------------------------------------------------------------*/ + +void PNE_AllocCoupesDeProbing( PROBLEME_PNE * Pne ) +{ +COUPES_DE_PROBING * CoupesDeProbing; + +CoupesDeProbing = (COUPES_DE_PROBING *) malloc( sizeof( COUPES_DE_PROBING ) ); +if ( CoupesDeProbing == NULL ) return; + +CoupesDeProbing->SecondMembre = (double *) malloc( SIZE_ALLOC_COUPES * sizeof( double ) ); +if ( CoupesDeProbing->SecondMembre == NULL ) { + return; +} +CoupesDeProbing->LaCoupDeProbingEstDansLePool = (char *) malloc( SIZE_ALLOC_COUPES * sizeof( char ) ); +if ( CoupesDeProbing->LaCoupDeProbingEstDansLePool == NULL ) { + free( CoupesDeProbing->SecondMembre ); + return; +} +CoupesDeProbing->First = (int *) malloc( SIZE_ALLOC_COUPES * sizeof( int ) ); +if ( CoupesDeProbing->First == NULL ) { + free( CoupesDeProbing->SecondMembre ); + free( CoupesDeProbing->LaCoupDeProbingEstDansLePool ); + return; +} +CoupesDeProbing->NbElements = (int *) malloc( SIZE_ALLOC_COUPES * sizeof( int ) ); +if ( CoupesDeProbing->NbElements == NULL ) { + free( CoupesDeProbing->SecondMembre ); + free( CoupesDeProbing->LaCoupDeProbingEstDansLePool ); + free( CoupesDeProbing->First ); + return; +} +CoupesDeProbing->NombreDeCoupesDeProbingAlloue = SIZE_ALLOC_COUPES; + +CoupesDeProbing->Colonne = (int *) malloc( SIZE_ALLOC_TERMES_COUPES * sizeof( int ) ); +if ( CoupesDeProbing->Colonne == NULL ) { + free( CoupesDeProbing->SecondMembre ); + free( CoupesDeProbing->LaCoupDeProbingEstDansLePool ); + free( CoupesDeProbing->First ); + free( CoupesDeProbing->NbElements ); + return; +} +CoupesDeProbing->Coefficient = (double *) malloc( SIZE_ALLOC_TERMES_COUPES * sizeof( double ) ); +if ( CoupesDeProbing->Coefficient == NULL ) { + free( CoupesDeProbing->SecondMembre ); + free( CoupesDeProbing->LaCoupDeProbingEstDansLePool ); + free( CoupesDeProbing->First ); + free( CoupesDeProbing->NbElements ); + free( CoupesDeProbing->Colonne ); + return; +} +CoupesDeProbing->TailleCoupesDeProbingAllouee = SIZE_ALLOC_TERMES_COUPES; + +CoupesDeProbing->IndexLibre = 0; +CoupesDeProbing->NombreDeCoupesDeProbing = 0; +CoupesDeProbing->Full = NON_PNE; +Pne->CoupesDeProbing = CoupesDeProbing; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AugmenterNombreDeCoupesDeProbing( PROBLEME_PNE * Pne ) +{ +COUPES_DE_PROBING * CoupesDeProbing; int Size; double * SecondMembre; char * LaCoupDeProbingEstDansLePool; +int * First; int * NbElements; + +CoupesDeProbing = Pne->CoupesDeProbing; +Size = CoupesDeProbing->NombreDeCoupesDeProbingAlloue + SIZE_ALLOC_COUPES; + +SecondMembre = (double *) realloc( CoupesDeProbing->SecondMembre, Size * sizeof( double ) ); +if ( SecondMembre == NULL ) { + CoupesDeProbing->Full = OUI_PNE; + return; +} +LaCoupDeProbingEstDansLePool = (char *) realloc( CoupesDeProbing->LaCoupDeProbingEstDansLePool, Size * sizeof( char ) ); +if ( LaCoupDeProbingEstDansLePool == NULL ) { + free( SecondMembre ); + CoupesDeProbing->Full = OUI_PNE; + return; +} +First = (int *) realloc( CoupesDeProbing->First, Size * sizeof( int ) ); +if ( First == NULL ) { + free( SecondMembre ); + free( LaCoupDeProbingEstDansLePool ); + CoupesDeProbing->Full = OUI_PNE; + return; +} +NbElements = (int *) realloc( CoupesDeProbing->NbElements, Size * sizeof( int ) ); +if ( NbElements == NULL ) { + free( SecondMembre ); + free( LaCoupDeProbingEstDansLePool ); + free( First ); + CoupesDeProbing->Full = OUI_PNE; + return; +} +CoupesDeProbing->NombreDeCoupesDeProbingAlloue = Size; +CoupesDeProbing->SecondMembre = SecondMembre; +CoupesDeProbing->LaCoupDeProbingEstDansLePool = LaCoupDeProbingEstDansLePool; +CoupesDeProbing->First = First; +CoupesDeProbing->NbElements = NbElements; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AugmenterLaTailleDesCoupesDeProbing( PROBLEME_PNE * Pne ) +{ +COUPES_DE_PROBING * CoupesDeProbing; int Size; int * Colonne; double * Coefficient; + +CoupesDeProbing = Pne->CoupesDeProbing; +Size = CoupesDeProbing->TailleCoupesDeProbingAllouee + SIZE_ALLOC_TERMES_COUPES; + +Colonne = (int *) realloc( CoupesDeProbing->Colonne, Size * sizeof( int ) ); +if ( Colonne == NULL ) { + CoupesDeProbing->Full = OUI_PNE; + return; +} +Coefficient = (double *) realloc( CoupesDeProbing->Coefficient, Size * sizeof( double ) ); +if ( Coefficient == NULL ) { + free( Colonne ); + CoupesDeProbing->Full = OUI_PNE; + return; +} +CoupesDeProbing->TailleCoupesDeProbingAllouee = Size; +CoupesDeProbing->Colonne = Colonne; +CoupesDeProbing->Coefficient = Coefficient; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CreerUneCoupeDeProbing( PROBLEME_PNE * Pne, int Var1, double CoeffDeVar1, int ContrainteSource, + char TypeContrainteSource, int ContrainteNative, double ValeurDeVar1 ) +{ +COUPES_DE_PROBING * CoupesDeProbing; int il; int NombreDeCoupesDeProbing; +int Nb; int * First; int * NbElements; int * Colonne; int * Mdeb; int * NbTerm; +int * Nuvar; double * Coefficient; double * A; int il1; int ilMax; double Amin; +int ilVar1; double CoeffTest; int NbTrm; double Sec; + +CoupesDeProbing = Pne->CoupesDeProbing; +if ( CoupesDeProbing == NULL ) { + PNE_AllocCoupesDeProbing( Pne ); + CoupesDeProbing = Pne->CoupesDeProbing; + if ( CoupesDeProbing == NULL ) return; /* Saturation memoire */ +} + +NombreDeCoupesDeProbing = CoupesDeProbing->NombreDeCoupesDeProbing; +First = CoupesDeProbing->First; +NbElements = CoupesDeProbing->NbElements; +Coefficient = CoupesDeProbing->Coefficient; +Colonne = CoupesDeProbing->Colonne; + +/* Place suffisante */ +if ( NombreDeCoupesDeProbing >= CoupesDeProbing->NombreDeCoupesDeProbingAlloue ) { + /* On augmente la taille */ + PNE_AugmenterNombreDeCoupesDeProbing( Pne ); + if ( Pne->CoupesDeProbing == NULL ) return; + if ( CoupesDeProbing->Full == OUI_PNE ) return; + First = CoupesDeProbing->First; + NbElements = CoupesDeProbing->NbElements; +} + +if ( TypeContrainteSource == CONTRAINTE_NATIVE ) NbTerm = Pne->NbTermTrav; +else if ( TypeContrainteSource == COUPE_DE_PROBING ) NbTerm = CoupesDeProbing->NbElements; +else return; + +NbTrm = NbTerm[ContrainteSource]; +/* Place suffisante */ +il1 = CoupesDeProbing->IndexLibre; +while ( il1 + NbTrm + 1 >= CoupesDeProbing->TailleCoupesDeProbingAllouee ) { + /* On augmente la taille */ + PNE_AugmenterLaTailleDesCoupesDeProbing( Pne ); + if ( Pne->CoupesDeProbing == NULL ) return; + if ( CoupesDeProbing->Full == OUI_PNE ) return; + Coefficient = CoupesDeProbing->Coefficient; + Colonne = CoupesDeProbing->Colonne; +} + +if ( TypeContrainteSource == CONTRAINTE_NATIVE ) { + Mdeb = Pne->MdebTrav; + Nuvar = Pne->NuvarTrav; + A = Pne->ATrav; + Sec = Pne->BTrav[ContrainteSource]; +} +else { + Mdeb = CoupesDeProbing->First; + Nuvar = CoupesDeProbing->Colonne; + A = CoupesDeProbing->Coefficient; + Sec = CoupesDeProbing->SecondMembre[ContrainteSource]; +} + +First[NombreDeCoupesDeProbing] = il1; +Nb = 0; +il = Mdeb[ContrainteSource]; +ilMax = il + NbTerm[ContrainteSource]; +Amin = LINFINI_PNE; +ilVar1 = -1; +CoeffTest = 0; +while ( il < ilMax ) { + if ( A[il] != 0 ) { + if ( Nuvar[il] == Var1 ) { + ilVar1 = il1; + } + if ( fabs( A[il] ) < Amin ) Amin = fabs( A[il] ); + Coefficient[il1] = A[il]; + Colonne[il1] = Nuvar[il]; + il1++; + Nb++; + } + il++; +} +NbElements[NombreDeCoupesDeProbing] = Nb; + +CoupesDeProbing->SecondMembre[NombreDeCoupesDeProbing] = Sec; + +if ( ilVar1 >= 0 ) { + /* On modifie le coefficient de la variable */ + if ( ValeurDeVar1 == 1 ) { + /* La variable Var1 a ete instanciee a 1 dans le probing */ + Coefficient[ilVar1] += CoeffDeVar1; + if ( fabs( Coefficient[ilVar1] ) < ZERO_NOUVEAU_COEFF ) Coefficient[ilVar1] = 0.0; + } + else { + /* La variable Var1 a ete instanciee a 0 dans le probing */ + Coefficient[ilVar1] -= CoeffDeVar1; + if ( fabs( Coefficient[ilVar1] ) < ZERO_NOUVEAU_COEFF ) Coefficient[ilVar1] = 0.0; + CoupesDeProbing->SecondMembre[NombreDeCoupesDeProbing] -= CoeffDeVar1; + } + CoeffTest = Coefficient[ilVar1]; + if ( CoeffTest == 0.0 ) { + /* On enleve la variable */ + Coefficient[ilVar1] = Coefficient[il1-1]; + Colonne[ilVar1] = Colonne[il1-1]; + NbElements[NombreDeCoupesDeProbing]--; + if ( NbElements[NombreDeCoupesDeProbing] <= 0 ) return; + } +} +else { + /* On ajoute la variable */ + Colonne[il1] = Var1; + if ( ValeurDeVar1 == 1 ) { + /* La variable Var1 a ete instanciee a 1 dans le probing */ + Coefficient[il1] = CoeffDeVar1; + } + else { + /* La variable Var1 a ete instanciee a 0 dans le probing */ + Coefficient[il1] = -CoeffDeVar1; + CoupesDeProbing->SecondMembre[NombreDeCoupesDeProbing] -= CoeffDeVar1; + } + CoeffTest = Coefficient[il1]; + NbElements[NombreDeCoupesDeProbing]++; + il1++; +} + +/* Problemes de conditionnement ? */ +if ( CoeffTest != 0.0 ) { + if ( Pne->PlusGrandTerme / Pne->PlusPetitTerme < 1.e+5 ) { + if ( fabs( CoeffTest ) > RMAX * Amin ) { + # if TRACES == 1 + printf("Coupe de probing refusee a cause du conditionnement Amin = %e\n",Amin); + # endif + return; + } + } + else if ( fabs( CoeffTest ) > 1.01 * Pne->PlusGrandTerme || fabs( CoeffTest ) < 0.99 * Pne->PlusPetitTerme ) { + # if TRACES == 1 + printf("Coupe de probing refusee a cause du conditionnement CoeffTest = %e PlusPetitTerme = %e PlusGrandTerme = %e\n", + CoeffTest,Pne->PlusPetitTerme,Pne->PlusGrandTerme); + # endif + return; + } +} +else if ( NbElements[NombreDeCoupesDeProbing] <= 1 ) { + /* 1 seul element et en plus il est nul ! */ + return; +} +if ( fabs( CoeffTest ) < 0.1 ) return; + +# if TRACES == 1 + printf("Coupe de probing: %d\n",NombreDeCoupesDeProbing); + il = First[NombreDeCoupesDeProbing]; + ilMax = il + NbElements[NombreDeCoupesDeProbing]; + while ( il < ilMax ) { + if ( Pne->TypeDeVariableTrav[Colonne[il]] == ENTIER ) printf("%e (%d I) ",Coefficient[il],Colonne[il]); + else printf("%e (%d R) ",Coefficient[il],Colonne[il]); + il++; + } + printf(" SecondMembre %e\n",CoupesDeProbing->SecondMembre[NombreDeCoupesDeProbing]); +# endif + +/* Si la contrainte source est deja une coupe de probing on invalide l'ancienne coupe de probing */ +if ( TypeContrainteSource == COUPE_DE_PROBING ){ + /* Si la contrainte source est deja une coupe de probing on invalide l'ancienne coupe de probing */ + First[ContrainteSource] = -1; +} + +Pne->ProbingOuNodePresolve->NumeroDeCoupeDeProbing[ContrainteNative] = NombreDeCoupesDeProbing; + +CoupesDeProbing->IndexLibre = il1; +CoupesDeProbing->LaCoupDeProbingEstDansLePool[NombreDeCoupesDeProbing] = NON_PNE; +CoupesDeProbing->NombreDeCoupesDeProbing++; + +return; +} + +/*----------------------------------------------------------------------------------------------------*/ +/* Si des contraintes son devenues non activables on cree les coupes de probing correspondantes */ +void PNE_CreerLesCoupesDeProbing( PROBLEME_PNE * Pne, PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve ) +{ +int NombreDeContraintes; double * Bmax; double * B; double CoeffCandidat; int Cnt; double * BmaxSv; +int * NumeroDeCoupeDeProbing; int * First; int * NbElements; int * Colonne; double * SecondMembre; +double * Coefficient; int NumCoupe; COUPES_DE_PROBING * CoupesDeProbing; char * BorneInfConnueSv; +double * ValeurDeBorneInfSv; double * ValeurDeBorneSupSv; int il; int Var; double A; int NbCntCoupesDeProbing; +char BrnInfConnueSv; int ilMax; double SmaxSv; double Sec; char TypeContrainteSource; +int NumContrainteSource; double Smax; char BrnInfConnue; char * BorneInfConnue; double * ValeurDeBorneInf; +double * ValeurDeBorneSup; int i; int * NumCntCoupesDeProbing; char * FlagCntCoupesDeProbing; + +# if UTILISER_LES_COUPES_DE_PROBING == NON_PNE + return; +# endif + +if ( ProbingOuNodePresolve->VariableInstanciee < 0 ) return; + +if ( ProbingOuNodePresolve->NbCntCoupesDeProbing <= 0 ) return; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +B = Pne->BTrav; +Bmax = ProbingOuNodePresolve->Bmax; +BmaxSv = ProbingOuNodePresolve->BmaxSv; +NumeroDeCoupeDeProbing = ProbingOuNodePresolve->NumeroDeCoupeDeProbing; + +CoupesDeProbing = Pne->CoupesDeProbing; + +BorneInfConnueSv = ProbingOuNodePresolve->BorneInfConnueSv; +ValeurDeBorneInfSv = ProbingOuNodePresolve->ValeurDeBorneInfSv; +ValeurDeBorneSupSv = ProbingOuNodePresolve->ValeurDeBorneSupSv; +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; +ValeurDeBorneSup = ProbingOuNodePresolve->ValeurDeBorneSup; + +NumCntCoupesDeProbing = ProbingOuNodePresolve->NumCntCoupesDeProbing; +FlagCntCoupesDeProbing = ProbingOuNodePresolve->FlagCntCoupesDeProbing; + +NbCntCoupesDeProbing = ProbingOuNodePresolve->NbCntCoupesDeProbing; +ProbingOuNodePresolve->NbCntCoupesDeProbing = 0; + +for ( i = 0 ; i < NbCntCoupesDeProbing ; i++ ) { + + Cnt = NumCntCoupesDeProbing[i]; + FlagCntCoupesDeProbing[Cnt] = 0; + + SmaxSv = BmaxSv[Cnt]; + Smax = Bmax[Cnt]; + Sec = B[Cnt]; + TypeContrainteSource = CONTRAINTE_NATIVE; + NumContrainteSource = Cnt; + + /* Si la contrainte est deja reliee a une coupe de probing on regarde si elle est violee puis relaxee */ + if ( NumeroDeCoupeDeProbing[Cnt] >= 0 && CoupesDeProbing != NULL ) { + /* Car a pu etre augmente */ + First = CoupesDeProbing->First; + NbElements = CoupesDeProbing->NbElements; + SecondMembre = CoupesDeProbing->SecondMembre; + Colonne = CoupesDeProbing->Colonne; + Coefficient = CoupesDeProbing->Coefficient; + NumCoupe = NumeroDeCoupeDeProbing[Cnt]; + TypeContrainteSource = COUPE_DE_PROBING; + NumContrainteSource = NumCoupe; + il = First[NumCoupe]; + if ( il < 0 ) goto TestSeuil; + ilMax = il + NbElements[NumCoupe]; + SmaxSv = 0; + Smax = 0; + while ( il < ilMax ) { + Var = Colonne[il]; + A = Coefficient[il]; + BrnInfConnueSv = BorneInfConnueSv[Var]; + if ( BrnInfConnueSv == FIXE_AU_DEPART || BrnInfConnueSv == FIXATION_SUR_BORNE_INF || + BrnInfConnueSv == FIXATION_SUR_BORNE_SUP || BrnInfConnueSv == FIXATION_A_UNE_VALEUR ) { + SmaxSv += A * ValeurDeBorneInfSv[Var]; + } + else { + if ( A > 0.0 ) SmaxSv += A * ValeurDeBorneSupSv[Var]; + else SmaxSv += A * ValeurDeBorneInfSv[Var]; + } + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) { + Smax += A * ValeurDeBorneInf[Var]; + } + else { + if ( A > 0.0 ) Smax += A * ValeurDeBorneSup[Var]; + else Smax += A * ValeurDeBorneInf[Var]; + } + + il++; + } + Sec = SecondMembre[NumCoupe]; + } + TestSeuil: + if ( SmaxSv <= Sec ) continue; + if ( Smax >= Sec ) continue; + + CoeffCandidat = Sec - Smax; + if ( CoeffCandidat < SEUIL_DADMISSIBILITE /*1.e-2*/ ) continue; + + PNE_CreerUneCoupeDeProbing( Pne, ProbingOuNodePresolve->VariableInstanciee, CoeffCandidat, NumContrainteSource, + TypeContrainteSource, Cnt, Pne->ProbingOuNodePresolve->ValeurDeLaVariableInstanciee ); +} + +/* +if ( Pne->CoupesDeProbing != NULL ) printf("CoupesDeProbing->NombreDeCoupesDeProbing %d\n",Pne->CoupesDeProbing->NombreDeCoupesDeProbing); +*/ + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_coupes_de_probing_violees.c b/src/ext/Sirius_Solver/pne/pne_coupes_de_probing_violees.c new file mode 100644 index 0000000000..80607629bc --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_coupes_de_probing_violees.c @@ -0,0 +1,146 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Detection des coupes de probing violees. + Les coupes de probing sont crees a la creation du conflict graph. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define PROFONDEUR_LIMITE_COUPES_DE_PROBING 100000 /*10*/ /* Pas de limite */ + +/*----------------------------------------------------------------------------*/ + +void PNE_DetectionDesCoupesDeProbingViolees( PROBLEME_PNE * Pne ) +{ +double S; int Cnt; double E; int * First; int * NbElements; int NbV; double NormeV; +int il; int ilMax; double * Coeff; int * Indice; double B; int NbT; double * X; +int * Colonne; char * LaCoupDeProbingEstDansLePool; double * SecondMembre; +double * Coefficient; COUPES_DE_PROBING * CoupesDeProbing; double Marge; +int * TypeDeBorne; BB * Bb; + +# if UTILISER_LE_GRAPHE_DE_CONFLITS == OUI_PNE + # if PROBING_JUSTE_APRES_LE_PRESOLVE == OUI_PNE + return; + # endif +# endif + +if ( Pne->CoupesDeProbing == NULL ) return; + +Bb = Pne->ProblemeBbDuSolveur; +if ( Bb->NoeudEnExamen->ProfondeurDuNoeud > PROFONDEUR_LIMITE_COUPES_DE_PROBING ) return; + +CoupesDeProbing = Pne->CoupesDeProbing; + +Marge = SEUIL_VIOLATION_COUPES_DE_PROBING; + +TypeDeBorne = Pne->TypeDeBorneTrav; +X = Pne->UTrav; +Coeff = Pne->Coefficient_CG; +Indice = Pne->IndiceDeLaVariable_CG; + +First = CoupesDeProbing->First; +LaCoupDeProbingEstDansLePool = CoupesDeProbing->LaCoupDeProbingEstDansLePool; +NbElements = CoupesDeProbing->NbElements; +SecondMembre = CoupesDeProbing->SecondMembre; +Colonne = CoupesDeProbing->Colonne; +Coefficient = CoupesDeProbing->Coefficient; + +/* Attention: la partie simplexe considere que les variables intervenant dans les coupes ne + sont jamais de type fixe, c'est a dire qu'il y a toujours une correspondance des + les variables du simplexe. Il faut donc ne pas mettre ces coupes. */ + +NbV = 0; +NormeV = 0.0; + +for ( Cnt = 0 ; Cnt < CoupesDeProbing->NombreDeCoupesDeProbing ; Cnt++ ) { + if ( First[Cnt] < 0 ) continue; + if ( LaCoupDeProbingEstDansLePool[Cnt] == OUI_PNE ) continue; + il = First[Cnt]; + if ( il < 0 ) continue; + ilMax = il + NbElements[Cnt]; + S = 0; + NbT = 0; + B = SecondMembre[Cnt]; + while ( il < ilMax ) { + if ( TypeDeBorne[Colonne[il]] != VARIABLE_FIXE ) { + /* Car sinon il n'y a pas de variable correspondante dans le simplexe */ + S += Coefficient[il] * X[Colonne[il]]; + Coeff[NbT] = Coefficient[il]; + Indice[NbT] = Colonne[il]; + NbT++; + } + else { + NbT = 0; /* Pour qu'elle ne soit pas violee */ + break; + } + il++; + } + if ( S > B + Marge && NbT > 0 ) { + /* + printf("NbT %d depassement %e\n",NbT,S-B); + for ( il = 0 ; il < NbT ; il++ ) { + printf(" %e (%d) ",Coeff[il],Indice[il]); + } + printf("< %e\n",B); + */ + E = S - B; + NormeV += E; + /* On Stocke la coupe */ + NbV++; + PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'K', NbT, B, E, Coeff, Indice ); + Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees-1]->IndexDansCoupesDeProbing = Cnt; + } +} + +if ( Pne->AffichageDesTraces == OUI_PNE && NbV > 0 ) { + printf("Adding %d probing cuts violated by %e\n",NbV,NormeV); + fflush( stdout ); +} + +return; +} + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_cover_knapsack.c b/src/ext/Sirius_Solver/pne/pne_cover_knapsack.c new file mode 100644 index 0000000000..24f376f518 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_cover_knapsack.c @@ -0,0 +1,835 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recherche de couverture de sac a dos + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define MARGE 1.e-5 /*1.e-6*/ +# define SEUIL_POUR_REBOUCLAGE 50 +# define MX_NBAR_AJ 50 + +# define ZERO_X 1.e-12 /*1.e-8*/ +# define ZERO_X_UPLIFT 1.e-12 /*1.e-8*/ + +# define POSSIBLE 1 +# define IMPOSSIBLE 0 + +/* Remarque sur le sequence independant: finalement ce n'est pas si interessant que ca */ +# define KNAPSACK_SEQUENCE_INDEPENDENT_LIFTING NON_PNE + +# define VALEUR_CONTRAINTE_MOINS_A_DE_VARIABLE_A_1 OUI_PNE /* OUI_PNE */ + + + +int NbK=0; double SommeViolations=0; + + + +/*----------------------------------------------------------------------------*/ +int PNE_PartitionTriRapide( double * Tableau, int * Ordre, int Deb, int Fin, char TypeTri ) +{ +int Compt; double Pivot; int i; int j; int Var; + +Compt = Deb; +j = Ordre[Deb]; +Pivot = Tableau[j]; + +if ( TypeTri == DECROISSANT ) { + /* Ordre decroissant */ + for ( i = Deb + 1 ; i <= Fin ; i++) { + j = Ordre[i]; + if ( Tableau[j] > Pivot) { + Compt++; + Var = Ordre[Compt]; + Ordre[Compt] = j; + Ordre[i] = Var; + } + } +} +else { + /* Ordre croissant */ + for ( i = Deb + 1 ; i <= Fin ; i++) { + j = Ordre[i]; + if ( Tableau[j] < Pivot) { + Compt++; + Var = Ordre[Compt]; + Ordre[Compt] = j; + Ordre[i] = Var; + } + } +} + +Var = Ordre[Compt]; +Ordre[Compt] = Ordre[Deb]; +Ordre[Deb] = Var; + +return(Compt); +} + +/*----------------------------------------------------------------------------*/ +void PNE_TriRapide( double * Tableau, int * Ordre, int Debut, int Fin, char TypeTri ) +{ +int Pivot; +if ( Debut < Fin ) { + Pivot = PNE_PartitionTriRapide( Tableau, Ordre, Debut, Fin, TypeTri ); + PNE_TriRapide( Tableau, Ordre, Debut , Pivot-1, TypeTri ); + PNE_TriRapide( Tableau, Ordre, Pivot+1, Fin , TypeTri ); +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_ReclasserCsurA( int VariableLiftee, char * Z, int * Nb, double * CsurA, + int MxCoeff, int * C, double * A1, double * A, int * NumVar ) +{ +int iSupprime; int NbNew; double CdivA; int i; +NbNew = *Nb; +Z[VariableLiftee] = 1; +CdivA = (double) MxCoeff / A[VariableLiftee]; +iSupprime = NbNew; +for ( i = 0 ; i < NbNew ; i++ ) { + if ( CsurA[i] < CdivA ) { + iSupprime = i; + break; + } +} +for( i = NbNew ; i > iSupprime ; i-- ) { + CsurA[i] = CsurA[i-1]; + C[i] = C[i-1]; + A1[i] = A1[i-1]; + NumVar[i] = NumVar[i-1]; +} +C[iSupprime] = MxCoeff; +A1[iSupprime] = A[VariableLiftee]; +CsurA[iSupprime] = CdivA; +NumVar[iSupprime] = VariableLiftee; +NbNew++; +*Nb = NbNew; +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_RechercherUneCouvertureMinimale( int NombreDeVariables, double * ValeurDeX, double * A, int * C, + char * CouvertureTrouvee , double ValeurDeLaContrainte , + char * Z , double * CsurA, int * OrdreVar , + double * SecondMembreDeLaKnapsak, int * NombreDeVariablesDeLaKnapsak, + double * CoefficientsDeLaKnapsack, int * VariableBooleenneDeLaKnapsack, + double * A1, int * NumVar, char LesCoeffSontEntiers ) +{ +double Bmax; int i; int Var; double NouvelleValeurDeB; double VB; int j ; +char TypeTri; char OnEnleve; int Nb; double B0; double B; int SecondMembreCouverture; +int Xi; int Co; int YaDesVariablesDansC2; char OnPeutDownLifter; double Zdyn; + +*CouvertureTrouvee = NON_PNE; + +/* On essaie d'abord de trouver une couverture minimale par empilements puis on lifte + les variables. + A noter: j'ai essaye de trouver une couverture minimale violee par la solution + courante par programmation dynamique. Ce n'est pas une bonne methode car tres souvent + la programmation dynamique ne trouve pas de couverture violee. + L'heuristique ci-dessous (proposee par Zongao Gu) part d'une couverture minimale + trouvee par un empilement un peu "intelligent" ce qui permet de lifter les variables + et de trouver une inegalite valide violee par la solution courante. + Demander a partir d'un couverture violee pour faire du lifting est trop + restictif */ + +/* Calcul de la valeur max de la somme (toutes les variables sont a 1) */ +Bmax = 0.0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) Bmax+= A[Var]; +if ( Bmax <= ValeurDeLaContrainte ) goto FinCouverture; + + +/********************** Test **************************/ +Zdyn = -1.; +/* +if ( LesCoeffSontEntiers == OUI_PNE ) { + if ( ValeurDeLaContrainte <= SEUIL_POUR_PROGRAMMATION_DYNAMIQUE ) { + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + CsurA[Var] = 1. - ValeurDeX[Var]; + } + Zdyn = PNE_ProgrammationDynamiqueKnapsackSeparation( NombreDeVariables, CsurA, A, ValeurDeLaContrainte ); + if ( Zdyn < 1 ) printf("Couverture minimale trouvee Zdyn %e\n",Zdyn); + } +} +*/ +/************** Fin test ***********************/ + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + OrdreVar[Var] = Var; + CsurA[Var] = (1. - ValeurDeX[Var]) / A[Var]; + Z[Var] = 0; +} + +/* On empile */ +/* On ne tient pas compte des variables a 0, lesquelles seront upliftees */ +NouvelleValeurDeB = 0.0; +Nb = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( ValeurDeX[Var] > ZERO_X ) { + NouvelleValeurDeB += A[Var]; + if ( ValeurDeX[Var] == 1.0 ) Z[Var] = 2; /* mettre 1 pour ne pas downlifter */ + else Z[Var] = 1; + Nb++; + } +} + +/* Si on peut tout empiler sans contrainte on sort */ +if ( NouvelleValeurDeB <= ValeurDeLaContrainte + MARGE ) { + goto FinCouverture; +} + +/* Ordre decroissant */ +TypeTri = DECROISSANT; +PNE_TriRapide( CsurA, OrdreVar, 0, NombreDeVariables - 1, TypeTri); + +# if DEBUG_PNE + /* Verification */ + for ( j = 0 ; j < NombreDeVariables - 1 ; j++ ) { + Var = OrdreVar[j]; + Var1 = OrdreVar[j+1]; + if ( (1. - ValeurDeX[Var]) / A[Var] < (1. - ValeurDeX[Var1]) / A[Var1]) { + printf("Mauvais classement\n"); + exit(0); + } + } +# endif + +/* On enleve les objets tout en respectant la contrainte */ +for ( j = 0 ; j < NombreDeVariables ; j++ ) { + Var = OrdreVar[j]; + if ( Z[Var] != 0 ) { + /* On essaie d'enlever l'objet */ + if ( NouvelleValeurDeB - A[Var] > ValeurDeLaContrainte + MARGE ) { + /* On peut enlever l'objet */ + NouvelleValeurDeB -= A[Var]; + Z[Var] = 0; + Nb--; + } + } +} + +if ( Nb == 0 ) goto FinCouverture; +if ( NouvelleValeurDeB < ValeurDeLaContrainte + MARGE ) { + goto FinCouverture; +} + +/* Couverture minimale : si on peut enlever une variable en etant superieur a ContrainteMoinsVariablesAUn, on l'enleve */ + +OnEnleve = OUI_PNE; +while ( OnEnleve == OUI_PNE ) { + OnEnleve = NON_PNE; + NouvelleValeurDeB = 0.0; + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( Z[Var] != 0 ) NouvelleValeurDeB += A[Var]; + } + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( Z[Var] != 0 ) { + if ( NouvelleValeurDeB - A[Var] > ValeurDeLaContrainte + MARGE ) { + OnEnleve = OUI_PNE; + Nb--; + Z[Var] = 0; + break; + } + } + } +} + +if ( Nb == 0 ) goto FinCouverture; + +if ( NouvelleValeurDeB < ValeurDeLaContrainte + MARGE ) goto FinCouverture; + +/* On verifie que la couverture est minimale */ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( Z[Var] != 0 ) { + if ( NouvelleValeurDeB - A[Var] > ValeurDeLaContrainte + MARGE ) { + printf("La couverture n'est pas minimale NouvelleValeurDeB %e A[Var] %e ValeurDeLaContrainte %e\n", + NouvelleValeurDeB,A[Var],ValeurDeLaContrainte); + goto FinCouverture; + } + } +} + +if ( Nb == 0 ) goto FinCouverture; + +# if KNAPSACK_SEQUENCE_INDEPENDENT_LIFTING == OUI_PNE + if ( LesCoeffSontEntiers == OUI_PNE ) { + /* On classe les coefficients de la couverture dans l'ordre decroissant */ + for ( i = 0 ; i < NombreDeVariables ; i++ ) OrdreVar[i] = i; + TypeTri = DECROISSANT; + PNE_TriRapide( A, OrdreVar, 0, NombreDeVariables - 1, TypeTri); + Nb = 0; + B0 = ValeurDeLaContrainte; + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + Var = OrdreVar[i]; + /*if ( Z[Var] == 2 ) Z[Var] = 1;*/ /* Ca ne marche pas si on ne met pas les variable de C2 dans la couverture de depart */ + if ( Z[Var] == 1 ) { + A1[Nb] = A[Var]; + CoefficientsDeLaKnapsack[Nb] = 1; + VariableBooleenneDeLaKnapsack[Nb] = Var; + Nb++; + } + else if ( Z[Var] == 2 ) { + B0 -= A[Var]; + } + } + *SecondMembreDeLaKnapsak = Nb - 1; + *NombreDeVariablesDeLaKnapsak = Nb; + /* La couverture passee n'est constituee que de variables dans C1 */ + PNE_SequenceIndependantCoverKnapsackLifting( /* La contrainte de sac a dos */ + NombreDeVariables, ValeurDeX, A, B0, + /* La couverture */ + NombreDeVariablesDeLaKnapsak, CoefficientsDeLaKnapsack, + VariableBooleenneDeLaKnapsack, SecondMembreDeLaKnapsak, A1, + /* Les variables a lifter */ + Z, CsurA, OrdreVar, + /* Code retour */ + CouvertureTrouvee ); + return; + } +# endif + +/* On constitue C1 */ +/* Z[Var] = 1 si Var est dans C1 , Z[Var] = 2 si Var est dans C2 */ +YaDesVariablesDansC2 = NON_PNE; +Nb = 0; +B0 = ValeurDeLaContrainte; +NouvelleValeurDeB = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( Z[Var] == 1 ) { + NouvelleValeurDeB += A[Var]; + CsurA[Nb] = 1. / A[Var]; + NumVar[Nb] = Var; + OrdreVar[Nb] = Nb; + Nb++; + } + else if ( Z[Var] == 2 ) { + B0 -= A[Var]; + YaDesVariablesDansC2 = OUI_PNE; + } +} + +OnPeutDownLifter = NON_PNE; +if ( YaDesVariablesDansC2 == OUI_PNE ) OnPeutDownLifter = OUI_PNE; + +SecondMembreCouverture = Nb - 1; + +if ( NouvelleValeurDeB < B0 ) { + printf("Erreur NouvelleValeurDeB %e B0 %e apres avoir enleve les variables dans C2\n",NouvelleValeurDeB,B0); +} + +if ( Nb == 0 ) goto FinCouverture; + +/* Classement de C/A dans l'ordre decroissant */ +TypeTri = DECROISSANT; +PNE_TriRapide( CsurA, OrdreVar, 0, Nb - 1, TypeTri); + +for ( i = 0 ; i < Nb ; i++ ) { + j = OrdreVar[i]; + Var = NumVar[j]; + C[i] = 1; + A1[i] = A[Var]; + CsurA[i] = 1. / A1[i]; + OrdreVar[i] = Var; +} + +memcpy( (char *) NumVar, (char *) OrdreVar, Nb * sizeof( int ) ); + +/* On classe les variables dans l'ordre decroissant de X */ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) OrdreVar[Var] = Var; +TypeTri = DECROISSANT; +PNE_TriRapide( ValeurDeX, OrdreVar, 0, NombreDeVariables - 1, TypeTri); + +# if DEBUG_PNE + /* Verification */ + for ( j = 0 ; j < NombreDeVariables - 1 ; j++ ) { + if ( ValeurDeX[OrdreVar[j]] < ValeurDeX[OrdreVar[j+1]] ) { + printf("Mauvais classement\n"); + exit(0); + } + } +# endif + +/* On uplifte toutes les variables qui ne sont pas dans la K */ +/* On downlift les variables qui sont dans C2 */ + +/* On uplifte dans F */ + +/* On parcours la table dans le sens de ValeurDeX decroissant */ + +# if VALEUR_CONTRAINTE_MOINS_A_DE_VARIABLE_A_1 == NON_PNE + B0 = ValeurDeLaContrainte; /* Non: quand on uplifte on a enleve les variable dans C2 donc il faut enlever leurs + coefficients dans le second membre */ +# endif + +for ( j = 0 ; j < NombreDeVariables ; j++ ) { + Var = OrdreVar[j]; + if ( Z[Var] != 0 ) continue; /* La variable est dans C1 ou C2 */ + if ( ValeurDeX[Var] <= ZERO_X_UPLIFT ) continue; + B = B0 - A[Var]; + if ( B < 0.0 ) { + # if VALEUR_CONTRAINTE_MOINS_A_DE_VARIABLE_A_1 == OUI_PNE + /* Lifting impossible: les ensembles ont ete mal choisis, tant pis */ + goto FinCouverture; + # else + continue; + # endif + } + Xi = PNE_MajorantKnapsack( Nb, C, A1, B, LesCoeffSontEntiers ); + Co = SecondMembreCouverture - Xi; + if ( Co > 0 ) { + PNE_ReclasserCsurA( Var, Z, &Nb, CsurA, Co, C, A1, A, NumVar ); + } +} + +/* If the resulting cover is not violated, the cover will not be violated */ +VB = 0.0; +for ( i = 0 ; i < Nb ; i++ ) VB += C[i] * ValeurDeX[NumVar[i]]; + +/* Verification: normalement la couverture est violee par rapport a Nb */ +if ( VB < (double) SecondMembreCouverture ) { + /*printf(" VB %e SecondMembreCouverture %d\n",VB,SecondMembreCouverture);*/ + goto FinCouverture; +} + +/* On downlift les variables qui sont dans C2 */ +if ( OnPeutDownLifter == NON_PNE ) goto OnUpLifteDansR; + +B0 = ValeurDeLaContrainte; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( Z[Var] != 2 ) continue; + /* La variable est dans C2 */ + B = B0; + Xi = PNE_MajorantKnapsack( Nb, C, A1, B, LesCoeffSontEntiers ); + Co = Xi - SecondMembreCouverture; + + # if VALEUR_CONTRAINTE_MOINS_A_DE_VARIABLE_A_1 == OUI_PNE + /* Lifting impossible: les ensembles ont ete mal choisis, tant pis */ + if ( Co <= 0 ) goto FinCouverture; + # endif + + if ( Co > 0 ) { + /* Insertion de la variable et modification du Classement de C/A */ + PNE_ReclasserCsurA( Var, Z, &Nb, CsurA, Co, C, A1, A, NumVar ); + SecondMembreCouverture += Co; + } +} + +OnUpLifteDansR: + +B0 = ValeurDeLaContrainte; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( Z[Var] != 0 ) continue; /* La variable est dans C1 ou dans C2 */ + if ( ValeurDeX[Var] > ZERO_X_UPLIFT ) continue; + + B = B0 - A[Var]; + if ( B < 0.0 ) { + # if VALEUR_CONTRAINTE_MOINS_A_DE_VARIABLE_A_1 == OUI_PNE + /* Lifting impossible. En principe ici ca ne peut pas arriver car sinon cela voudrait dire + qu'il y a une couverture a 1 seul element */ + goto FinCouverture; + # else + continue; + # endif + } + Xi = PNE_MajorantKnapsack( Nb, C, A1, B, LesCoeffSontEntiers ); + Co = SecondMembreCouverture - Xi; + if ( Co > 0 ) { + /*printf("Uplift de %d dans R\n",Var);*/ + /* Insertion de la variable et modification du Classement de C/A */ + PNE_ReclasserCsurA( Var, Z, &Nb, CsurA, Co, C, A1, A, NumVar ); + } +} + +*SecondMembreDeLaKnapsak = SecondMembreCouverture; +*NombreDeVariablesDeLaKnapsak = 0; +for ( i = 0 ; i < Nb ; i++ ) { + if ( C[i] == 0 ) continue; + if ( Z[NumVar[i]] != 1 ) { + printf("Attention C[i] = %d Z[NumVar[i]] = %d OnPeutDownLifter %d\n",C[i],Z[NumVar[i]],OnPeutDownLifter); + goto FinCouverture; + } + CoefficientsDeLaKnapsack [*NombreDeVariablesDeLaKnapsak] = C[i]; + VariableBooleenneDeLaKnapsack[*NombreDeVariablesDeLaKnapsak] = NumVar[i]; + *NombreDeVariablesDeLaKnapsak = *NombreDeVariablesDeLaKnapsak + 1; +} + +*CouvertureTrouvee = OUI_PNE; + +FinCouverture: + +return; +} + +/*----------------------------------------------------------------------------*/ +/* On essaie d'en faire une contrainte avec des coefficients entiers */ +void PNE_KnapsackCoeffEntiers( int NbBool, double * Coeff, double * SecondMembre, + double * FacteurMultiplicatifSurPGCD ) +{ +int Kref; int i; int a; int b; int c; char Bfait; double B; double Min; +char TousLesCoeffSontEntiers; + +Min = ldexp( 2, 4 ); /*2^4=16 2^5=32 etc..*/ + +*FacteurMultiplicatifSurPGCD = 1.; + +B = *SecondMembre; +/* Si les coefficients et le second membre sont entiers au passe a l'etape du PGCD */ +TousLesCoeffSontEntiers = OUI_PNE; +if ( B - floor( B ) != 0.0 ) TousLesCoeffSontEntiers = NON_PNE; +for ( i = 0 ; i < NbBool && TousLesCoeffSontEntiers == OUI_PNE ; i++ ) { + if ( Coeff[i] - floor( Coeff[i] ) != 0.0 ) TousLesCoeffSontEntiers = NON_PNE; +} +if ( TousLesCoeffSontEntiers == NON_PNE ) { + Kref = 3; /* Pour esperer se deplacer d'au moins un chiffre apres la virgule */ + while ( ldexp( B, Kref ) < Min ) Kref++; + for ( i = 0 ; i < NbBool ; i++ ) { + while ( ldexp( Coeff[i], Kref ) < Min ) Kref++; + } + for ( i = 0 ; i < NbBool ; i++ ) { + Coeff[i] = floor( ldexp( Coeff[i], Kref ) ); + } + /*B = floor( ldexp( B, Kref ) );*/ + B = ceil( ldexp( B, Kref ) ); +} +else { + /* Il n'y a rien a faire */ + return; +} + +/* Calcul du GCD des coeffs de la contrainte */ +if ( Coeff[0] > Coeff[1] ) { a = (int) Coeff[0]; b = (int) Coeff[1]; } +else { a = (int) Coeff[1]; b = (int) Coeff[0]; } + +i = 1; +Bfait = NON_PNE; + +GCD: +if ( a == 0 && b == 0 ) c = 0; +else if ( b == 0 ) c = a; +else if ( a == 0 ) c = b; +else { + c = a % b; + while ( c != 0 ) { + a = b; + b = c; + c = a % b; + } + c = b; +} + +i++; +if ( i < NbBool ) { + if ( (int) Coeff[i] > c ) { a = (int) Coeff[i]; b = c; } + else { a = c; b = (int) Coeff[i]; } + goto GCD; +} +if ( Bfait == NON_PNE ) { + Bfait = OUI_PNE; + if ( (int) B > c ) { a = (int) B; b = c; } + else { a = c; b = (int) B; } + goto GCD; +} + +if ( c != 0 ) { + for ( i = 0 ; i < NbBool ; i++ ) Coeff[i] /= c; + B /= c; +} + +*SecondMembre = B; + +/*printf("Kref %d PGCD %d FacteurMultiplicatifSurPGCD %e\n",Kref,c,ldexp( 1.0, Kref ) / (double) c);*/ +*FacteurMultiplicatifSurPGCD = ldexp( 1.0, Kref ) / (double) c; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_GreedyCoverKnapsack( PROBLEME_PNE * Pne, int Mdeb, int NbTerm, int * Nuvar, + double * A, double B, char RendreLesCoeffsEntiers, + char * CouvertureTrouvee, + /* Pour pouvoir lifter la variable continue s'il sagit d'une mixed 0-1 knapsack */ + char Mixed_0_1_Knapsack, /* OUI_PNE ou NON_PNE */ + double sBarre, + int NombreDeVariablesSubstituees, + int * NumeroDesVariablesSubstituees, + char * TypeDeSubsitution, + double * CoefficientDeLaVariableSubstituee + ) +{ +double * Coefficients; int il; int ilMax; double X; int Var; int NbBooleens; +int i; char * Complementee; int NombreDeTermes; double SecondMembre; +int * C; double a; char * Z; double * CsurA; int * OrdreVar; double * ValeurDeX; +int * NumVarDeVarBooleenne; double SecondMembreCouverture; int NombreDeVariablesCouverture; +double * CoefficientCouverture; int * VariableBooleenneCouverture; +int NumVarBooleenne; int * IndiceColonne; double * UTrav; int * TypeDeBorneTrav; +int * TypeDeVariableTrav; double S; double * A1; int * NumVar; double ValB; +char * TasPourKnapsack; char * pt; int LallocTas; char LesCoeffSontEntiers; +double CoeffDeLaVariableContinue; double FacteurMultiplicatifSurPGCD; +double Seuil; + +*CouvertureTrouvee = NON_PNE; + +UTrav = Pne->UTrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; + +ValeurDeX = Pne->ValeurLocale; +C = Pne->IndiceLocal; +Coefficients = Pne->Coefficient_CG; +OrdreVar = Pne->IndiceDeLaVariable_CG; + +LallocTas = NbTerm * sizeof( double ); /* Pour CsurA */ +LallocTas += NbTerm * sizeof( double ); /* Pour CoefficientCouverture */ +LallocTas += NbTerm * sizeof( double ); /* Pour A1 */ + +LallocTas += NbTerm * sizeof( int ); /* Pour NumVarDeVarBooleenne */ +LallocTas += NbTerm * sizeof( int ); /* Pour VariableBooleenneCouverture */ +LallocTas += NbTerm * sizeof( int ); /* Pour NumVar */ + +LallocTas += NbTerm * sizeof( char );/* Pour Complementee */ +LallocTas += NbTerm * sizeof( char );/* Pour Z */ + +TasPourKnapsack = (char *) malloc( LallocTas ); +if ( TasPourKnapsack == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_GreedyCoverKnapsack \n"); + goto FinGreedy; +} + +pt = TasPourKnapsack; +CsurA = (double *) pt; +pt += NbTerm * sizeof( double ); +CoefficientCouverture = (double *) pt; +pt += NbTerm * sizeof( double ); +A1 = (double *) pt; +pt += NbTerm * sizeof( double ); +NumVarDeVarBooleenne = (int *) pt; +pt += NbTerm * sizeof( int ); +VariableBooleenneCouverture = (int *) pt; +pt += NbTerm * sizeof( int ); +NumVar = (int *) pt; +pt += NbTerm * sizeof( int ); +Complementee = (char *) pt; +pt += NbTerm * sizeof( char ); +Z = (char *) pt; +pt += NbTerm * sizeof( char ); + +il = Mdeb; +ilMax = il + NbTerm; +while ( il < ilMax ) { + Var = Nuvar[il]; + if ( TypeDeBorneTrav[Var] == VARIABLE_FIXE ) { + B -= A[il] * UTrav[Var]; + } + il++; +} + +il = Mdeb; +ilMax = il + NbTerm; +NbBooleens = 0; +while ( il < ilMax ) { + /* Attention A est dans Pne->ValeurLocale */ + a = A[il]; + /* Attention Nuvar est dans Pne->IndiceLocal */ + Var = Nuvar[il]; + if ( TypeDeBorneTrav[Var] != VARIABLE_FIXE && a != 0.0 ) { + if ( TypeDeVariableTrav[Var] == ENTIER ) { + X = UTrav[Var]; + Complementee [NbBooleens] = NON_PNE; + if ( a < 0.0 ) { + Complementee[NbBooleens] = OUI_PNE; + B -= a; + a *= -1.0; + X = 1.0 - X; + } + Coefficients[NbBooleens] = a; + C [NbBooleens] = 0; /* Sera initialise ensuite */ + ValeurDeX [NbBooleens] = X; + NumVarDeVarBooleenne[NbBooleens] = Var; + NbBooleens++; + } + else { + /* La variable est reelle */ + printf("--------------------------- La variable est reelle non fixe \n"); + goto FinGreedy; + } + } + il++; +} + +if ( B < 0 ) goto FinGreedy; + +/* En retour on recoit la knapsack */ +/*printf("--------------------------- RechercherUneCouvertureMinimale\n");*/ + +/* Rendre les coefficients entiers n'est pas toujours benefique */ +LesCoeffSontEntiers = NON_PNE; +FacteurMultiplicatifSurPGCD = 1.; +# if COEFFS_ENTIERS_DANS_KNAPSACK == OUI_PNE + if ( RendreLesCoeffsEntiers == OUI_PNE && NbBooleens >= 2 ) { + PNE_KnapsackCoeffEntiers( NbBooleens, Coefficients, &B, &FacteurMultiplicatifSurPGCD ); + LesCoeffSontEntiers = OUI_PNE; + } +# else + RendreLesCoeffsEntiers = NON_PNE; /* Pour ne pas avoir de warning a la compilation */ +# endif + +PNE_RechercherUneCouvertureMinimale( NbBooleens, ValeurDeX, Coefficients, C, CouvertureTrouvee, B, Z, + CsurA, OrdreVar, &SecondMembreCouverture, &NombreDeVariablesCouverture, + CoefficientCouverture, VariableBooleenneCouverture, + A1, NumVar, LesCoeffSontEntiers ); + +if ( *CouvertureTrouvee == NON_PNE ) goto FinGreedy; +if ( NombreDeVariablesCouverture <= 0 ) goto FinGreedy; + +/* +printf("Knapsack trouvee NombreDeVariablesCouverture %d NbBooleens %d\n",NombreDeVariablesCouverture,NbBooleens); +*/ + +/* S'il s'agit d'une 0-1 mixed Knapsack on lifte la variable continue */ +if ( Mixed_0_1_Knapsack == OUI_PNE ) { + ValB = 0.0; + for ( i = 0 ; i < NombreDeVariablesCouverture ; i++ ) { + ValB += CoefficientCouverture[i] * ValeurDeX[VariableBooleenneCouverture[i]]; + } + S = ValB - SecondMembreCouverture; + if ( S < 1.e-6 ) goto FinGreedy; + printf(" Avant Lift \n"); + printf("NbBooleens %d Violation de la K %e SecondMembreCouverture %e\n",NbBooleens,S,SecondMembreCouverture); + + PNE_KnapsackLifterLaVariableContinue( CsurA, + /* La knapsack */ + NbBooleens, + Coefficients, + B, + /* La coupe sur knapsack */ + NombreDeVariablesCouverture, + VariableBooleenneCouverture, + CoefficientCouverture, + SecondMembreCouverture, + /* La valeur prise par s pour le calcul de la coupe sur knapsack */ + sBarre, + /* En retour le coeff de la variable continue liftee */ + &CoeffDeLaVariableContinue ); + CoeffDeLaVariableContinue *= FacteurMultiplicatifSurPGCD; + if ( FacteurMultiplicatifSurPGCD != 1.0 ) { + printf("FacteurMultiplicatifSurPGCD %e\n",FacteurMultiplicatifSurPGCD); + } + printf("CoeffDeLaVariableContinue %e\n",CoeffDeLaVariableContinue); + +} + +/* On prepare la contrainte a stocker et on calcule la violation */ +B = SecondMembreCouverture; + +NombreDeTermes = 0; +IndiceColonne = OrdreVar; +S = 0.0; +for ( i = 0 ; i < NombreDeVariablesCouverture ; i++ ) { + X = CoefficientCouverture[i]; + NumVarBooleenne = VariableBooleenneCouverture[i]; + if ( Complementee[NumVarBooleenne] == OUI_PNE ) { + Complementee[NumVarBooleenne] = NON_PNE; + B -= X; + X *= -1.0; + } + if ( X != 0.0 ) { + Coefficients[NombreDeTermes] = X; + Var = NumVarDeVarBooleenne[NumVarBooleenne]; + IndiceColonne[NombreDeTermes] = Var; + S += X * UTrav[Var]; + NombreDeTermes++; + } +} +SecondMembre = B; +S -= SecondMembre; + +if ( Mixed_0_1_Knapsack == OUI_PNE ) printf("Violation de la K apres retour aux variables entieres initiales %e\n",S); + +PNE_MiseAJourSeuilCoupes( Pne, COUPE_KNAPSACK, &Seuil ); + +if ( S >= Seuil ) { + Pne->SommeViolationsK += S; + Pne->NombreDeK++; +} + +if ( S >= Pne->SeuilDeViolationK ) { + if ( Mixed_0_1_Knapsack == NON_PNE ) { + /* On peut tout de suite stocker */ + PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'K', NombreDeTermes, SecondMembre, S, Coefficients, IndiceColonne ); + } + else { + /* Il faut redecomposer la variable continue, puis stocker la coupe */ + + /* Attention: Coefficients est remis a 0 dans SyntheseEtStockageMIR car + NuVarCoupe = Pne->IndiceDeLaVariable_CG; + CoeffCoupe = Pne->Coefficient_CG;*/ + double * Co; int * Nu; + Co = (double *) malloc( NombreDeTermes * sizeof(double) ); + Nu = (int *) malloc( NombreDeTermes * sizeof(int) ); + for ( i = 0 ; i < NombreDeTermes ; i++ ) { + Co[i] = Coefficients[i]; + Nu[i] = IndiceColonne[i]; + } + + PNE_SyntheseEtStockageMIR( Pne, NombreDeTermes, Nu, Co, SecondMembre, CoeffDeLaVariableContinue, + NombreDeVariablesSubstituees, NumeroDesVariablesSubstituees, + TypeDeSubsitution, CoefficientDeLaVariableSubstituee ); + free(Co); + free(Nu); + + + } +} +else { + *CouvertureTrouvee = NON_PNE; +} + +FinGreedy: + +PNE_FreeTasGreedyCoverKnapsack( TasPourKnapsack ); + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_FreeTasGreedyCoverKnapsack( char * TasPourKnapsack ) +{ +free( TasPourKnapsack ); +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_cover_knapsack_combinaisons.c b/src/ext/Sirius_Solver/pne/pne_cover_knapsack_combinaisons.c new file mode 100644 index 0000000000..bf718551eb --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_cover_knapsack_combinaisons.c @@ -0,0 +1,256 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recherche de couverture de sac a dos sur combinaisons simples + de contraintes. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define ZERO_K 1.e-9 + +/*----------------------------------------------------------------------------*/ + +void PNE_KnapsackSurCombinaisonsDeContraintes( PROBLEME_PNE * Pne, int Cnt0, int NombreDeTermes, + int * Variable, double * Coeff, double SecondMembre, + char * ContrainteDejaUtilisee, + char * VariableSupprimee ) +{ +int Var; int ic; int il; int ilMax; int Var1; double X0; double X; int Cnt1; int il1; int il1Max; +int i; char CouvertureTrouvee; int NbK; int NbConcat; int NombreDeVariablesTrav; +double Alpha; int * MdebTrav; int * NbTermTrav; char RendreLesCoeffsEntiers; +int * NuvarTrav; int * TypeDeBorneTrav; int * TypeDeVariableTrav; int * CdebTrav; +int * CsuiTrav; int * NumContrainteTrav; double * BTrav; double * ATrav; double * UTrav; +double * UminTrav; double * UmaxTrav; char * SensContrainteTrav; +double * V; double Gamma; int NombreDeTermes0; +char Mixed_0_1_Knapsack; + +/* +printf("KnapsackSurCombinaisonsDeContraintes NombreDeTermes %d\n",NombreDeTermes); +*/ + +Mixed_0_1_Knapsack = NON_PNE; + +NbK = 0; + +NombreDeTermes0 = NombreDeTermes; +NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; + +memset( (char *) ContrainteDejaUtilisee, NON_PNE, Pne->NombreDeContraintesTrav * sizeof( char ) ); +ContrainteDejaUtilisee[Cnt0] = OUI_PNE; + +memset( (char *) VariableSupprimee, NON_PNE, NombreDeVariablesTrav * sizeof( char ) ); + +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +BTrav = Pne->BTrav; +ATrav = Pne->ATrav; +NuvarTrav = Pne->NuvarTrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; +UTrav = Pne->UTrav; +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; +CdebTrav = Pne->CdebTrav; +CsuiTrav = Pne->CsuiTrav; +NumContrainteTrav = Pne->NumContrainteTrav; +SensContrainteTrav = Pne->SensContrainteTrav; + +/* On etale la contrainte */ +V = Pne->Coefficient_CG; +memset( (char *) V , 0 , Pne->NombreDeVariablesTrav * sizeof( double ) ); +for ( i = 0 ; i < NombreDeTermes ; i++ ) V[Variable[i]] = Coeff[i]; + +/* On essaie de remplacer chaque variable entiere de la contrainte par d'autres variables + dont la valeur est plus grande que la variable remplacee. On espere ainsi augmenter le + membre de gauche pour trouver plus facilement une knapsack violee */ +NbConcat = 0; +il = MdebTrav[Cnt0]; +ilMax = il + NbTermTrav[Cnt0]; +while ( il < ilMax ) { + if ( ATrav[il] == 0.0 ) goto NextIl; + Var = NuvarTrav[il]; + if ( TypeDeVariableTrav[Var] != ENTIER ) goto NextIl; + if ( VariableSupprimee[Var] == OUI_PNE ) goto NextIl; + Gamma = V[Var]; + if ( Gamma == 0.0 ) goto NextIl; + + /* Si la variable est sur une borne peu prometteuse on ne la remplace pas */ + if ( Gamma > 0 ) { + if ( fabs( UTrav[Var] - UminTrav[Var] ) < ZERO_K ) goto NextIl; + } + else { + if ( fabs( UmaxTrav[Var] - UTrav[Var] ) < ZERO_K ) goto NextIl; + } + + X0 = fabs( Gamma * UTrav[Var] ); + X = 0.0; + /* Pour pouvoir remplacer cette variable, il faut trouver une contrainte ou la variable a un + signe oppose */ + ic = CdebTrav[Var]; + while ( ic >= 0 ) { + Cnt1 = NumContrainteTrav[ic]; + if ( ContrainteDejaUtilisee[Cnt1] == OUI_PNE ) goto NextIc; + if ( fabs( ATrav[ic] ) < ZERO_K ) goto NextIc; + if ( SensContrainteTrav[Cnt1] == '<' ) { + if ( ATrav[ic] * Gamma > 0.0 ) goto NextIc; + } + /* On s'interesse a la contrainte */ + Alpha = -Gamma / ATrav[ic]; + il1 = MdebTrav[Cnt1]; + il1Max = il1 + NbTermTrav[Cnt1]; + while ( il1 < il1Max ) { + Var1 = NuvarTrav[il1]; + if ( Var1 == Var ) goto NextIl1; + if ( VariableSupprimee[Var1] == OUI_PNE ) goto NextIc; + if ( TypeDeVariableTrav[Var1] == ENTIER ) { + X += fabs( Alpha * ATrav[il1] * UTrav[Var1] ); + } + else { + if ( Alpha * ATrav[il1] < 0.0 ) { + /* Il faudrait mettre la variable au max: on ne pourra pas utiliser la contrainte */ + if ( TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_DES_DEUX_COTES || + TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + X += fabs( Alpha * ATrav[il1] * UmaxTrav[Var1] ); + } + else { + /*printf("probleme de borne\n");*/ + goto NextIc; + } + } + else if ( Alpha * ATrav[il1] > 0.0 ) { + /* Il faudrait mettre la variable au min: on ne pourra pas utiliser la contrainte */ + if ( TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_DES_DEUX_COTES || + TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_INFERIEUREMENT ) { + X += fabs( Alpha * ATrav[il1] * UminTrav[Var1] ); + } + else { + /*printf("probleme de borne\n");*/ + goto NextIc; + } + } + } + NextIl1: + il1++; + } + if ( X >= X0 ) { + /* On peut utiliser la contrainte */ + il1 = MdebTrav[Cnt1]; + il1Max = il1 + NbTermTrav[Cnt1]; + while ( il1 < il1Max ) { + Var1 = NuvarTrav[il1]; + X = Alpha * ATrav[il1]; + if ( TypeDeBorneTrav[Var1] == VARIABLE_FIXE ) SecondMembre -= X * UTrav[Var1]; + /* On ajoute la variable mais on ne place pas les variables continues sur borne car + le signe peut encore changer */ + else V[Var1] += X; + il1++; + } + SecondMembre += Alpha * BTrav[Cnt1]; + if ( fabs( V[Var] ) > ZERO_K ) goto NextIl; /* Manque de precision */ + V[Var] = 0.0; + VariableSupprimee[Var] = OUI_PNE; + ContrainteDejaUtilisee[Cnt1] = OUI_PNE; + /*printf("Concatenation de la contrainte %d nbtermes %d\n",Cnt1,NbTermTrav[Cnt1]);*/ + NbConcat++; + goto NextIl; + } + NextIc: + ic = CsuiTrav[ic]; + } + NextIl: + il++; +} +/*printf("NbConcat %d NombreDeTermes0 %d\n",NbConcat,NombreDeTermes0);*/ +if ( NbConcat == 0 ) goto FinConcat; + +/* On reconstitue le vecteur de la contrainte sur laquelle on va chercher la knapsack */ +NombreDeTermes = 0; +for ( Var = 0 ; Var < NombreDeVariablesTrav ; Var++ ) { + if ( V[Var] != 0.0 ) { + if ( TypeDeVariableTrav[Var] == ENTIER ) { + Coeff[NombreDeTermes] = V[Var]; + Variable[NombreDeTermes] = Var; + NombreDeTermes++; + } + else { + if ( V[Var] < 0.0 ) { + /* Il faut monter la variable au max */ + if ( TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || + TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + SecondMembre -= V[Var] * UmaxTrav[Var]; + } + else { + NombreDeTermes = 0; + break; + } + } + else { + /* Il faut baisser la variable au min */ + if ( TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || + TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + SecondMembre -= V[Var] * UminTrav[Var]; + } + else { + NombreDeTermes = 0; + break; + } + } + } + } +} +/*printf(" NombreDeTermes %d SecondMembre %e\n",NombreDeTermes,SecondMembre);*/ +if ( NombreDeTermes == 0 ) goto FinConcat; +/* +printf(" Tentative recherche K NombreDeTermes0 %d NombreDeTermes %d NbConcat %d\n",NombreDeTermes0,NombreDeTermes,NbConcat); +*/ +if ( NombreDeTermes >= MIN_TERMES_POUR_KNAPSACK ) { + /* + printf(" recherche K NombreDeTermes0 %d NombreDeTermes %d NbConcat %d\n",NombreDeTermes0,NombreDeTermes,NbConcat); + */ + RendreLesCoeffsEntiers = OUI_PNE; + CouvertureTrouvee = NON_PNE; + PNE_GreedyCoverKnapsack( Pne, 0, NombreDeTermes, Variable, Coeff, SecondMembre, RendreLesCoeffsEntiers, &CouvertureTrouvee, + Mixed_0_1_Knapsack, 0.0, 0, NULL, NULL, NULL ); + if ( CouvertureTrouvee == OUI_PNE ) { + /*printf("---------------- Knapsack trouvee sur combinaison de contraintes NbConcat=%d\n",NbConcat);*/ + NbK++; + } + +} + +FinConcat: + +/* +if ( NbK > 0 || 1 ) printf(" -> %d Knapsack trouvees sur combinaison \n",NbK); +*/ + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_cover_knapsack_combinaisons_complexes.c b/src/ext/Sirius_Solver/pne/pne_cover_knapsack_combinaisons_complexes.c new file mode 100644 index 0000000000..f9da75cbb4 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_cover_knapsack_combinaisons_complexes.c @@ -0,0 +1,496 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recherche de couverture de sac a dos sur des combinaisons + un peu complexes de contraintes. + Remarque: on peu calculer les combinaisons une bonne fois + pour toutes. Idem pour les autres contraintes sur lesquelles + on fait un cover knapsack ou une MIR. + + On part d'une contrainte qui a les proprietes suivantes: + - soit c'est une contrainte mixte + - soit c'est une contrainte en variables entieres dont + certains coeffs sont negatifs. + + 1- On essai de combiner la contrainte de depart avec les autres. + Chaque combinaison doit supprimer une variable continue mais + la combinaison obtenue ne doit pas contenir plus de variables + continues. + 2- Pour chaque variable entiere a coeff negatif, on cherche + une combinaison qui fasse diminuer le nombre de signes + negatifs et qui n'amene pas de variable continue. + On passe le resultat au generateur de coupes de knapsack. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +void PNE_KnapsackSurCombinaisonsSupprimerUneVariableEntiere( PROBLEME_PNE * , int , double , int * , int * , + double * , int * , double * , char *, char * ); +void PNE_KnapsackSurCombinaisonsSupprimerUneVariableContinue( PROBLEME_PNE * , int , double , int * , int * , + double * , int * , double * , char * , char * ); + +/*----------------------------------------------------------------------------*/ + +void PNE_KnapsackSurCombinaisonsSupprimerUneVariableEntiere( PROBLEME_PNE * Pne, + int VarEnt, + double CoeffVarEnt, + int * NombreDeTermes, + int * Variable, + double * Coeff, + int * Presence, + double * SecondMembre, + char * ContrainteDejaUtilisee, + char * Echec ) +{ +double CoeffAi; double Rapport; int ic; int il; int ilMax; +int * CdebTrav; int * CsuiTrav; int * NumContrainteTrav; int * TypeDeVariableTrav; +int * MdebTrav; int * NbTermTrav; int * NuvarTrav; int Cnt; int Var; int ilDeb; +double * ATrav; char * SensContrainteTrav; double Sign; + +*Echec = OUI_PNE; + +CdebTrav = Pne->CdebTrav; +CsuiTrav = Pne->CsuiTrav; +NumContrainteTrav = Pne->NumContrainteTrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; + +ATrav = Pne->ATrav; +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; +SensContrainteTrav = Pne->SensContrainteTrav; + +ic = CdebTrav[VarEnt]; +while ( ic >= 0 ) { + Cnt = NumContrainteTrav[ic]; + if ( ContrainteDejaUtilisee[Cnt] == OUI_PNE ) goto NextIc2; + if ( SensContrainteTrav[ic] == '<' ) { + if ( ATrav[ic] >= 0.0 ) goto NextIc2; + } + CoeffAi = ATrav[ic]; + Rapport = -CoeffVarEnt / CoeffAi; + if ( Rapport > 0 ) Sign = 1.; + else Sign = -1.; + /* Contrainte candidate */ + ilDeb = MdebTrav[Cnt]; + il = ilDeb; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var = NuvarTrav[il]; + if ( Var == VarEnt ) goto NextIl2; + if ( TypeDeVariableTrav[Var] != ENTIER ) goto NextIc2; + if ( Sign * ATrav[il] < 0. && Presence[Var] < 0 ) goto NextIc2; + NextIl2: + il++; + } + /* Si on est arrive jusque la c'est que la combinaison est acceptable: on fait + la combinaison */ + il = ilDeb; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var = NuvarTrav[il]; + if ( Presence[Var] >= 0 ) { + Coeff[Presence[Var]] += Rapport * ATrav[il]; + } + else { + Variable[*NombreDeTermes] = Var; + Coeff[*NombreDeTermes] = Rapport * ATrav[il]; + *NombreDeTermes = *NombreDeTermes + 1; + } + il++; + } + *SecondMembre += Rapport * Pne->BTrav[Cnt]; + /* Suppression de VarEnt */ + if ( Presence[VarEnt] != *NombreDeTermes - 1 ) { + il = Presence[VarEnt]; + Variable[il] = Variable[*NombreDeTermes-1]; + Coeff[il] = Coeff[*NombreDeTermes-1]; + Presence[Variable[*NombreDeTermes-1]] = il; + Presence[VarEnt] = -1; + } + *NombreDeTermes = *NombreDeTermes - 1; + ContrainteDejaUtilisee[Cnt] = OUI_PNE; + *Echec = NON_PNE; + break; + NextIc2: + ic = CsuiTrav[ic]; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_KnapsackSurCombinaisonsSupprimerUneVariableContinue( PROBLEME_PNE * Pne, + int VarCont, + double CoeffVarCont, + int * NombreDeTermes, + int * Variable, + double * Coeff, + int * Presence, + double * SecondMembre, + char * ContrainteDejaUtilisee, + char * Echec ) +{ +double CoeffAi; double Rapport; int ic; int il; int ilMax; +int * CdebTrav; int * CsuiTrav; int * NumContrainteTrav; int * TypeDeVariableTrav; +int * MdebTrav; int * NbTermTrav; int * NuvarTrav; int Cnt; int Var; int ilDeb; +double * ATrav; char * SensContrainteTrav; + +*Echec = OUI_PNE; + +CdebTrav = Pne->CdebTrav; +CsuiTrav = Pne->CsuiTrav; +NumContrainteTrav = Pne->NumContrainteTrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; + +ATrav = Pne->ATrav; +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; +SensContrainteTrav = Pne->SensContrainteTrav; + +ic = CdebTrav[VarCont]; +while ( ic >= 0 ) { + Cnt = NumContrainteTrav[ic]; + if ( ContrainteDejaUtilisee[Cnt] == OUI_PNE ) goto NextIc1; + CoeffAi = ATrav[ic]; + if ( CoeffAi == 0.0 ) goto NextIc1; + Rapport = -CoeffVarCont / CoeffAi; + + if ( SensContrainteTrav[Cnt] == '<' ) { + if ( Rapport < 0.0 ) goto NextIc1; + } + /* Contrainte candidate */ + ilDeb = MdebTrav[Cnt]; + il = ilDeb; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var = NuvarTrav[il]; + if ( Var == VarCont ) goto NextIl1; + if ( TypeDeVariableTrav[Var] != ENTIER ) { + /* On suppose qu'il n'y a pas de "cancelation" numerique */ + /* La combinaison ajouterait une variable continue ? */ + if ( Presence[Var] < 0 ) goto NextIc1; + } + NextIl1: + il++; + } + /* Si on est arrive jusque la c'est que la combinaison est acceptable: on fait + la combinaison */ + Rapport = -CoeffVarCont / CoeffAi; + + if ( SensContrainteTrav[Cnt] == '<' && Rapport < 0.0 ) { + printf("Rapport %e SensContrainteTrav %c\n",Rapport,SensContrainteTrav[Cnt]); + exit(0); + } + + il = ilDeb; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var = NuvarTrav[il]; + if ( Presence[Var] >= 0 ) { + Coeff[Presence[Var]] += Rapport * ATrav[il]; + /*printf("Modif coeff de variable %d -> %e\n",Var,Coeff[Presence[Var]]);*/ + } + else { + Variable[*NombreDeTermes] = Var; + Coeff[*NombreDeTermes] = Rapport * ATrav[il]; + Presence[Var] = *NombreDeTermes; + /*printf("Creation coeff de variable %d -> %e\n",Var,Coeff[Presence[Var]]);*/ + *NombreDeTermes = *NombreDeTermes + 1; + } + il++; + } + *SecondMembre += Rapport * Pne->BTrav[Cnt]; + + if ( Coeff[Presence[VarCont]] != 0.0 ) { + printf("Coeff %e Presence[VarCont] %d NombreDeTermes %d \n",Coeff[Presence[VarCont]],Presence[VarCont],*NombreDeTermes); + exit(0); + } + + ContrainteDejaUtilisee[Cnt] = OUI_PNE; + + *Echec = NON_PNE; + break; + NextIc1: + ic = CsuiTrav[ic]; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_KnapsackSurCombinaisonsComplexesDeContraintes( PROBLEME_PNE * Pne ) +{ +char Mixed_0_1_Knapsack; int Cnt; int il; int ilMax; int ilDeb; int NombreDeTermes; +int * TypeDeVariableTrav; char * ContrainteKnapsack; char * ContrainteMixte; +int * MdebTrav; int * NbTermTrav; int * NuvarTrav; double * ATrav; int * Variable; +double * Coeff; int * Presence; double * BTrav; double SecondMembre; char Echec; +int i; int Var; int TypeBorne; int * TypeDeBorneTrav; double * UTrav; double * UminTrav; +double * UmaxTrav; char CouvertureTrouvee; char RendreLesCoeffsEntiers; +char * ContrainteDejaUtilisee; char * Buffer; char * pt; int Index; + +if ( Pne->ContrainteMixte == NULL ) return; + +/* +printf("KnapsackSurCombinaisonsComplexesDeContraintes \n"); +*/ +i = 0; +i += Pne->NombreDeVariablesTrav * sizeof( int ); /* Variable */ +i += Pne->NombreDeVariablesTrav * sizeof( double ); /* Coeff */ +i += Pne->NombreDeVariablesTrav * sizeof( int ); /* Presence */ +i += Pne->NombreDeContraintesTrav * sizeof( char ); /*ContrainteDejaUtilisee*/ + +Buffer = (char *) malloc( i * sizeof( char ) ); + +pt = Buffer; +Variable = (int *) pt; +pt += Pne->NombreDeVariablesTrav * sizeof( int ); +Coeff = (double *) pt; +pt += Pne->NombreDeVariablesTrav * sizeof( double ); +Presence = (int *) pt; +pt += Pne->NombreDeVariablesTrav * sizeof( int ); +ContrainteDejaUtilisee = (char *) pt; +pt += Pne->NombreDeContraintesTrav * sizeof( char ); + +Mixed_0_1_Knapsack = NON_PNE; + +UTrav = Pne->UTrav; +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; + +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +ContrainteKnapsack = Pne->ContrainteKnapsack; +ContrainteMixte = Pne->ContrainteMixte; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; +BTrav = Pne->BTrav; +ATrav = Pne->ATrav; +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + if ( ContrainteKnapsack[Cnt] != INF_POSSIBLE ) continue; + for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) Presence[i] = -1; + for ( i = 0 ; i < Pne->NombreDeContraintesTrav ; i++ ) ContrainteDejaUtilisee[i] = NON_PNE; + ilDeb = MdebTrav[Cnt]; + il = ilDeb; + ilMax = il + NbTermTrav[Cnt]; + NombreDeTermes = 0; + while ( il < ilMax ) { + if ( ATrav[il] != 0.0 ) { + Variable[NombreDeTermes] = NuvarTrav[il]; + Coeff[NombreDeTermes] = ATrav[il]; + Presence[NuvarTrav[il]] = NombreDeTermes; + NombreDeTermes++; + } + il++; + } + /* + printf("Etude contrainte NombreDeTermes %d\n",NombreDeTermes); + il = ilDeb; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + if ( TypeDeVariableTrav[NuvarTrav[il]] == ENTIER ) printf(" %e (i%d) ",ATrav[il],NuvarTrav[il]); + else printf(" %e (c%d)",ATrav[il],NuvarTrav[il]); + il++; + } + printf(" %c %e ContrainteMixte %d \n",Pne->SensContrainteTrav[Cnt],Pne->BTrav[Cnt],ContrainteMixte[Cnt]); + */ + ContrainteDejaUtilisee[Cnt] = OUI_PNE; + SecondMembre = BTrav[Cnt]; + if ( ContrainteMixte[Cnt] == OUI_PNE ) { + /* On essaie d'enlever les variables continues par des combinaisons */ + il = ilDeb; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var = NuvarTrav[il]; + if ( TypeDeVariableTrav[Var] == ENTIER ) goto NextIl; + if ( Presence[Var] < 0 ) goto NextIl; + if ( Coeff[Presence[Var]] == 0.0 ) goto NextIl; + PNE_KnapsackSurCombinaisonsSupprimerUneVariableContinue( Pne, Var,Coeff[Presence[Var]], + &NombreDeTermes, Variable, Coeff, Presence, &SecondMembre, + ContrainteDejaUtilisee, &Echec ); + if ( Echec == OUI_PNE ) { + /* Remarque: on pourrait tenter une MIR de Marchand Wolsey */ + break; + } + else { + /* Suppression de Var */ + if ( Presence[Var] != NombreDeTermes - 1 ) { + Index = Presence[Var]; + Variable[Index] = Variable[NombreDeTermes-1]; + Coeff[Index] = Coeff[NombreDeTermes-1]; + Presence[Variable[NombreDeTermes-1]] = Index; + } + Presence[Var] = -1; + NombreDeTermes = NombreDeTermes - 1; + } + NextIl: + il++; + } + } + else continue; + + if ( Echec == OUI_PNE ) continue; + + /* + printf("1- on arrive a NombreDeTermes %d\n",NombreDeTermes); + for ( i = 0 ; i < NombreDeTermes ; i++ ) { + Var = Variable[i]; + if ( TypeDeVariableTrav[Var] == ENTIER ) printf(" %e (i%d) ",Coeff[i],Var); + else printf(" %e (c%d) ",Coeff[i],Var); + il++; + } + printf(" < %e\n",SecondMembre); + */ + /* On essai d'enlever les signes negatifs sur les variables entieres de la contrainte d'origine */ + il = ilDeb; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax && 0 ) { + if ( TypeDeVariableTrav[NuvarTrav[il]] == ENTIER ) { + if ( ATrav[il] < 0.0 ) { + /*printf("On essai de supprimer le terme %d %e\n",NuvarTrav[il],ATrav[il]);*/ + PNE_KnapsackSurCombinaisonsSupprimerUneVariableEntiere( Pne, NuvarTrav[il], ATrav[il], + &NombreDeTermes, Variable, Coeff, Presence, &SecondMembre, + ContrainteDejaUtilisee, &Echec ); + if ( Echec == OUI_PNE ) { + /* Peut etre s'assurer qu'on a eu au moins une reussite ou bien que le remplacement + d'une variable continue a reussi */ + /*continue;*/ + } + } + } + il++; + } + /* + printf("2- on arrive a NombreDeTermes %d\n",NombreDeTermes); + for ( i = 0 ; i < NombreDeTermes ; i++ ) { + Var = Variable[i]; + if ( TypeDeVariableTrav[Var] == ENTIER ) printf(" %e (i%d) ",Coeff[i],Var); + else printf(" %e (c%d) ",Coeff[i],Var); + il++; + } + printf(" < %e\n",SecondMembre); + */ + /* On va pouvoir utiliser la contrainte */ + + for ( i = 0 ; i < NombreDeTermes ; i++ ) { + Var = Variable[i]; + if ( Coeff[i] == 0.0 ) { + Variable[i] = Variable[NombreDeTermes-1]; + Coeff[i] = Coeff[NombreDeTermes-1]; + NombreDeTermes--; + i--; + continue; + } + Var = Variable[i]; + TypeBorne = TypeDeBorneTrav[Var]; + if ( TypeBorne == VARIABLE_FIXE ) { + SecondMembre -= Coeff[i] * UTrav[Var]; + Variable[i] = Variable[NombreDeTermes-1]; + Coeff[i] = Coeff[NombreDeTermes-1]; + NombreDeTermes--; + i--; + continue; + } + if ( TypeDeVariableTrav[Var] == ENTIER ) continue; + + printf("Erreur il reste des variabes continues\n"); + exit(0); +NombreDeTermes = 0; +break; + + + /* La variable n'est pas entiere */ + if ( Coeff[i] < 0.0 ) { + /* Il faut monter la variable au max */ + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) { + SecondMembre -= Coeff[i] * UmaxTrav[Var]; + Variable[i] = Variable[NombreDeTermes-1]; + Coeff[i] = Coeff[NombreDeTermes-1]; + NombreDeTermes--; + i--; + } + else { + NombreDeTermes = 0; + break; + } + } + else { + /* Il faut baisser la variable au min */ + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) { + SecondMembre -= Coeff[i] * UminTrav[Var]; + Variable[i] = Variable[NombreDeTermes-1]; + Coeff[i] = Coeff[NombreDeTermes-1]; + NombreDeTermes--; + i--; + } + else { + NombreDeTermes = 0; + break; + } + } + } + /* + printf("3 on arrive a NombreDeTermes %d\n",NombreDeTermes); + for ( i = 0 ; i < NombreDeTermes ; i++ ) { + Var = Variable[i]; + if ( TypeDeVariableTrav[Var] == ENTIER ) printf(" %e (i%d) ",Coeff[i],Var); + else printf(" %e (c%d) ",Coeff[i],Var); + il++; + } + printf(" < %e\n",SecondMembre); + */ + + if ( NombreDeTermes <= 1 ) continue; + + RendreLesCoeffsEntiers = NON_PNE; + /* + if ( CoeffMn > ZERO_COEFFMN ) { + if ( CoeffMx / CoeffMn < RAPPORT_MAX ) RendreLesCoeffsEntiers = OUI_PNE; + } + */ + CouvertureTrouvee = NON_PNE; + PNE_GreedyCoverKnapsack( Pne, 0, NombreDeTermes, Variable, Coeff, SecondMembre, RendreLesCoeffsEntiers, &CouvertureTrouvee, + Mixed_0_1_Knapsack, 0.0, 0, NULL, NULL, NULL ); + /* + if ( CouvertureTrouvee == OUI_PNE ) { + printf(" K trouvee sur combinaison complexe !!!!!!!!!!!!!!\n"); + } + */ +} + +free( Buffer ); + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_cover_knapsack_lifting.c b/src/ext/Sirius_Solver/pne/pne_cover_knapsack_lifting.c new file mode 100644 index 0000000000..617034b190 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_cover_knapsack_lifting.c @@ -0,0 +1,401 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Lifting d'une couverture de sac a dos par la methode + "Sequence independent lifting of cover inequalities" + Gu, Nemhauser, Savelsbergh + Integer Prog. and Combinatorial Opt, 4th Int'l + IPCO Conference Proceedings, Copenhagen, Denmark, + May 1995, pgs 452-461. + Rq: je n'ai plus l'article mais on peut trouver la + methode dans " Sequence Independent Lifting in Mixed Integer + Programming" des memes auteur. + + Plusieurs chose ne sont pas au point: + le downlifting des ariables dans C2 et le + calcul du majorant knapsack. En ce qui concerne le + calcul du majorant knapsack, le probleme vient du fait + que les coefficients de la couverture ne sont pas + toujours des entiers. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define COMPILER 0 + +# define TRACES NON_PNE + +# define Epsilon 1.e-8 + +double PNE_SequenceIndependentMajorantKnapsack( int , double * , double * , double ); +void PNE_SequenceIndependentReclasserCsurA( int , char * , int * , double * , double , double * , double * , double * , int * ); + +/*----------------------------------------------------------------------------*/ + +double PNE_SequenceIndependentMajorantKnapsack( int NombreDeVariables, double * C, double * A, double B0 ) +{ +int Var; double X; double Z; double U_Dantzig; double U0; double U1; char U0_Valide; char U1_Valide; +char SolEntiere; int sigma0_s; int sigma1_s; double Marge; double B; int s; +int U; char U_Valide; + +Marge = 1.e-8; +SolEntiere = NON_PNE; + +/* Recherche de l'element critique s */ +B = B0; +Z = 0; +X = 0.0; +s = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + B -= A[Var]; + Z += C[Var]; + if ( B < 0.0 ) { + /* On a empile la variable en trop */ + /* L'item critique est Var */ + s = Var; + B += A[s]; + Z -= C[s]; + X = B / A[s]; + if ( fabs(X) < Marge ) { + SolEntiere = OUI_PNE; + } + else if ( fabs( 1. - X ) < Marge ) { + Z += C[s]; + SolEntiere = OUI_PNE; + } + } +} +if ( SolEntiere == OUI_PNE ) return( Z ); + +/* Borne de Dantzig */ +U_Dantzig = Z + ( C[Var] * X ); + +return( U_Dantzig ); + +U0 = U_Dantzig; +U1 = U_Dantzig; +U = U_Dantzig; + +/* A ce stade, Z est la valeur de la fonction cout apres avoir empile les item jusqu'a s-1 compris */ +/* sigma0_s est l'item critique lorsqu'on fait Xs = 0 */ +U0_Valide = NON_PNE; +for ( Var = s + 1 ; Var < NombreDeVariables ; Var++ ) { + B -= A[Var]; + Z += C[Var]; + if ( B < 0.0 ) { + /* L'item critique est Var */ + sigma0_s = Var; + B += A[sigma0_s]; + Z -= C[sigma0_s]; + X = B / A[sigma0_s]; + /* Borne de Fayard et Plateau */ + U0_Valide = OUI_PNE; + if ( fabs(X) < Marge ) U0 = Z; + else if ( fabs( 1. - X ) < Marge ) U0 = Z + C[sigma0_s]; + else U0 = Z + ( C[sigma0_s] * X ); + } +} + +/* sigma1_s est l'item critique lorsqu'on fait Xs = 1 sigma0_s est forcement toujours avant s */ +B = B0 - A[s]; +Z = C[s]; +U1_Valide = NON_PNE; +if ( B > 0.0 ) { + for ( Var = 0 ; Var < s ; Var++ ) { + B -= A[Var]; + Z += C[Var]; + if ( B < 0.0 ) { + /* L'item critique est Var */ + sigma1_s = Var; + B += A[sigma1_s]; + Z -= C[sigma1_s]; + X = B / A[sigma1_s]; + /* Borne de Hudson */ + U1_Valide = OUI_PNE; + if ( fabs(X) < Marge ) U1 = Z; + else if ( fabs( 1. - X ) < Marge ) U1 = Z + C[sigma1_s]; + else U1 = Z + ( C[sigma1_s] * X ); + } + } +} + +U_Valide = NON_PNE; +if ( U0_Valide == OUI_PNE && U1_Valide == OUI_PNE ) { + U_Valide = OUI_PNE; + U = U0; + if ( U < U1 ) U = U1; +} + +Z = U_Dantzig ; +if ( U_Valide == OUI_PNE ) { + if ( U <= Z ) { + Z = U; + } +} + +return( Z ); + +} +/*----------------------------------------------------------------------------*/ + +void PNE_SequenceIndependentReclasserCsurA( int VariableLiftee, char * Z, int * Nb, double * CsurA, + double Co, double * C, double * A, double * A0, int * NumVar ) +{ +int iSupprime; int NbNew; double CdivA; int i; +NbNew = *Nb; +Z[VariableLiftee] = 1; +CdivA = (double) Co / A0[VariableLiftee]; +iSupprime = NbNew; +for ( i = 0 ; i < NbNew ; i++ ) { + if ( CsurA[i] < CdivA ) { + iSupprime = i; + break; + } +} +for( i = NbNew ; i > iSupprime ; i-- ) { + CsurA[i] = CsurA[i-1]; + C[i] = C[i-1]; + A[i] = A[i-1]; + NumVar[i] = NumVar[i-1]; +} +C[iSupprime] = Co; +A[iSupprime] = A0[VariableLiftee]; +CsurA[iSupprime] = CdivA; +NumVar[iSupprime] = VariableLiftee; +NbNew++; +*Nb = NbNew; +return; +} + +# if COMPILER == 1 + +/*----------------------------------------------------------------------------*/ +/* Finalement on constate que le sequence independent lifting donne de moins + bons resultats */ +void PNE_SequenceIndependantCoverKnapsackLifting( + /* La contrainte de sac a dos */ + int NombreDeVariables, /* Nombre de variables de la contrainte de sac a dos */ + double * ValeurDeX, + double * A0, /* Les coefficients de la contrainte de sac a dos */ + double b, /* Second membre de la contrainte de sac a dos */ + /* La couverture */ + int * NombreDeVariablesDeLaCouvertureAuDepart, + double * CoefficientsDeLaCouverture, /* Coefficients de la couverture */ + int * VariableBooleenneDeLaCouverture, /* Contient les numeros de variables de la couverture */ + double * SecondMembreDeLaCouverture, + double * A, /* Contient les coeff (dans la contrainte A0) des variables de la couverture */ + char * Z, /* Contient des infos pour savoir si on doit lifter une variable */ + double * CsurA, + int * Ordre, + char * CouvertureTrouvee ) +{ +double * Mu; double Lambda; double Somme; double * MuMoinsLambda; int Var; int h; +double Aj; double Co; double * Rho; int i; int NbVarAjoutees; int j; double Xi; +int NombreDeVariablesDeLaCouverture; char TypeTri; double * C; int * Num; + +NbVarAjoutees = 0; +NombreDeVariablesDeLaCouverture = *NombreDeVariablesDeLaCouvertureAuDepart; + +/* Mu est dimensionnes au nombre de variables de la couverture + 1 */ +/* Rho est dimmensionne au nombre de variables de la couverture */ +/* On met NombreDeVariables car on s'en resert a la fin */ + +Mu = (double *) malloc( ( NombreDeVariables + 1 ) * sizeof( double) ); +MuMoinsLambda = (double *) malloc( ( NombreDeVariables + 1 ) * sizeof( double) ); +Rho = (double *) malloc( ( NombreDeVariables + 1 ) * sizeof( double) ); + +/* Les coefficients A des variables de la couverture sont supposes positifs et classes dans +l'ordre decroissant */ + +/* Mu[i] = Somme pour j = 0 a j = i-1 A[j] attention: dans l'article on va jusqu'a j=i mais + c'est parce que la numerotation des variables commence a 1 or en C la numerotation + commence a 0. + On a Mu[0] = 0 ; Mu[1] = A[0] ; Mu[2] = A[0] + A[1] ; + Pour s'en rappeler il faut se dire que Mu[2] c'est la somme pour 2 variables */ + +/* Calcul de Lambda: le depassement de la couverture (cover excess) */ +Somme = 0.0; +for ( i = 0 ; i < NombreDeVariablesDeLaCouverture ; i++ ) Somme += A[i]; +Lambda = Somme - b; +if ( Lambda < Epsilon ) return; + +Mu[0] = 0.0; +MuMoinsLambda[0] = -Lambda; +for ( i = 1 ; i < NombreDeVariablesDeLaCouverture + 1 ; i++ ) { + Mu[i] = Mu[i-1] + A[i-1]; + MuMoinsLambda[i] = Mu[i] - Lambda; +} + +/* On controle si f(z) est superaditive */ +if ( MuMoinsLambda[1] < A[1] || 1 ) goto FNonSuperAditive; +/* f(z) est superaditive */ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( Z[Var] != 0 ) continue; /* La variable est dans la couverture */ + Aj = A0[Var]; + /* La variable doit etre liftee car elle est dans C2 */ + if ( Aj <= MuMoinsLambda[1] - Epsilon ) { + /* Le coeff de lifting vaut 0 */ + continue; + } + for ( h = 2 ; h < NombreDeVariablesDeLaCouverture + 1 ; h++ ) { + if ( Aj <= MuMoinsLambda[h] - Epsilon ) { + /* Le coefficient de lifting de la variable Var est h */ + Co = h - 1; + # if TRACES == OUI_PNE + printf("valeur du coeff lifte : %e VariableLiftee %d\n",Co,Var); + # endif + CoefficientsDeLaCouverture[NombreDeVariablesDeLaCouverture + NbVarAjoutees] = Co; + VariableBooleenneDeLaCouverture[NombreDeVariablesDeLaCouverture + NbVarAjoutees] = Var; + NbVarAjoutees++; + break; + } + } +} +goto FinLifting; + +FNonSuperAditive: +/* On utilise une autre fonction g qui est superaditive */ +Rho[0] = Lambda; +Rho[NombreDeVariablesDeLaCouverture] = 0.0; +for ( i = 1 ; i < NombreDeVariablesDeLaCouverture ; i++ ) { + if ( A[i] - MuMoinsLambda[1] > 0 ) Rho[i] = A[i] - MuMoinsLambda[1]; + else Rho[i] = 0.0; +} + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( Z[Var] != 0 ) continue; /* La variable est dans la couverture */ + Aj = A0[Var]; + for ( h = 0 ; h < NombreDeVariablesDeLaCouverture ; h++ ) { + if ( Aj <= MuMoinsLambda[h+1] - Epsilon ) { + if ( h > 0 ) { + Co = h; /* Coeff de la variable liftee */ + # if TRACES == OUI_PNE + printf("1- valeur du coeff lifte : %e VariableLiftee %d\n",Co,Var); + # endif + CoefficientsDeLaCouverture[NombreDeVariablesDeLaCouverture + NbVarAjoutees] = Co; + VariableBooleenneDeLaCouverture[NombreDeVariablesDeLaCouverture + NbVarAjoutees] = Var; + NbVarAjoutees++; + } + break; + } + else if ( Aj <= MuMoinsLambda[h+1] + Rho[h+1] - Epsilon ) { + Co = h+1; + Co -= ( MuMoinsLambda[h+1] + Rho[h+1]- Aj ) / Rho[1]; + # if TRACES == OUI_PNE + printf("2- valeur du coeff lifte : %e VariableLiftee %d\n",Co,Var); + # endif + CoefficientsDeLaCouverture[NombreDeVariablesDeLaCouverture + NbVarAjoutees] = Co; + VariableBooleenneDeLaCouverture[NombreDeVariablesDeLaCouverture + NbVarAjoutees] = Var; + NbVarAjoutees++; + break; + } + } +} + +FinLifting: + +# if TRACES == OUI_PNE + printf("NbVarAjoutees %d\n",NbVarAjoutees); +# endif + +NombreDeVariablesDeLaCouverture += NbVarAjoutees; + +/* On downlift les variables dans C2 */ +/* Classement de C/A dans l'ordre decroissant */ +for ( i = 0 ; i < NombreDeVariablesDeLaCouverture ; i++ ) { + CsurA[i] = CoefficientsDeLaCouverture[i] / A0[VariableBooleenneDeLaCouverture[i]]; + Ordre[i] = i; +} +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( Z[Var] != 2 ) continue; + b += A0[Var]; +} +TypeTri = DECROISSANT; +PNE_TriRapide( CsurA, Ordre, 0, NombreDeVariablesDeLaCouverture - 1, TypeTri); + +C = (double *) MuMoinsLambda; +Num = (int *) Rho; +memcpy( (char *) C, (char *) CoefficientsDeLaCouverture, NombreDeVariablesDeLaCouverture * sizeof( double ) ); +memcpy( (char *) Num, (char *) VariableBooleenneDeLaCouverture, NombreDeVariablesDeLaCouverture * sizeof( int ) ); + +for ( i = 0 ; i < NombreDeVariablesDeLaCouverture ; i++ ) { + j = Ordre[i]; + CoefficientsDeLaCouverture[i] = C[j]; + VariableBooleenneDeLaCouverture[i] = Num[j]; + A[i] = A0[VariableBooleenneDeLaCouverture[i]]; + CsurA[i] = CoefficientsDeLaCouverture[i] / A[i]; +} + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( Z[Var] != 2 ) continue; + /* La variable est dans C2 */ + Xi = PNE_SequenceIndependentMajorantKnapsack( NombreDeVariablesDeLaCouverture, CoefficientsDeLaCouverture, A, b ); + Co = Xi - *SecondMembreDeLaCouverture; + /* Lifting impossible: les ensembles ont ete mal choisis, tant pis */ + if ( Co <= 0 ) goto Fin; + if ( Co > 0 ) { + /* Insertion de la variable et modification du Classement de C/A */ + PNE_SequenceIndependentReclasserCsurA ( Var, Z, &NombreDeVariablesDeLaCouverture, CsurA, Co, + CoefficientsDeLaCouverture, A, A0, VariableBooleenneDeLaCouverture ); + *SecondMembreDeLaCouverture = *SecondMembreDeLaCouverture + Co; + } +} + +*NombreDeVariablesDeLaCouvertureAuDepart = NombreDeVariablesDeLaCouverture; + +/* Controle du depassement */ +Somme = 0.0; +for ( i = 0 ; i < NombreDeVariablesDeLaCouverture ; i++ ) { + Somme += CoefficientsDeLaCouverture[i] * ValeurDeX[VariableBooleenneDeLaCouverture[i]]; +} +if ( Somme > *SecondMembreDeLaCouverture + Pne->SeuilDeViolationK ) { + # if TRACES == OUI_PNE + printf("Couverture liftee depasse b: Somme = %e SecondMembreDeLaCouverture = %e ecart %e\n", + Somme,*SecondMembreDeLaCouverture, Somme - *SecondMembreDeLaCouverture ); + # endif + *CouvertureTrouvee = OUI_PNE; +} +else { + # if TRACES == OUI_PNE + printf("Couverture liftee ne viole pas b: Somme = %e SecondMembreDeLaCouverture = %e \n", + Somme, *SecondMembreDeLaCouverture); + # endif +} + +Fin: + +free( Mu ); +free( MuMoinsLambda ); +free( Rho ); + +return; +} + +# endif diff --git a/src/ext/Sirius_Solver/pne/pne_cover_knapsack_simple.c b/src/ext/Sirius_Solver/pne/pne_cover_knapsack_simple.c new file mode 100644 index 0000000000..1aa2374592 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_cover_knapsack_simple.c @@ -0,0 +1,365 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recherche de couverture de sac a dos + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_CoverKnapsackSimple( PROBLEME_PNE * Pne ) +{ +int Cnt; int il; int ilMax; int ilDeb; int ilFin; char CouvertureTrouvee; +int NbKnapsack; int Var; int NombreDeTermes; double SecondMembre; double * Coeff; +int * Variable; char Inf; char Sup; char * ContrainteKnapsack; int * MdebTrav; +int * NbTermTrav; double * BTrav; double * ATrav; int * NuvarTrav; int * TypeDeVariableTrav; +int TypeBorne; int * TypeDeBorneTrav; double * UTrav; double * UminTrav; double * UmaxTrav; +char * VariableSupprimee; char * ContrainteDejaUtilisee; double * VariableDuale; +char Mixed_0_1_Knapsack; int Cnt1; int i; char Found; double u; double l; double bBorne; +int VarBin; int * CntDeBorneInfVariable; int * CntDeBorneSupVariable; char RendreLesCoeffsEntiers; + +/*printf("PNE_CoverKnapsackSimple\n");*/ + +ContrainteDejaUtilisee = (char *) malloc( Pne->NombreDeContraintesTrav * sizeof( char ) ); +if ( ContrainteDejaUtilisee == NULL ) { + printf("Saturation memoire dans PNE_CoverKnapsackSimple\n"); + return; +} +VariableSupprimee = (char *) malloc( Pne->NombreDeVariablesTrav * sizeof( char ) ); +if ( VariableSupprimee == NULL ) { + free( ContrainteDejaUtilisee ); + printf("Saturation memoire dans PNE_CoverKnapsackSimple\n"); + return; +} + +Mixed_0_1_Knapsack = NON_PNE; + +CntDeBorneInfVariable = Pne->CntDeBorneInfVariable; +CntDeBorneSupVariable = Pne->CntDeBorneSupVariable; + +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +BTrav = Pne->BTrav; +ATrav = Pne->ATrav; +NuvarTrav = Pne->NuvarTrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; +UTrav = Pne->UTrav; +UminTrav = Pne->UminTravSv; +UmaxTrav = Pne->UmaxTravSv; + +VariableDuale = Pne->VariablesDualesDesContraintesTravEtDesCoupes; + +ContrainteKnapsack = Pne->ContrainteKnapsack; +Coeff = Pne->ValeurLocale; +Variable = Pne->IndiceLocal; + +NbKnapsack = 0; + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + if ( ContrainteKnapsack[Cnt] == IMPOSSIBLE ) continue; + if ( NbTermTrav[Cnt] > NB_TERMES_FORCE_CALCUL_DE_K ) { + if ( fabs( VariableDuale[Cnt] ) < SEUIL_VARIABLE_DUALE_POUR_CALCUL_DE_COUPE ) continue; + } + Inf = IMPOSSIBLE; + Sup = IMPOSSIBLE; + if ( ContrainteKnapsack[Cnt] == INF_ET_SUP_POSSIBLE ) { + Inf = INF_POSSIBLE; + Sup = SUP_POSSIBLE; + } + else if ( ContrainteKnapsack[Cnt] == INF_POSSIBLE ) { + Inf = INF_POSSIBLE; + Sup = IMPOSSIBLE; + } + else if ( ContrainteKnapsack[Cnt] == SUP_POSSIBLE ) { + Inf = IMPOSSIBLE; + Sup = SUP_POSSIBLE; + } + + ilDeb = MdebTrav[Cnt]; + ilFin = ilDeb + NbTermTrav[Cnt]; + if ( Inf == INF_POSSIBLE ) { + SecondMembre = BTrav[Cnt]; + NombreDeTermes = 0; + il = ilDeb; + ilMax = ilFin; + while ( il < ilMax ) { + if ( ATrav[il] == 0.0 ) goto Next1_Il; + Var = NuvarTrav[il]; + TypeBorne = TypeDeBorneTrav[Var]; + if ( TypeBorne == VARIABLE_FIXE ) { + SecondMembre -= ATrav[il] * UTrav[Var]; + goto Next1_Il; + } + if ( TypeDeVariableTrav[Var] == ENTIER ) { + + /* Attention a cause des bornes variables il faut verifier que la variable n'y est pas deja. Peut etre ameliore. */ + Found = 0; + /* + for ( i = 0 ; i < NombreDeTermes ; i++ ) { + if ( Variable[i] == Var ) { + Found = 1; + Coeff[i] += ATrav[il]; + break; + } + } + */ + /* Fin borne sup variable */ + + if ( Found == 0 ) { + Coeff[NombreDeTermes] = ATrav[il]; + Variable[NombreDeTermes] = Var; + NombreDeTermes++; + } + goto Next1_Il; + } + /* La variable n'est pas entiere */ + if ( ATrav[il] < 0.0 ) { + /* Il faut monter la variable au max */ + + /* S'il y a une borne sup variable on remplace la variable par sa borne sup variable */ + if ( CntDeBorneSupVariable != NULL && 0 ) { + if ( CntDeBorneSupVariable[Var] >= 0 ) { + Cnt1 = CntDeBorneSupVariable[Var]; + i = MdebTrav[Cnt1]; + bBorne = BTrav[Cnt1]; + SecondMembre -= ATrav[il] * bBorne ; + VarBin = NuvarTrav[i]; + u = -ATrav[i]; + /* Peut etre ameliore */ + Found = 0; + for ( i = 0 ; i < NombreDeTermes ; i++ ) { + if ( Variable[i] == VarBin ) { + Found = 1; + Coeff[i] += ATrav[il] * u; + break; + } + } + if ( Found == 0 ) { + Coeff[NombreDeTermes] = ATrav[il] * u; + Variable[NombreDeTermes] = VarBin; + NombreDeTermes++; + } + /*printf("Variable bound ajoute\n");*/ + goto Next1_Il; + } + } + /* Fin borne sup variable */ + + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) { + SecondMembre -= ATrav[il] * UmaxTrav[Var]; + } + else { + NombreDeTermes = 0; + printf("2- Erreur dans la constitution des contraintes de sac a dos TypeBorne %d\n",TypeBorne); + break; + } + } + else { + /* Il faut baisser la variable au min */ + /* S'il y a une borne sup variable on remplace la variable par sa borne sup variable */ + if ( CntDeBorneInfVariable != NULL && 0 ) { + if ( CntDeBorneInfVariable[Var] >= 0 ) { + Cnt1 = CntDeBorneInfVariable[Var]; + i = MdebTrav[Cnt1]; + bBorne = -BTrav[Cnt1]; + SecondMembre -= ATrav[il] * bBorne ; + VarBin = NuvarTrav[i]; + l = ATrav[i]; + /* Peut etre ameliore */ + Found = 0; + for ( i = 0 ; i < NombreDeTermes ; i++ ) { + if ( Variable[i] == VarBin ) { + Found = 1; + Coeff[i] += ATrav[il] * l; + break; + } + } + if ( Found == 0 ) { + Coeff[NombreDeTermes] = ATrav[il] * l; + Variable[NombreDeTermes] = VarBin; + NombreDeTermes++; + } + /*printf("Variable bound ajoute\n");*/ + goto Next1_Il; + } + } + /* Fin borne inf variable */ + + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) { + SecondMembre -= ATrav[il] * UminTrav[Var]; + } + else { + NombreDeTermes = 0; + printf("4- Erreur dans la constitution des contraintes de sac a dos TypeBorne %d\n",TypeBorne); + break; + } + } + Next1_Il: + il++; + } + /* Recherche couverture de sac a dos */ + if ( NombreDeTermes >= MIN_TERMES_POUR_KNAPSACK ) { + /*printf("Recherche Knapsack simple\n");*/ + RendreLesCoeffsEntiers = OUI_PNE; + CouvertureTrouvee = NON_PNE; + PNE_GreedyCoverKnapsack( Pne, 0, NombreDeTermes, Variable, Coeff, SecondMembre, RendreLesCoeffsEntiers, &CouvertureTrouvee, + Mixed_0_1_Knapsack, 0.0, 0, NULL, NULL, NULL ); + if ( CouvertureTrouvee == OUI_PNE ) { + /* + printf(" K trouvee !!!!!!!!!!!!!!\n"); + */ + NbKnapsack++; + } + } + /* Si couverture pas trouvee */ + /* On essaie maintenant de remplacer les variables de cette contrainte par d'autres variables en combinant + les contraintes */ + if ( /*CouvertureTrouvee == NON_PNE &&*/ NbTermTrav[Cnt] >= MIN_TERMES_POUR_KNAPSACK + && KNAPSACK_SUR_COMBINAISONS_DE_CONTRAINTES == OUI_PNE ) { + /* Attention: Coeff et Variable sont detruits dans GreedyCoverKnapsack */ + SecondMembre = BTrav[Cnt]; + NombreDeTermes = 0; + il = ilDeb; + ilMax = ilFin; + while ( il < ilMax ) { + if ( ATrav[il] == 0.0 ) goto Next12_Il; + Var = NuvarTrav[il]; + TypeBorne = TypeDeBorneTrav[Var]; + if ( TypeBorne == VARIABLE_FIXE ) { + SecondMembre -= ATrav[il] * UTrav[Var]; + goto Next12_Il; + } + if ( TypeDeVariableTrav[Var] == ENTIER ) { + Coeff[NombreDeTermes] = ATrav[il]; + Variable[NombreDeTermes] = Var; + NombreDeTermes++; + goto Next12_Il; + } + /* La variable n'est pas entiere */ + if ( ATrav[il] < 0.0 ) { + /* Il faut mettre la variable au max */ + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) { + SecondMembre -= ATrav[il] * UmaxTrav[Var]; + } + else { + NombreDeTermes = 0; + break; + } + } + else { + /* Il faut monter la variable au min */ + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) { + SecondMembre -= ATrav[il] * UminTrav[Var]; + } + else { + NombreDeTermes = 0; + break; + } + } + Next12_Il: + il++; + } + PNE_KnapsackSurCombinaisonsDeContraintes( Pne, Cnt, NombreDeTermes, Variable, Coeff, SecondMembre, + ContrainteDejaUtilisee, VariableSupprimee); + } + + } + if ( Sup == SUP_POSSIBLE ) { + SecondMembre = BTrav[Cnt]; + NombreDeTermes = 0; + il = ilDeb; + ilMax = ilFin; + while ( il < ilMax ) { + if ( ATrav[il] == 0.0 ) goto Next2_Il; + Var = NuvarTrav[il]; + TypeBorne = TypeDeBorneTrav[Var]; + if ( TypeBorne == VARIABLE_FIXE ) { + SecondMembre -= ATrav[il] * UTrav[Var]; + goto Next2_Il; + } + if ( TypeDeVariableTrav[Var] == ENTIER ) { + Coeff[NombreDeTermes] = ATrav[il]; + Variable[NombreDeTermes] = Var; + NombreDeTermes++; + goto Next2_Il; + } + /* La variable n'est pas entiere */ + if ( ATrav[il] < 0.0 ) { + /* Il faut mettre la variable au max */ + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) { + SecondMembre -= ATrav[il] * UminTrav[Var]; + } + else { + NombreDeTermes = 0; + printf("6- Erreur dans la constitution des contraintes de sac a dos TypeBorne %d echec mise au max ATrav %e\n",TypeBorne,ATrav[il]); + break; + } + } + else { + /* Il faut mettre la variable au max */ + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) { + SecondMembre -= ATrav[il] * UmaxTrav[Var]; + } + else { + NombreDeTermes = 0; + printf("8- Erreur dans la constitution des contraintes de sac a dos TypeBorne %d echec mise au max ATrav %e\n",TypeBorne,ATrav[il]); + break; + } + } + Next2_Il: + il++; + } + /* Recherche couverture de sac a dos */ + if ( NombreDeTermes >= MIN_TERMES_POUR_KNAPSACK ) { + SecondMembre *= -1.; + for ( il = 0 ; il < NombreDeTermes ; il++ ) Coeff[il] *= -1.; + RendreLesCoeffsEntiers = OUI_PNE; + CouvertureTrouvee = NON_PNE; + PNE_GreedyCoverKnapsack( Pne, 0, NombreDeTermes, Variable, Coeff, SecondMembre, RendreLesCoeffsEntiers, &CouvertureTrouvee, + Mixed_0_1_Knapsack, 0.0, 0, NULL, NULL, NULL ); + if ( CouvertureTrouvee == OUI_PNE ) { + /*printf(" K trouvee !!!!!!!!!!!!!!\n");*/ + NbKnapsack++; + } + } + } +} +/* +if ( NbKnapsack != 0 || 1 ) printf("CoverKnapsackSimple : %d\n",NbKnapsack); +*/ + +free( ContrainteDejaUtilisee ); +free( VariableSupprimee ); + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_define.h b/src/ext/Sirius_Solver/pne/pne_define.h new file mode 100644 index 0000000000..f7e5436129 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_define.h @@ -0,0 +1,602 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef DEFINITIONS_PNE_FAITES +/*******************************************************************************************/ + +# include "pne_sys.h" +# include "pne_constantes_externes.h" +# include "pne_constantes_internes.h" + +/*******************************************************************************************************/ + +typedef struct{ +int NombreDeContraintesAllouees; +int TailleAlloueePourLaMatriceDesContraintes; +/*----------------------------------------*/ +int NombreDeContraintes; +/* Le second membre des contraintes */ +double * B; /* Le sens est toujours <= */ +char * PositionDeLaVariableDEcart; /* EN_BASE si la contrainte n'est pas saturee + HORS_BASE_SUR_BORNE_INF si elle est saturee */ +char * PositionDeLaVariableDEcartAGauche; /* Pour le strong branching */ +char * PositionDeLaVariableDEcartADroite; /* Pour le strong branching */ +/*----------------------------------------*/ +/* Chainage de la matrice des contraintes */ +int * Mdeb; +int * NbTerm; +int * Nuvar; +double * A; +char * TypeDeCoupe; +} COUPES_DUN_PROBLEME_RELAXE; + +/*******************************************************************************************************/ + +typedef struct{ +char Type; /* 'G' gomory, 'L' lift and project, 'K' knapsack, 'M' Mir */ +int IndexDansCliques; /* -1 si ce n'est pas une clique */ +int IndexDansCoupesDeProbing; /* -1 si ce n'est pas une coupe de probing */ +int IndexDansContraintesDeBorneVariable; /* -1 si ce n'est pas une contrainte de borne variable qui vient du variable probing */ +int IndexDansKNegligees; /* -1 si ce n'est pas une knapsack negligee */ +int IndexDansGNegligees; /* -1 si ce n'est pas une coupe gomry negligee */ +int NumeroDeLaContrainte; /* C'est le numero de la contrainte qui correspond a la coupe dans le probleme relaxe */ +int NombreDeTermes; /* Nombre de coefficients non nuls dans la coupe */ +double * Coefficient; /* Coefficient de la contrainte */ +int * IndiceDeLaVariable; /* Indices des variables qui interviennent dans la coupe */ +double SecondMembre; /* La coupe est toujours dans le sens <= SecondMembre */ +double Distance; /* Distance de la solution courante */ +} COUPE_CALCULEE; + +/*******************************************************************************************************/ +# define VALIDITE_A_DETERMINER 10 /* Pour BminValide et BmaxValide */ +typedef struct { +int Faisabilite; +int VariableInstanciee; +double ValeurDeLaVariableInstanciee; + +/* Zone de travail */ +/* Variables */ +char * BorneInfConnue; +char * BorneSupConnue; +double * ValeurDeBorneInf; +double * ValeurDeBorneSup; +/* Contraintes */ +double * Bmin; +double * Bmax; + +/* Zone de sauvegarde */ +char * BorneInfConnueSv; +char * BorneSupConnueSv; +double * ValeurDeBorneInfSv; +double * ValeurDeBorneSupSv; +double * BminSv; +double * BmaxSv; + +int NbVariablesModifiees; +int * NumeroDeVariableModifiee; +char * VariableModifiee; + +int NbContraintesModifiees; +int * NumeroDeContrainteModifiee; +int * NbFoisContrainteModifiee; + +int NombreDeContraintesAAnalyser; +int NbParcours; + +int IndexCourantContraintesAAnalyser; +int IndexLibreContraintesAAnalyser; + +int SeuilNbTermesMatrice; +int * NumeroDeContrainteAAnalyser; +char * ContrainteAAnalyser; +/*int * IndexContrainteAAnalyser;*/ + +/*int Next_NombreDeContraintesAAnalyser;*/ +/*int * Next_NumeroDeContrainteAAnalyser;*/ +/*int * Next_IndexContrainteAAnalyser;*/ + +char * BminValide; +char * BmaxValide; + +/* Variables fixees */ +int NombreDeVariablesFixees; +int * NumeroDesVariablesFixees; + +/* Pour pouvoir remplacer les contraintes concernees par une leur equivalent en coupe de probing */ +int * NumeroDeCoupeDeProbing; + +int NombreDeVariablesFixeesDansLeProbing; + +int NbCntCoupesDeProbing; +int * NumCntCoupesDeProbing; /* Attention il faudra liberer ca ensuite */ +char * FlagCntCoupesDeProbing; /* Attention il faudra liberer ca ensuite */ + +int NbVarAInstancier; +int * NumVarAInstancier; /* Attention il faudra liberer ca ensuite */ +char * FlagVarAInstancier; /* Attention il faudra liberer ca ensuite */ + +/* Tableaux de travail */ +char * Buffer; /* C'est l'adresse du buffer qu'il faudra liberer */ +} PROBING_OU_NODE_PRESOLVE; + +typedef struct { +int TailleAllouee; +int NbNoeudsDuGraphe; +int Pivot; +int * First; +int * Adjacent; +int * Next; +int NbEdges; +int NbEdgesLast; +char Full; /* OUI_PNE ou NON_PNE */ +int IncrementDAllocation; +} CONFLICT_GRAPH; + +typedef struct { +int NbCliquesAllouees; +int TailleCLiquesAllouee; +int NombreDeCliques; +int * First; +int * NbElements; +int * Noeud; +/* */ +char * LaCliqueEstDansLePool; /* OUI_PNE ou NON_PNE */ +char * CliqueDeTypeEgalite; /* OUI_PNE ou NON_PNE */ +int * NumeroDeCliqueDuNoeud; +/* */ +char Full; /* OUI_PNE ou NON_PNE */ +} CLIQUES; + +typedef struct { +int IndexLibre; +int NombreDeCoupesDeProbingAlloue; +int NombreDeCoupesDeProbing; +double * SecondMembre; +int * First; +int * NbElements; +int TailleCoupesDeProbingAllouee; +int * Colonne; +double * Coefficient; +/* */ +char * LaCoupDeProbingEstDansLePool; /* OUI_PNE ou NON_PNE */ +/* */ +char Full; /* OUI_PNE ou NON_PNE */ +} COUPES_DE_PROBING; + +typedef struct { +int IndexLibre; +int NombreDeContraintesDeBorneAlloue; +int NombreDeContraintesDeBorne; +double * SecondMembre; +int * First; +int TailleContraintesDeBorneAllouee; +int * Colonne; +double * Coefficient; +/* */ +char * LaContrainteDeBorneVariableEstDansLePool; /* OUI_PNE ou NON_PNE */ +/* */ +char Full; /* OUI_PNE ou NON_PNE */ +} CONTRAITES_DE_BORNE_VARIABLE; + +typedef struct { +int IndexLibre; +int NombreDeCoupesAllouees; +int NombreDeCoupes; +double * SecondMembre; +int * First; +int * NbElements; +int TailleCoupesAllouee; +int * Colonne; +double * Coefficient; +/* */ +char * LaCoupeEstDansLePool; /* OUI_PNE ou NON_PNE */ +/* */ +char Full; /* OUI_PNE ou NON_PNE */ +} COUPES_K_NEGLIGEES; + +typedef struct { +int IndexLibre; +int NombreDeCoupesAllouees; +int NombreDeCoupes; +double * SecondMembre; +int * First; +int * NbElements; +int TailleCoupesAllouee; +int * Colonne; +double * Coefficient; +/* */ +char * LaCoupeEstDansLePool; /* OUI_PNE ou NON_PNE */ +/* */ +char Full; /* OUI_PNE ou NON_PNE */ +} COUPES_G_NEGLIGEES; + +typedef struct { + int NombreDeContraintes; + int * IndexDebut; + int * NombreDeTermes; + double * SecondMembre; + char * Sens; + int * Colonne; + double * Coefficient; + /* Pour la base de depart: uniquement pour le clone du simplexe au noeud racine */ + int BaseDeDepartFournie; + double * X; + double * CoutsReduits; + int * PositionDeLaVariable; + int * PositionDeLaVariableSV; + int NbVarDeBaseComplementaires; + int NbVarDeBaseComplementairesSV; + int * ComplementDeLaBase; + int * ComplementDeLaBaseSV; +} MATRICE_DE_CONTRAINTES; + +/*******************************************************************************************************/ +/* Donnees supplementaires pour le pilotage si appele par le branch ans bound lui-meme */ +/* La structure n'existe que dans le cas d'un appel interne. Sinon le pointeur "Controls" est NULL */ +typedef struct { + void * Pne; /* Donne le probleme PNE pere si le probleme courant est lui meme appele par le solveur */ + void * PneFils; /* Donne le probleme PNE fils si le probleme courant est lui meme appele par le solveur */ + void * Presolve; /* Donne le probleme PRESOLVE du PNE fils si le probleme courant est lui meme appele par le solveur */ + int PresolveUniquement; /* OUI_PNE ou NON_PNE */ + int FaireDuVariableProbing; /* OUI_PNE ou NON_PNE */ + int RechercherLesCliques; /* OUI_PNE ou NON_PNE */ +} CONTROLS; + +typedef struct { +/* Pour les outils de gestion memoire */ +void * Tas; + +/*--------------------------------------------*/ +/* Pour le pilotage */ +/* Lorsque le solveur s'appelle lui-meme */ +CONTROLS * Controls; +char FaireHeuristiqueRINS; +char StopHeuristiqueRINS; +int NombreDeSolutionsHeuristiqueRINS; +int NombreDEchecsSuccessifsHeuristiqueRINS; +int NombreDeRefusSuccessifsHeuristiqueRINS; +int NombreDeReactivationsSansSuccesHeuristiqueRINS; + +char FaireHeuristiqueFixation; +char StopHeuristiqueFixation; +int NombreDeSolutionsHeuristiqueFixation; +int NombreDEchecsSuccessifsHeuristiqueFixation; +int NombreDeRefusSuccessifsHeuristiqueFixation; +int NombreDeReactivationsSansSuccesHeuristiqueFixation; + +char FaireHeuristiqueFractionalDive; +char StopHeuristiqueFractionalDive; +int NombreDeSolutionsHeuristiqueFractionalDive; +int NombreDEchecsSuccessifsHeuristiqueFractionalDive; +int NombreDeRefusSuccessifsHeuristiqueFractionalDive; +int NombreDeReactivationsSansSuccesHeuristiqueFractionalDive; + +/* */ +char FaireDuPresolve; +int TempsDExecutionMaximum; /* En secondes */ +char AffichageDesTraces; +int NombreMaxDeSolutionsEntieres; +double ToleranceDOptimalite; + +char SolveurPourLeProblemeRelaxe; + +double DureeDuPremierSimplexe; + +/*--------------------------------------------*/ + +int * CorrespondanceVarEntreeVarNouvelle; +char * VariableAInverser; + +/* Variables eliminees dont il faut recalculer la valeur */ +int NombreDeVariablesElimineesSansValeur; +int * VariableElimineeSansValeur; + +int NombreDeVariablesTrav; +int NombreDeVariablesNonFixes; +int * NumeroDesVariablesNonFixes; +int NombreDeVariablesEntieresNonFixes; +char YaQueDesVariablesEntieres; /* OUI_PNE ou NON_PNE */ +int NombreDeVariablesEntieresTrav; +int * NumerosDesVariablesEntieresTrav; +int * TypeDeVariableTrav; +double * SeuilDeFractionnalite; /* On pourrait compacter les variables entieres plutot que d'utiliser TypeDeVariableTrav et SeuilDeFractionnalite en parallele */ +char * VariableBinaireBigM; /* Vaut OUI_PNE ou NON_PNE */ +int * TypeDeBorneTrav; +int * TypeDeBorneTravSv; + +double * UTrav; +double * S1Trav; +double * S2Trav; +double * UmaxTrav; +double * UmaxTravSv; +double * UminTrav; +double * UminTravSv; +double * UmaxEntree; +double * UminEntree; +double * LTrav; +double * CoutsReduits; +/*----------------------------------*/ +/* Pour le reduced cost fixing */ +double CritereAuNoeudRacine; +double MxCoutReduitAuNoeudRacineFoisDeltaBornes; +double * CoutsReduitsAuNoeudRacine; +int * PositionDeLaVariableAuNoeudRacine; + +/* +int NombreDeVariablesHorsBase; +int * NumeroDeVariableCoutReduit; +double * CoutsReduitsAuNoeudRacineFoisDeltaBornes; +*/ +/*----------------------------------*/ +int NombreDeContraintesTrav; +int NombreDeContraintesDInegalite; +/*----------------------------------*/ +/* Le second membre des contraintes */ +double * BTrav; +char * SensContrainteTrav; +int * ContrainteSaturee; +char * ContrainteActivable; /* Utilisables que si presence de variables entieres OUI_PNE ou NON_PNE */ +/*----------------------------------*/ +/* Utilise dans le presolve */ +double PlusGrandTerme; +double PlusPetitTerme; +/*----------------------------------*/ +int * CorrespondanceCntPneCntEntree; +/* En resultat les variables duales des contraintes */ +double * VariablesDualesDesContraintesTrav; +double * VariablesDualesDesContraintesTravEtDesCoupes; +int TailleAlloueeVariablesDualesDesContraintesTravEtDesCoupes; +/*----------------------------------------*/ +/* Chainage de la matrice des contraintes */ +int * MdebTrav; +int * NbTermTrav; +int * NuvarTrav; +double * ATrav; +/*---------------------------------------------------------*/ +int NombreDeGub; +int * NumeroDeContrainteDeLaGub; +int * ValeurDInstanciationPourLaGub; +/*---------------------------------------------------------*/ +/* Chainage de la transposee de la matrice des contraintes */ +char ChainageTransposeeExploitable; /* OUI_PNE ou NON_PNE */ +int * CdebTrav; +int * CNbTermTrav; +int * CsuiTrav; +int * NumContrainteTrav; +/*---------------------------------------------------------*/ +/* Tailles allouees */ +int NombreDeVariablesAllouees; +int NombreDeContraintesAllouees; +int TailleAlloueePourLaMatriceDesContraintes; +/*---------------------------------------------------------*/ + +int VariableLaPlusFractionnaire; +/* Pour faire des branchements de type Gub */ +int DimBranchementGub; +int ValeurAGauche; +int NbVarGauche; +int * PaquetDeGauche; +int ValeurADroite; +int NbVarDroite; +int * PaquetDeDroite; +/* */ +int NumeroDeLaVariableFractionnaire; +int LaContrainteDisjointQuelqueChose; + +int NombreDeVariablesAValeurFractionnaire; +int * LaVariableAUneValeurFractionnaire; +double NormeDeFractionnalite; + +int PremFrac; /* Pour le classement des variables entieres dont */ +int * SuivFrac; /* la valeur est fractionnaire */ + +/*-----------------------------------*/ +/* Pour le strong branching */ +char FaireDuStrongBranching; /* Vaut OUI_PNE ou NON_PNE */ +double * UStrongBranching; + +/*-----------------------------------*/ +/* Pour les coupes */ +COUPES_DUN_PROBLEME_RELAXE Coupes; + +char ResolutionDuNoeudReussie; +int NombreDeCoupesCalculees; /* Nombre de coupes calculees au probleme courant */ +int NombreDeCoupesCalculeesNonEvaluees; /* C'est le nombre de coupes qui a ete calcule apres resolution du noeud */ +int NombreDeCoupesAjouteesAuRoundPrecedent; +double DernierTauxParCoupe; +double DbleNbIterLim; + +int NbGDuCycle; +int NbIDuCycle; +int NbKDuCycle; +int NbGInsere; +int NbIInsere; +int NbKInsere; +COUPE_CALCULEE ** CoupesCalculees; /* Pointeur sur les coupes calculees au probleme courant */ + +int NombreDeK; +double SommeViolationsK; +double SeuilDeViolationK; + +int NombreDeMIR_MARCHAND_WOLSEY; +double SommeViolationsMIR_MARCHAND_WOLSEY; +double SeuilDeViolationMIR_MARCHAND_WOLSEY; + +int NombreDeCliques; +double SommeViolationsCliques; +double SeuilDeViolationCliques; + +int NombreDImplications; +double SommeViolationsImplications; +double SeuilDeViolationImplications; + +int NombreDeBornesVariables; +double SommeViolationsBornesVariables; +double SeuilDeViolationBornesVariables; + +int NombreDeCoupesAjoute; + +double * Coefficient_CG; +int * IndiceDeLaVariable_CG; + +double * ValeurLocale; /* Dimension nombre de variable et dont la validite n'est garantie que localement */ +int * IndiceLocal; /* Dimension nombre de variable et dont la validite n'est garantie que localement */ + +char * ContrainteKnapsack; + +int * CntDeBorneSupVariable; /* Pour chaque variable, numero de la contrainte qui decrit la borne variable */ + /* Vaut -1 si pas de borne variable */ +int * CntDeBorneInfVariable; +char * ContrainteMixte; +char CalculDeMIRmarchandWolsey; +int NbEvitementsDeCalculsMIRmarchandWolsey; +int NbEchecsConsecutifsDeCalculsMIRmarchandWolsey; +int ProfondeurMirMarchandWolseTrouvees; +int * FoisCntSuccesMirMarchandWolseyTrouvees; + +/*-----------------------------------*/ + +double ValeurOptimaleDuProblemeCourantAvantNouvellesCoupes; + +/*-----------------------------------*/ + +char YaDesVariablesEntieres; /* Vaut OUI_PNE ou NON_PNE */ +char YaDesBigM; /* Vaut OUI_PNE ou NON_PNE */ +int CestTermine; +int YaUneSolution; /* Vaut OUI_PNE ou NON_PNE */ +int YaUneSolutionEntiere; /* Vaut OUI_PNE ou NON_PNE */ +double CoutOpt; /* Cout de la solution entiere stockee */ +double Z0; +double * UOpt; /* Vecteur contenant la solution optimale */ +int NumeroDeLaContrainteDeCoutMax; +int NumeroDeLaVariableDEcartPourCoutMax; + +/*-----------------------------------*/ + +int PremierIndexLibre; /* Premier index que l'on peut utiliser dans la matrice + des contraintes */ + +/*-------------------------------------------------------------------------*/ + +PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; +CONFLICT_GRAPH * ConflictGraph; +CLIQUES * Cliques; +COUPES_DE_PROBING * CoupesDeProbing; +CONTRAITES_DE_BORNE_VARIABLE * ContraintesDeBorneVariable; +time_t HeureDeCalendrierDebutCliquesEtProbing; +time_t HeureDeCalendrierCourantCliquesEtProbing; +double TempsEcoule; +char ArreterCliquesEtProbing; + +/*-------------------------------------------------------------------------*/ + +COUPES_K_NEGLIGEES * CoupesKNegligees; +COUPES_G_NEGLIGEES * CoupesGNegligees; + +/*-------------------------------------------------------------------------*/ +/* Informations utiles pour les operations de postsovle */ + +int NombreDOperationsDePresolve; +int TailleTypeDOperationDePresolve; +char * TypeDOperationDePresolve; +int * IndexDansLeTypeDOperationDePresolve; + +/*-------------------------------------------------------------------------*/ +/* Ceci est a affiner. Ce sont des vecteurs qui permettent de retrouver les + variables qui ont ete substituees dans le presolve. Dans un premier temps + on reserve une place equivalente a la taille de la matrice puis une fois + qu'on a fini on fait un realloc pour recuperer de la place */ + +int IndexLibreVecteurDeSubstitution; +int NbVariablesSubstituees; +int * NumeroDesVariablesSubstituees; +double * CoutDesVariablesSubstituees; /* Je pense qu'on peut s'en passer */ +int * ContrainteDeLaSubstitution; +double * ValeurDeLaConstanteDeSubstitution; +int * IndiceDebutVecteurDeSubstitution; +int * NbTermesVecteurDeSubstitution; +double * CoeffDeSubstitution; +int * NumeroDeVariableDeSubstitution; + +/* Cas des colonnes colineaires qui correspondent a des variables de cout identique. + Dans le presolve on cree cree une variable equivalente combinaison lineaire + des vraibles concernees: nouvelle variable = variable1 + ValeurDeNu * variable 2. + En sortie il faut retrouver la valeur de chacune de ces variables. */ +int NbCouplesDeVariablesColineaires; +int * PremiereVariable; +double * XminPremiereVariable; +double * XmaxPremiereVariable; + +int * DeuxiemeVariable; +double * XminDeuxiemeVariable; +double * XmaxDeuxiemeVariable; + +double * ValeurDeNu; + +/* Cas des ligne singleton: il faut pouvoir restituer la valeur de la variable duale + de la contrainte */ +int NbLignesSingleton; +int * NumeroDeLaContrainteSingleton; +int * VariableDeLaContrainteSingleton; +double * SecondMembreDeLaContrainteSingleton; + +/* Cas des forcing constraints: il faut pouvoir restituer la valeur de la variable duale + de la contrainte */ +int NbForcingConstraints; +int * NumeroDeLaForcingConstraint; + +/* Cas des contraintes colineaires : il faut pouvoir restituer la valeur de la variable duale + de la contrainte */ +int NbSuppressionsDeContraintesColineaires; +int * ContrainteConservee; +int * ContrainteSupprimee; + +/* Contraintes inactives */ +int NombreDeContraintesInactives; +int * NumeroDesContraintesInactives; + +/*-------------------------------------------------------------------------*/ + +char PrioriteDansSpxAuxVariablesSortantesEntieres; /* OUI_PNE ou NON_PNE */ +void * ProblemeSpxDuSolveur; +void * ProblemeSpxDuNoeudRacine; +MATRICE_DE_CONTRAINTES * MatriceDesContraintesAuNoeudRacine; +void * ProblemeBbDuSolveur; +void * ProblemePrsDuSolveur; + +/* Pour les temps */ +time_t HeureDeCalendrierDebut; +time_t HeureDeCalendrierCourant; + +/*-------------------------------------------------------------------------*/ +int AnomalieDetectee; +jmp_buf Env; +/*-------------------------------------------------------------------------*/ + +double Critere; + +} PROBLEME_PNE; + +/*******************************************************************************************/ +# define DEFINITIONS_PNE_FAITES +# endif +# ifdef __cplusplus + } +# endif diff --git a/src/ext/Sirius_Solver/pne/pne_definition_arguments.h b/src/ext/Sirius_Solver/pne/pne_definition_arguments.h new file mode 100644 index 0000000000..ac5656f4b9 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_definition_arguments.h @@ -0,0 +1,150 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef PROBLEME_DEJA_DEFINI +/*******************************************************************************************/ +/* + Le passage des informations a la routine de resolution du probleme se fait par un pointeur + a la structure C definie ci-apres. + + Le fichier pne_definition_arguments.h doit etre inclus dans le code de l'appelant, + il contient la definition de la structure C exploitee par la fonction. + Apres avoir renseigne les champs, le module utilisateur appelle la fonction + PNE_Solveur avec, pour argument d'appel, un pointeur a la structure ci-dessous. + + Exemple d'utilisation : + + PROBLEME_A_RESOUDRE Mon_Probleme; <- definition d'une structure "Mon_Probleme" de type PROBLEME_A_RESOUDRE + ....... + ....... + Remplissage des champs de la structure + ....... + ....... + ....... + Appel de la fonction: + + PNE_Solveur( &Mon_Probleme ); + +*/ + +typedef struct { + + int NombreDeVariables; /* Nombre de variables */ + int * TypeDeVariable ; /* ENTIER ou REEL attention dans le cas des variables entieres, le seul cas traite + est celui des variables {0,1} */ + int * TypeDeBorneDeLaVariable; /* Indicateur du type de variable, il ne doit prendre que les suivantes + (voir le fichier pne_constantes_externes.h mais ne jamais utiliser les + valeurs explicites des constantes): + VARIABLE_FIXE , + VARIABLE_BORNEE_DES_DEUX_COTES , + VARIABLE_BORNEE_INFERIEUREMENT , + VARIABLE_BORNEE_SUPERIEUREMENT , + VARIABLE_NON_BORNEE + */ + double * X ; /* Vecteur des inconnues: en sortie, il contient la solution s'il y en a une */ + double * Xmax ; /* Borne sup de chaque inconnue */ + double * Xmin ; /* Borne inf de chaque inconnue */ + double * CoutLineaire ; /* Vecteur des couts lineaires */ + /* Description des contraintes */ + int NombreDeContraintes; /* Nombre de contraintes */ + double * SecondMembre ; /* Vecteur des second membres */ + char * Sens ; /* Sens de chaque contrainte : + pour une contraintes de type inferieur ou egal mettre le caractere '<' + pour une contraintes de type superieur ou egal mettre le caractere '>' + pour une contrainte d'egalite mettre le caractere "=" */ + +/* +La matrice des contrainte est decrite par les 4 vecteurs qui suivent. Elle doit etre decrite par ligne. + -> Les coefficients de la matrice des contraintes doivent etre donnes dans un vecteur double precision. + -> En parallele du vecteur des coefficient, il faut donner l'indice colonne du coefficient. + -> Pour chaque ligne (ou premier membre de la contrainte) il faut donner sont indice début dans le vecteur + double precision qui contient les coefficients de la contraintes, et le nombre de coefficients non nuls. +*/ + int * IndicesDebutDeLigne ; /* Pour chaque ligne, indice debut de la ligne dans le + vecteur des coefficients */ + int * NombreDeTermesDesLignes ; /* Nombre de termes non nuls de la ligne */ + double * CoefficientsDeLaMatriceDesContraintes ; /* Coefficients de la matrice des contraintes */ + int * IndicesColonnes ; /* Vecteur parallele au precedent. Il contient l'indice + colonne de chaque coefficient */ + + /* En retour */ + double * VariablesDualesDesContraintes; /* Pointeur sur un vecteur dans lequel le solveur va mettre + les variables duales des contraintes. Attention, ce tableau + doit etre alloue par l'appelant */ + + int ExistenceDUneSolution; /* Indicateur d'existence de solution. Valeurs possible: + -> PAS_DE_SOLUTION_TROUVEE + -> SOLUTION_OPTIMALE_TROUVEE + -> SOLUTION_OPTIMALE_TROUVEE_MAIS_QUELQUES_CONTRAINTES_SONT_VIOLEES + -> PROBLEME_INFAISABLE + -> PROBLEME_NON_BORNE + -> ARRET_PAR_LIMITE_DE_TEMPS_AVEC_SOLUTION_ADMISSIBLE_DISPONIBLE + -> ARRET_CAR_ERREUR_INTERNE (saturation memoire par exemple) + */ + /* Options */ + char AlgorithmeDeResolution; /* Doit valoir SIMPLEXE ou POINT_INTERIEUR */ + /* Attention, le choix POINT_INTERIEUR ne peut ętre utilise que dans le cas + d'un probleme ne comportant pas de varaibles entieres */ + char AffichageDesTraces; /* Peut valoir OUI_PNE ou NON_PNE */ + char SortirLesDonneesDuProbleme; /* Peut valoir OUI_PNE ou NON_PNE. + Mettre OUI_PNE pour sortir les donnees du probleme dans un fichier au format mps */ + char FaireDuPresolve; /* Peut valoir OUI_PNE ou NON_PNE */ + /* La valeur hautement conseillee est OUI_PNE */ + int TempsDExecutionMaximum; /* Temps (en secondes) au bout duquel la resolution du probleme est arretee meme si la + solution optimale n'a pas ete trouvee. Attention, cette grandeur n'est prise en compte + que si le probleme contient des variables entieres */ + /* Mettre 0 si le temps est illimite */ + int NombreMaxDeSolutionsEntieres; /* Lorsque le nombre de solutions entieres est egal ŕ la valeur de ce + parametre, le solveur s'arrete et donne la meilleure solution rencontree. + Remarque: mettre une valeur strictement negative pour que ce parametre n'ai pas + de rôle. + */ + double ToleranceDOptimalite; /* Si l'écart relatif entre le cout de la solution entiere trouvee et le plus petit minorant + est inférieur ŕ ToleranceDOptimalite, le solveur s'arrete et considčre que la solution + entiere trouvee est la solution optimale. + Convention: ToleranceDOptimalite doit etre exprimé en %. + Conseil : mettre 0 %. + */ + char CoupesLiftAndProject; /* Utile que s'il y a des variables entieres dans le probleme. + Peut valoir OUI_PNE ou NON_PNE. Lorsque cette option vaut OUI_PNE + le calcul des coupes de type lift and project est activé. + - Choix conseillé: NON_PNE car le calcul de ce type de coupe peut ętre + couteux. + - Mettre OUI_PNE si le probleme est difficile a resoudre. + */ +} PROBLEME_A_RESOUDRE; + + +/* Prototype du la fonction d'entree */ +void PNE_Solveur( PROBLEME_A_RESOUDRE * ); + +/*******************************************************************************************/ +# define PROBLEME_DEJA_DEFINI +# endif +# ifdef __cplusplus + } +# endif + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_detection_des_contraintes_mixtes.c b/src/ext/Sirius_Solver/pne/pne_detection_des_contraintes_mixtes.c new file mode 100644 index 0000000000..3ed5ce1e3e --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_detection_des_contraintes_mixtes.c @@ -0,0 +1,122 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Marquage des contraintes mixtes sur lesquelles on peut + faire des MIR. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define ZERO_COEFF 1.e-8 + +/*----------------------------------------------------------------------------*/ + +void PNE_DetecterLesContraintesMixtes( PROBLEME_PNE * Pne ) +{ +int Cnt; int NbCont; int NbBin; int il; int ilMax; int Var; char YaDesContraintesMixtes; +int * MdebTrav; int * NbTermTrav; int * NuvarTrav; int * TypeDeBorneTrav; double * ATrav; +int * TypeDeVariableTrav; char * ContrainteMixte; char * SensContrainteTrav; double * BTrav; +int * CntDeBorneSupVariable; int * CntDeBorneInfVariable; int NbBinPotentiel; double Ai; +int * FoisCntSuccesMirMarchandWolseyTrouvees; + +if ( Pne->ContrainteMixte == NULL ) { + Pne->ContrainteMixte = (char *) malloc( Pne->NombreDeContraintesTrav * sizeof( char ) ); + if ( Pne->ContrainteMixte == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AnalyseInitialeDesBornesVariables \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} +if ( Pne->FoisCntSuccesMirMarchandWolseyTrouvees == NULL ) { + Pne->FoisCntSuccesMirMarchandWolseyTrouvees = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); + if ( Pne->FoisCntSuccesMirMarchandWolseyTrouvees == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_AnalyseInitialeDesBornesVariables \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} + +CntDeBorneSupVariable = Pne->CntDeBorneSupVariable; +CntDeBorneInfVariable = Pne->CntDeBorneInfVariable; + +BTrav = Pne->BTrav; +SensContrainteTrav = Pne->SensContrainteTrav; +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; +ATrav = Pne->ATrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; + +YaDesContraintesMixtes = NON_PNE; +ContrainteMixte = Pne->ContrainteMixte; +FoisCntSuccesMirMarchandWolseyTrouvees = Pne->FoisCntSuccesMirMarchandWolseyTrouvees; + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + ContrainteMixte[Cnt] = NON_PNE; + FoisCntSuccesMirMarchandWolseyTrouvees[Cnt] = 0; + /* Ne pas compter les contraintes de bornes variables */ + if ( NbTermTrav[Cnt] <= 1 ) continue; + if ( SensContrainteTrav[Cnt] == '<' && NbTermTrav[Cnt] == 2 && BTrav[Cnt] == 0.0 ) continue; + NbCont = 0; + /*if ( SensContrainteTrav[Cnt] == '<' ) NbCont++;*/ + NbBin = 0; + NbBinPotentiel = 0; + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var = NuvarTrav[il]; + Ai = fabs( ATrav[il] ); + if ( Ai > ZERO_COEFF ) { + if ( TypeDeBorneTrav[Var] != VARIABLE_FIXE ) { + if ( TypeDeVariableTrav[Var] == ENTIER ) NbBin++; + else { + NbCont++; + if ( CntDeBorneSupVariable != NULL && CntDeBorneInfVariable != NULL ) { + if ( CntDeBorneSupVariable[Var] >= 0 ) NbBinPotentiel++; + else if ( CntDeBorneInfVariable[Var] >= 0 ) NbBinPotentiel++; + } + } + } + } + il++; + } + if ( NbCont > 0 && ( NbBin > 0 || NbBinPotentiel > 0 ) ) { + YaDesContraintesMixtes = OUI_PNE; + ContrainteMixte[Cnt] = OUI_PNE; + } +} +if ( YaDesContraintesMixtes == NON_PNE ) { + free( Pne->ContrainteMixte ); + Pne->ContrainteMixte = NULL; + free( Pne->FoisCntSuccesMirMarchandWolseyTrouvees ); + Pne->FoisCntSuccesMirMarchandWolseyTrouvees = NULL; +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_detection_des_gub.c b/src/ext/Sirius_Solver/pne/pne_detection_des_gub.c new file mode 100644 index 0000000000..a995f9a1ed --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_detection_des_gub.c @@ -0,0 +1,131 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Detection de GUB (General Upper Bound constraints). + Type de GUB detectees: + - Somme de Xi <= 1 ou Somme de Xi = 1. Dans le cas de l'inegalite + il y a au plus une variable egale a 1. Dans le cas de l'egalite + il y a une variable egale a 1. + Pour ce type de GUB la valeur d'instanciation du groupe de + variable choisi est 0. + - Somme de Xi = N-1 ou n est le nombre de variables entieres + de la contrainte. Dans ce cas toutes les variables sont egales + a 1 sauf une qui vaut 0. + Pour ce type de GUB la valeur d'instanciation du groupe de + variables est 1. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "prs_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void PNE_DetecterLesGub( PROBLEME_PNE * Pne ) +{ +int Cnt; int il; int ilMax; char Gub; int N; int NombreDeGub; int NombreDeContraintes; +int * NbTerm; int * Mdeb; double * B; int * Nuvar; int * TypeDeVariable; int NbNonFix; +double * A; int * NumeroDeContrainteDeLaGub; char * SensContrainte; int Var; +char OnInverse; int Valeur; int * ValeurDInstanciationPourLaGub; int * TypeDeBorne; + +# if UTILISER_LES_GUB == NON_PNE + Pne->NombreDeGub = 0; + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Will not branch on GUB constraints\n"); + } + return; +# endif + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +NbTerm = Pne->NbTermTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +B = Pne->BTrav; +SensContrainte = Pne->SensContrainteTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +NumeroDeContrainteDeLaGub = Pne->NumeroDeContrainteDeLaGub; +ValeurDInstanciationPourLaGub = Pne->ValeurDInstanciationPourLaGub; +TypeDeBorne = Pne->TypeDeBorneTrav; + +NombreDeGub = 0; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + + if ( SensContrainte[Cnt] != '=' ) continue; + + N = NbTerm[Cnt]; + if ( N < MIN_TERMES_GUB ) continue; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + NbNonFix = 0; + Gub = OUI_PNE; + if ( B[Cnt] != 1.0 && B[Cnt] != N - 1 ) continue; + if ( B[Cnt] == N - 1 && SensContrainte[Cnt] != '=' ) continue; + if ( B[Cnt] == 1.0 ) Valeur = 0; + else Valeur = 1; + while ( il < ilMax ) { + Var = Nuvar[il]; + if ( TypeDeBorne[Var] != VARIABLE_FIXE ) NbNonFix++; + if ( TypeDeVariable[Var] != ENTIER || A[il] != 1.0 ) { + Gub = NON_PNE; + break; + } + il++; + } + if ( Gub == OUI_PNE && NbNonFix >= MIN_TERMES_GUB ) { + NumeroDeContrainteDeLaGub[NombreDeGub] = Cnt; + ValeurDInstanciationPourLaGub[NombreDeGub] = Valeur; + NombreDeGub++; + } +} + +/* Classement des Gub dans l'ordre decroissant du nombre de termes. Afin de couvrir le plus grand nombre de termes d'une + knapsack avec le moins grand nombre de GUB */ +OnInverse = OUI_PNE; +while ( OnInverse == OUI_PNE ) { + OnInverse = NON_PNE; + for ( Cnt = 0 ; Cnt < NombreDeGub - 1 ; Cnt++ ) { + if ( NbTerm[NumeroDeContrainteDeLaGub[Cnt]] < + NbTerm[NumeroDeContrainteDeLaGub[Cnt+1]] ) { + OnInverse = OUI_PNE; + il = NumeroDeContrainteDeLaGub[Cnt+1]; + NumeroDeContrainteDeLaGub[Cnt+1] = NumeroDeContrainteDeLaGub[Cnt]; + NumeroDeContrainteDeLaGub[Cnt] = il; + } + } +} + +Pne->NombreDeGub = NombreDeGub; + +/* Pour recuperer de la place */ +Pne->NumeroDeContrainteDeLaGub = (int *) realloc( Pne->NumeroDeContrainteDeLaGub , Pne->NombreDeGub * sizeof( int ) ); +Pne->ValeurDInstanciationPourLaGub = (int *) realloc( Pne->ValeurDInstanciationPourLaGub, Pne->NombreDeGub * sizeof( int ) ); + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("%d GUB constraints found (native)\n",Pne->NombreDeGub); +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_detection_des_variables_big_M.c b/src/ext/Sirius_Solver/pne/pne_detection_des_variables_big_M.c new file mode 100644 index 0000000000..46f483755a --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_detection_des_variables_big_M.c @@ -0,0 +1,108 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Marquage des contraintes mixtes sur lesquelles on peut + faire des MIR. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define Ai_BIG_M 1.e+4 +# define RAPPORT_BIG_M 5. + +/*----------------------------------------------------------------------------*/ + +void PNE_DetecterLesVariablesBigM( PROBLEME_PNE * Pne ) +{ +int Cnt; int il; int ilMax; int Var; int Var1; int ic; int * MdebTrav; +int * NbTermTrav; int * NuvarTrav; int * TypeDeBorneTrav; double * ATrav; +int * TypeDeVariableTrav; double AmaxCont; double Ai; char * VariableBinaireBigM; +int * CdebTrav; int * CsuiTrav; int * NumContrainteTrav; double Abin; + +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; +ATrav = Pne->ATrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; + +VariableBinaireBigM = Pne->VariableBinaireBigM; + +if ( Pne->ChainageTransposeeExploitable == NON_PNE ) PNE_ConstruireLeChainageDeLaTransposee( Pne ); + +CdebTrav = Pne->CdebTrav; +CsuiTrav = Pne->CsuiTrav; +NumContrainteTrav = Pne->NumContrainteTrav; + +Pne->YaDesBigM = NON_PNE; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) VariableBinaireBigM[Var] = NON_PNE; + +/* Le critere de detection des Big M se fait en analysant les rapports des coefficients dans les contraintes */ + +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( TypeDeVariableTrav[Var] != ENTIER ) continue; + if ( TypeDeBorneTrav[Var] == VARIABLE_FIXE ) continue; + ic = CdebTrav[Var]; + while ( ic >= 0 ) { + Cnt = NumContrainteTrav[ic]; + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + Abin = 0.; + AmaxCont = -1.; + while ( il < ilMax ) { + Var1 = NuvarTrav[il]; + Ai = fabs( ATrav[il] ); + if ( Var1 == Var ) { + if ( Ai < Ai_BIG_M ) goto NextIc; + Abin = Ai; + } + else { + if ( TypeDeBorneTrav[Var1] == VARIABLE_FIXE ) goto NextIl; + if ( Ai > AmaxCont ) AmaxCont = Ai; + } + NextIl: + il++; + } + if ( AmaxCont <= 0.0 ) goto NextIc; + if ( fabs( Abin / AmaxCont ) < RAPPORT_BIG_M ) goto NextIc; + Pne->YaDesBigM = OUI_PNE; + VariableBinaireBigM[Var] = OUI_PNE; + break; + } + NextIc: + ic = CsuiTrav[ic]; +} + +if ( Pne->YaDesBigM == OUI_PNE ) { + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Big M detected for integer variables\n"); + } +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_determiner_les_variables_fractionnaires.c b/src/ext/Sirius_Solver/pne/pne_determiner_les_variables_fractionnaires.c new file mode 100644 index 0000000000..7453e948f8 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_determiner_les_variables_fractionnaires.c @@ -0,0 +1,266 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Determination des variables a valeur fractionnaire + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# define UTILISER_LES_POIDS_DU_SIMPLEXE NON_PNE + +void PNE_ClasserLesVariableFractionnairesSteepestEdge( PROBLEME_PNE * , int , double , double * ); + +/*----------------------------------------------------------------------------*/ + +void PNE_DeterminerLesVariablesFractionnaires( PROBLEME_PNE * Pne, int * PositionDeLaVariable ) +{ +int Var; int LaValeurEstEntiere; double Sigma; double U1; double U2; double UTrav; +double Milieu; double Moyenne; double ValeurDeFractionnaliteNulle; +# if UTILISER_LES_POIDS_DU_SIMPLEXE == OUI_PNE + PROBLEME_SPX * Spx; double * ScaleX; int * CorrespondanceVarEntreeVarSimplexe; + int * ContrainteDeLaVariableEnBase; int VarSpx; int CntSpx; double * DualPoids; + double * Fractionnalite; double Frac; +# endif + +# if UTILISER_LES_POIDS_DU_SIMPLEXE == OUI_PNE + Spx = NULL; + if ( Pne->ProblemeSpxDuSolveur != NULL ) { + Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur; + } + else { + printf("Bug dans PNE_DeterminerLesVariablesFractionnaires. On ne dispose pas du probleme Simplexe associe au probleme en nombres entiers etudie\n"); + } + ScaleX = Spx->ScaleX; + CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; + ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; + DualPoids = Spx->DualPoids; + Fractionnalite = Pne->UStrongBranching; +# endif + +Pne->CestTermine = OUI_PNE; +Pne->VariableLaPlusFractionnaire = -1; +Milieu = 0.5; +Pne->NombreDeVariablesAValeurFractionnaire = 0; +Pne->NormeDeFractionnalite = 0.0; +Pne->PremFrac = -1; + +Moyenne = 0.0; +Sigma = 0.0; + +ValeurDeFractionnaliteNulle = VALEUR_DE_FRACTIONNALITE_NULLE; + +/* Verification des valeurs entieres et choix de branchement. Pour finioler on peut boucler sur les seules variables entieres + car il y existe maintenant une liste de ces variables. On peut acceder au type de variable par TypeDeVariable. Ceci dit + il n'y a pas grande difference. */ +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + Pne->LaVariableAUneValeurFractionnaire[Var] = NON_PNE; + if ( Pne->UminTrav[Var] == Pne->UmaxTrav[Var] ) continue; + if ( Pne->TypeDeVariableTrav[Var] == ENTIER && Pne->TypeDeBorneTrav[Var] != VARIABLE_FIXE ) { + LaValeurEstEntiere = OUI_PNE; + UTrav = Pne->UTrav[Var]; + ValeurDeFractionnaliteNulle = Pne->SeuilDeFractionnalite[Var]; + if ( Pne->SolveurPourLeProblemeRelaxe == SIMPLEXE ) { + /* Si la variable est basique sa valeur est potentiellement fractionnaire */ + if ( PositionDeLaVariable[Var] == EN_BASE ) { + /* Ceci permet de resserer la tolerance */ + U1 = UTrav - floor( UTrav ); + U2 = ceil( UTrav ) - UTrav; + if( U1 > ValeurDeFractionnaliteNulle && U2 > ValeurDeFractionnaliteNulle ) { + /* + if ( U1 < U2 ) printf("%d ValeurDeFractionnaliteNulle %e fractionnalite %e \n",Var,ValeurDeFractionnaliteNulle,U1); + else printf("%d ValeurDeFractionnaliteNulle %10.17e fractionnalite %10.17e \n",Var,ValeurDeFractionnaliteNulle,U2); + */ + Pne->CestTermine = NON_PNE; + LaValeurEstEntiere = NON_PNE; + Pne->LaVariableAUneValeurFractionnaire[Var] = OUI_PNE; + Pne->NombreDeVariablesAValeurFractionnaire++; + if ( U1 < U2 ) { + Pne->NormeDeFractionnalite+= U1; + Sigma+= U1 * U1; + } + else { + Pne->NormeDeFractionnalite+= U2; + Sigma+= U2 * U2; + } + + # if UTILISER_LES_POIDS_DU_SIMPLEXE == OUI_PNE + /* Avant classement on prend en compte les poids du steepest edge */ + VarSpx = CorrespondanceVarEntreeVarSimplexe[Var]; + if ( VarSpx < 0 ) printf("Bug dans PNE_DeterminerLesVariablesFractionnaires. Table Spx->CorrespondanceVarEntreeVarSimplexe fausse.\n"); + CntSpx = ContrainteDeLaVariableEnBase[VarSpx]; + if ( CntSpx < 0 ) printf("Bug dans PNE_DeterminerLesVariablesFractionnaires. Table Spx->ContrainteDeLaVariableEnBase fausse.\n"); + /* On scale pour se ramener au simplexe et on applique les poids du steepest edge */ + U1 = U1 / ScaleX[VarSpx]; U1 = U1 * U1 / DualPoids[CntSpx]; + U2 = U2 / ScaleX[VarSpx]; U2 = U2 * U2 / DualPoids[CntSpx]; + Frac = U1; + if ( U1 < U2 ) Frac = U2; + PNE_ClasserLesVariableFractionnairesSteepestEdge( Pne, Var, Frac, Fractionnalite ); + # else + /* Classement de la variable en fonction de sa position par rapport au milieu */ + PNE_ClasserLesVariableFractionnaires( Pne, Var, Milieu ); + # endif + + } + } + } + else if( fabs( UTrav - floor( UTrav ) ) > ValeurDeFractionnaliteNulle && fabs( UTrav - ceil ( UTrav ) ) > ValeurDeFractionnaliteNulle ) { + Pne->CestTermine = NON_PNE; + LaValeurEstEntiere = NON_PNE; + Pne->LaVariableAUneValeurFractionnaire[Var] = OUI_PNE; + Pne->NombreDeVariablesAValeurFractionnaire++; + PNE_ClasserLesVariableFractionnaires( Pne, Var, Milieu ); + } + } +} + +Pne->VariableLaPlusFractionnaire = Pne->PremFrac; + +#if VERBOSE_PNE + printf(" Nombre de variables a valeur fractionnaire: %d \n",Pne->NombreDeVariablesAValeurFractionnaire); fflush(stdout); +#endif + /* + { + BB * Bb; + Bb = (BB *) Pne->ProblemeBbDuSolveur; + printf(" Nombre de variables a valeur fractionnaire: %d profondeur du noeud: %d\n", + Pne->NombreDeVariablesAValeurFractionnaire, + Bb->NoeudEnExamen->ProfondeurDuNoeud); + } + */ + +/* Si on a trouve une solution entiere, on place les valeurs optimales des variables entieres sur la bonne borne + pour ne pas avoir de probleme par la suite */ +if ( Pne->NombreDeVariablesAValeurFractionnaire == 0 ) { + for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Pne->TypeDeVariableTrav[Var] == ENTIER && Pne->TypeDeBorneTrav[Var] != VARIABLE_FIXE ) { + U1 = fabs( Pne->UmaxTrav[Var] - Pne->UTrav[Var] ); + U2 = fabs( Pne->UTrav[Var] - Pne->UminTrav[Var] ); + if ( U1 < U2 ) Pne->UTrav[Var] = Pne->UmaxTrav[Var]; + else Pne->UTrav[Var] = Pne->UminTrav[Var]; + } + } +} + +Pne->FaireDuStrongBranching = OUI_PNE; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Classe les variables entieres en fonction + de leur valeur fractionnaire */ + +void PNE_ClasserLesVariableFractionnaires( PROBLEME_PNE * Pne, int i , double Milieu ) +{ +int ik; int ikPrec; + +if ( Pne->PremFrac == -1 ) { /* C'est la premiere variable */ + Pne->PremFrac = i; + Pne->SuivFrac[i] = -1; + return; +} + +/* C'est pas la premiere variable: on lui cherche un emplacement */ +ik = Pne->PremFrac; +if ( fabs( Pne->UTrav[i ] - ( Milieu * Pne->UmaxTrav[i ] ) ) < + fabs( Pne->UTrav[ik] - ( Milieu * Pne->UmaxTrav[ik] ) ) ) { + Pne->PremFrac = i; + Pne->SuivFrac[i] = ik; + return; +} + +/* C'est pas le meilleur */ +ikPrec = ik; +ik = Pne->SuivFrac[ik]; +while ( ik >= 0 ) { + if ( fabs( Pne->UTrav[i ] - ( Milieu * Pne->UmaxTrav[i ] ) ) < + fabs( Pne->UTrav[ik] - ( Milieu * Pne->UmaxTrav[ik] ) ) ) { + /* Emplacement trouve */ + Pne->SuivFrac[ikPrec] = i; + Pne->SuivFrac[i] = ik; + return; + } + ikPrec = ik; + ik = Pne->SuivFrac[ik]; +} + +/* C'est la plus mauvaise: classement de la variable a la fin de la liste */ +Pne->SuivFrac[ikPrec] = i; +Pne->SuivFrac[i] = -1; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Classe les variables entieres en fonction */ +/* de leur valeur fractionnaire ponderee par */ +/* le steepest edge du simplexe */ + +void PNE_ClasserLesVariableFractionnairesSteepestEdge( PROBLEME_PNE * Pne, int Var, + double Frac, + double * Fractionnalite ) +{ +int ik; int ikPrec; + +Fractionnalite[Var] = Frac; +if ( Pne->PremFrac == -1 ) { /* C'est la premiere variable */ + Pne->PremFrac = Var; + Pne->SuivFrac[Var] = -1; + return; +} + +/* C'est pas la premiere variable: on lui cherche un emplacement */ +ik = Pne->PremFrac; +if ( Frac > Fractionnalite[ik] ) { + Pne->PremFrac = Var; + Pne->SuivFrac[Var] = ik; + return; +} + +/* C'est pas le meilleur */ +ikPrec = ik; +ik = Pne->SuivFrac[ik]; +while ( ik >= 0 ) { + if ( Frac > Fractionnalite[ik] ) { + /* Emplacement trouve */ + Pne->SuivFrac[ikPrec] = Var; + Pne->SuivFrac[Var] = ik; + return; + } + ikPrec = ik; + ik = Pne->SuivFrac[ik]; +} + +/* C'est la plus mauvaise: classement de la variable a la fin de la liste */ +Pne->SuivFrac[ikPrec] = Var; +Pne->SuivFrac[Var] = -1; + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_ecrire_jeu_de_donnees_mps.c b/src/ext/Sirius_Solver/pne/pne_ecrire_jeu_de_donnees_mps.c new file mode 100644 index 0000000000..9eda7ce985 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_ecrire_jeu_de_donnees_mps.c @@ -0,0 +1,270 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Ecriture du jeu de donnees au format MPS + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" +# include "pne_define.h" +# include "pne_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_EcrireJeuDeDonneesMPS( PROBLEME_PNE * Pne, PROBLEME_A_RESOUDRE * Probleme ) +{ +FILE * Flot; +int Cnt; int Var; int il; int ilk; int ilMax; char * Nombre; +int * Cder; int * Cdeb; int * NumeroDeContrainte; int * Csui; + +/* */ +int NombreDeVariables; int * TypeDeVariable; int * TypeDeBorneDeLaVariable; +double * Xmax; double * Xmin; double * CoutLineaire; int NombreDeContraintes; +double * SecondMembre; char * Sens; int * IndicesDebutDeLigne; +int * NombreDeTermesDesLignes; double * CoefficientsDeLaMatriceDesContraintes; +int * IndicesColonnes; +/* */ + +NombreDeVariables = Probleme->NombreDeVariables; +TypeDeVariable = Probleme->TypeDeVariable; +TypeDeBorneDeLaVariable = Probleme->TypeDeBorneDeLaVariable; +Xmax = Probleme->Xmax; +Xmin = Probleme->Xmin; +CoutLineaire = Probleme->CoutLineaire; +NombreDeContraintes = Probleme->NombreDeContraintes; +SecondMembre = Probleme->SecondMembre; +Sens = Probleme->Sens; +IndicesDebutDeLigne = Probleme->IndicesDebutDeLigne; +NombreDeTermesDesLignes = Probleme->NombreDeTermesDesLignes; +CoefficientsDeLaMatriceDesContraintes = Probleme->CoefficientsDeLaMatriceDesContraintes; +IndicesColonnes = Probleme->IndicesColonnes; + +/* Chainage de la transposee */ +for ( ilMax = -1 , Cnt = 0 ; Cnt < NombreDeContraintes; Cnt++ ) { + if ( ( IndicesDebutDeLigne[Cnt] + NombreDeTermesDesLignes[Cnt] - 1 ) > ilMax ) { + ilMax = IndicesDebutDeLigne[Cnt] + NombreDeTermesDesLignes[Cnt] - 1; + } +} +ilMax+= NombreDeContraintes; /* Marge */ + +Cder = (int *) malloc( NombreDeVariables * sizeof( int ) ); +Cdeb = (int *) malloc( NombreDeVariables * sizeof( int ) ); +NumeroDeContrainte = (int *) malloc( ilMax * sizeof( int ) ); +Csui = (int *) malloc( ilMax * sizeof( int ) ); +Nombre = (char *) malloc( 1024 ); +if ( Cder == NULL || Cdeb == NULL || NumeroDeContrainte == NULL || Csui == NULL || Nombre == NULL ) { + printf("Memoire insuffisante dans le sous programme PNE_EcrireJeuDeDonneesMPS\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) Cdeb[Var] = -1; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = IndicesDebutDeLigne[Cnt]; + ilMax = il + NombreDeTermesDesLignes[Cnt]; + while ( il < ilMax ) { + Var = IndicesColonnes[il]; + if ( Cdeb[Var] < 0 ) { + Cdeb [Var] = il; + NumeroDeContrainte[il] = Cnt; + Csui [il] = -1; + Cder [Var] = il; + } + else { + ilk = Cder[Var]; + Csui [ilk] = il; + NumeroDeContrainte[il] = Cnt; + Csui [il] = -1; + Cder [Var] = il; + } + il++; + } +} +free( Cder ); +/* Fin chainage de la transposee */ + +/* Fichier qui contiendra le jeu de donnees */ +printf("***************************************************************************\n"); +printf("*** Vous avez demande la creation d'un fichier contenant la description ***\n"); +printf("*** du probleme en cours de resolution. Le fichier de donnees se trouve ***\n"); +printf("*** dans le repertoire d'execution. Il s'appelle: ***\n"); +printf("*** ***\n"); +printf("*** Donnees_Probleme_Solveur.mps ***\n"); +printf("*** ***\n"); +printf("*** Si un fichier de ce nom existait deja, il sera ecrase par avec les ***\n"); +printf("*** nouvelles donnees. ***\n"); +printf("***************************************************************************\n"); + +Flot = fopen( "Donnees_Probleme_Solveur.mps", "w" ); +if( Flot == NULL ) { + printf("Erreur ouverture du fichier pour l'ecriture du jeu de donnees \n"); + exit(0); +} + +/* Ecrire du titre */ +fprintf(Flot,"* Number of variables: %d\n",NombreDeVariables); +fprintf(Flot,"* Number of constraints: %d\n",NombreDeContraintes); + +/* + Les champs du format MPS +Champ1 : 2- 3 +Champ2 : 5-12 +Champ3 : 15-22 +Champ4 : 25-36 +Champ5 : 40-47 +Champ6 : 50-61 +*/ + +/* NAME */ +fprintf(Flot,"NAME Pb Solve\n"); + +/* ROWS */ +fprintf(Flot,"ROWS\n"); +/* +In this section all the row labels are defined, as well as the row type. The row +type is entered in field 1 (in column 2 or 3) and the row label is entered in +field 2 (columns 5-12). Row type: +E : egalité +L : inferieur ou egal +G : superieur ou egal +N : objectif +N : free ?? +*/ +/* Objectif */ +fprintf(Flot," N OBJECTIF\n"); +/* Ecriture de toutes les contraintes */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( Sens[Cnt] == '=' ) { + fprintf(Flot," E R%07d\n",Cnt); + } + else if ( Sens[Cnt] == '<' ) { + fprintf(Flot," L R%07d\n",Cnt); + } + else if ( Sens[Cnt] == '>' ) { + fprintf(Flot," G R%07d\n",Cnt); + } + else { + fprintf(Flot,"PNE_EcrireJeuDeDonneesMPS : le sens de la contrainte %c ne fait pas partie des sens reconnus\n", + Sens[Cnt]); + exit(0); + } +} + +/* COLUMNS */ +fprintf(Flot,"COLUMNS\n"); +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( CoutLineaire[Var] != 0.0 ) { + sprintf(Nombre,"%-.10lf",CoutLineaire[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," C%07d OBJECTIF %s\n",Var,Nombre); + } + il = Cdeb[Var]; + while ( il >= 0 ) { + sprintf(Nombre,"%-.10lf",CoefficientsDeLaMatriceDesContraintes[il]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," C%07d R%07d %s\n",Var,NumeroDeContrainte[il],Nombre); + il = Csui[il]; + } +} + +/* RHS */ +fprintf(Flot,"RHS\n"); +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( SecondMembre[Cnt] != 0.0 ) { + sprintf(Nombre,"%-.9lf",SecondMembre[Cnt]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," RHSVAL R%07d %s\n",Cnt,Nombre); + } +} + +/* BOUNDS */ +fprintf(Flot,"BOUNDS\n"); +/* + Field 1 (columns 2-3) specifies the type of bound: + LO lower bound + UP upper bound + LI lower bound integer variable + UI upper bound integer variable + BV binary variable + FX fixed variable + FR free + MI lower bound - infini + PL upper bound + infini +*/ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_FIXE ) { + sprintf(Nombre,"%-.9lf",Xmin[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," FX BNDVALUE C%07d %s\n",Var,Nombre); + continue; + } + if ( TypeDeVariable[Var] == ENTIER ) { + fprintf(Flot," BV BNDVALUE C%07d\n",Var); + continue; + } + /* Variable reelle */ + /* Par defaut la variable est PL i.e;. comprise entre 0 et + l'infini */ + if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( Xmin[Var] != 0.0 ) { + sprintf(Nombre,"%-.9lf",Xmin[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," LO BNDVALUE C%07d %s\n",Var,Nombre); + } + sprintf(Nombre,"%-.9lf",Xmax[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," UP BNDVALUE C%07d %s\n",Var,Nombre); + } + if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( Xmin[Var] != 0.0 ) { + sprintf(Nombre,"%-.9lf",Xmin[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," LO BNDVALUE C%07d %s\n",Var,Nombre); + } + } + if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + fprintf(Flot," MI BNDVALUE C%07d\n",Var); + if ( Xmax[Var] != 0.0 ) { + sprintf(Nombre,"%-.9lf",Xmax[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," UP BNDVALUE C%07d %s\n",Var,Nombre); + } + } + if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_NON_BORNEE ) { + fprintf(Flot," FR BNDVALUE C%07d\n",Var); + } +} + +/* ENDDATA */ +fprintf(Flot,"ENDATA\n"); + +free ( Cdeb ); +free ( NumeroDeContrainte ); +free ( Csui ); +free ( Nombre ); + +fclose( Flot ); + +return; + +} diff --git a/src/ext/Sirius_Solver/pne/pne_ecrire_presolved_mps.c b/src/ext/Sirius_Solver/pne/pne_ecrire_presolved_mps.c new file mode 100644 index 0000000000..d97a2c81ea --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_ecrire_presolved_mps.c @@ -0,0 +1,270 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Ecriture du probleme au format MPS apres le presolve + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" +# include "pne_define.h" +# include "pne_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_EcrirePresolvedMPS( PROBLEME_PNE * Pne ) +{ +FILE * Flot; +int Cnt; int Var; int il; int ilk; int ilMax; char * Nombre; +int * Cder; int * Cdeb; int * NumeroDeContrainte; int * Csui; + +/* */ +int NombreDeVariables; int * TypeDeVariable; int * TypeDeBorneDeLaVariable; +double * Xmax; double * Xmin; double * CoutLineaire; int NombreDeContraintes; +double * SecondMembre; char * Sens; int * IndicesDebutDeLigne; +int * NombreDeTermesDesLignes; double * CoefficientsDeLaMatriceDesContraintes; +int * IndicesColonnes; +/* */ + +NombreDeVariables = Pne->NombreDeVariablesTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorneDeLaVariable = Pne->TypeDeBorneTrav; +Xmax = Pne->UmaxTrav; +Xmin = Pne->UminTrav; +CoutLineaire = Pne->LTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +SecondMembre = Pne->BTrav; +Sens = Pne->SensContrainteTrav; +IndicesDebutDeLigne = Pne->MdebTrav; +NombreDeTermesDesLignes = Pne->NbTermTrav; +CoefficientsDeLaMatriceDesContraintes = Pne->ATrav; +IndicesColonnes = Pne->NuvarTrav; + +/* Chainage de la transposee */ +for ( ilMax = -1 , Cnt = 0 ; Cnt < NombreDeContraintes; Cnt++ ) { + if ( ( IndicesDebutDeLigne[Cnt] + NombreDeTermesDesLignes[Cnt] - 1 ) > ilMax ) { + ilMax = IndicesDebutDeLigne[Cnt] + NombreDeTermesDesLignes[Cnt] - 1; + } +} +ilMax+= NombreDeContraintes; /* Marge */ + +Cder = (int *) malloc( NombreDeVariables * sizeof( int ) ); +Cdeb = (int *) malloc( NombreDeVariables * sizeof( int ) ); +NumeroDeContrainte = (int *) malloc( ilMax * sizeof( int ) ); +Csui = (int *) malloc( ilMax * sizeof( int ) ); +Nombre = (char *) malloc( 1024 ); +if ( Cder == NULL || Cdeb == NULL || NumeroDeContrainte == NULL || Csui == NULL || Nombre == NULL ) { + printf("Memoire insuffisante dans le sous programme PNE_EcrireJeuDeDonneesMPS\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) Cdeb[Var] = -1; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = IndicesDebutDeLigne[Cnt]; + ilMax = il + NombreDeTermesDesLignes[Cnt]; + while ( il < ilMax ) { + Var = IndicesColonnes[il]; + if ( Cdeb[Var] < 0 ) { + Cdeb [Var] = il; + NumeroDeContrainte[il] = Cnt; + Csui [il] = -1; + Cder [Var] = il; + } + else { + ilk = Cder[Var]; + Csui [ilk] = il; + NumeroDeContrainte[il] = Cnt; + Csui [il] = -1; + Cder [Var] = il; + } + il++; + } +} +free( Cder ); +/* Fin chainage de la transposee */ + +/* Fichier qui contiendra le jeu de donnees */ +printf("***************************************************************************\n"); +printf("*** Vous avez demande la creation d'un fichier contenant la description ***\n"); +printf("*** du probleme en cours de resolution. Le fichier de donnees se trouve ***\n"); +printf("*** dans le repertoire d'execution. Il s'appelle: ***\n"); +printf("*** ***\n"); +printf("*** Donnees_Probleme_Solveur.mps ***\n"); +printf("*** ***\n"); +printf("*** Si un fichier de ce nom existait deja, il sera ecrase par avec les ***\n"); +printf("*** nouvelles donnees. ***\n"); +printf("***************************************************************************\n"); + +Flot = fopen( "Donnees_Probleme_Solveur.mps", "w" ); +if( Flot == NULL ) { + printf("Erreur ouverture du fichier pour l'ecriture du jeu de donnees \n"); + exit(0); +} + +/* Ecrire du titre */ +fprintf(Flot,"* Number of variables: %d\n",NombreDeVariables); +fprintf(Flot,"* Number of constraints: %d\n",NombreDeContraintes); + +/* + Les champs du format MPS +Champ1 : 2- 3 +Champ2 : 5-12 +Champ3 : 15-22 +Champ4 : 25-36 +Champ5 : 40-47 +Champ6 : 50-61 +*/ + +/* NAME */ +fprintf(Flot,"NAME Pb Solve\n"); + +/* ROWS */ +fprintf(Flot,"ROWS\n"); +/* +In this section all the row labels are defined, as well as the row type. The row +type is entered in field 1 (in column 2 or 3) and the row label is entered in +field 2 (columns 5-12). Row type: +E : egalité +L : inferieur ou egal +G : superieur ou egal +N : objectif +N : free ?? +*/ +/* Objectif */ +fprintf(Flot," N OBJECTIF\n"); +/* Ecriture de toutes les contraintes */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( Sens[Cnt] == '=' ) { + fprintf(Flot," E R%07d\n",Cnt); + } + else if ( Sens[Cnt] == '<' ) { + fprintf(Flot," L R%07d\n",Cnt); + } + else if ( Sens[Cnt] == '>' ) { + fprintf(Flot," G R%07d\n",Cnt); + } + else { + fprintf(Flot,"PNE_EcrireJeuDeDonneesMPS : le sens de la contrainte %c ne fait pas partie des sens reconnus\n", + Sens[Cnt]); + exit(0); + } +} + +/* COLUMNS */ +fprintf(Flot,"COLUMNS\n"); +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( CoutLineaire[Var] != 0.0 || 1 ) { + sprintf(Nombre,"%-.10lf",CoutLineaire[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," C%07d OBJECTIF %s\n",Var,Nombre); + } + il = Cdeb[Var]; + while ( il >= 0 ) { + sprintf(Nombre,"%-.10lf",CoefficientsDeLaMatriceDesContraintes[il]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," C%07d R%07d %s\n",Var,NumeroDeContrainte[il],Nombre); + il = Csui[il]; + } +} + +/* RHS */ +fprintf(Flot,"RHS\n"); +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( SecondMembre[Cnt] != 0.0 ) { + sprintf(Nombre,"%-.9lf",SecondMembre[Cnt]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," RHSVAL R%07d %s\n",Cnt,Nombre); + } +} + +/* BOUNDS */ +fprintf(Flot,"BOUNDS\n"); +/* + Field 1 (columns 2-3) specifies the type of bound: + LO lower bound + UP upper bound + LI lower bound integer variable + UI upper bound integer variable + BV binary variable + FX fixed variable + FR free + MI lower bound - infini + PL upper bound + infini +*/ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_FIXE ) { + sprintf(Nombre,"%-.9lf",Xmin[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," FX BNDVALUE C%07d %s\n",Var,Nombre); + continue; + } + if ( TypeDeVariable[Var] == ENTIER ) { + fprintf(Flot," BV BNDVALUE C%07d\n",Var); + continue; + } + /* Variable reelle */ + /* Par defaut la variable est PL i.e;. comprise entre 0 et + l'infini */ + if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( Xmin[Var] != 0.0 ) { + sprintf(Nombre,"%-.9lf",Xmin[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," LO BNDVALUE C%07d %s\n",Var,Nombre); + } + sprintf(Nombre,"%-.9lf",Xmax[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," UP BNDVALUE C%07d %s\n",Var,Nombre); + } + if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( Xmin[Var] != 0.0 ) { + sprintf(Nombre,"%-.9lf",Xmin[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," LO BNDVALUE C%07d %s\n",Var,Nombre); + } + } + if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + fprintf(Flot," MI BNDVALUE C%07d\n",Var); + if ( Xmax[Var] != 0.0 ) { + sprintf(Nombre,"%-.9lf",Xmax[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," UP BNDVALUE C%07d %s\n",Var,Nombre); + } + } + if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_NON_BORNEE ) { + fprintf(Flot," FR BNDVALUE C%07d\n",Var); + } +} + +/* ENDDATA */ +fprintf(Flot,"ENDATA\n"); + +free ( Cdeb ); +free ( NumeroDeContrainte ); +free ( Csui ); +free ( Nombre ); + +fclose( Flot ); + +return; + +} diff --git a/src/ext/Sirius_Solver/pne/pne_enlever_tout_petits_termes.c b/src/ext/Sirius_Solver/pne/pne_enlever_tout_petits_termes.c new file mode 100644 index 0000000000..d17d27c456 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_enlever_tout_petits_termes.c @@ -0,0 +1,170 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + FONCTION: Construction du probleme + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# define RAPPORT_ECRETEMENT_PETITS_TERMES 1.e+15 +# define RAPPORT_ECRETEMENT_PETITS_TERMES_PAR_CONTRAINTE 1.e+12 +# define SEUIL_ALERTE_ECRETEMENT 1.e-6 +# define SEUIL_ECRETEMENT_1 1.e-10 +# define SEUIL_ECRETEMENT_2 5.e-8 + +/*----------------------------------------------------------------------------*/ +/* Si le rapport Max/Min est tres grand on enleve les tout petits termes */ + +void PNE_EnleverLesToutPetitsTermes( int * Mdeb, int * NbTerm, int * Indcol, + double * A, double * Xmax, double * Xmin, + int NombreDeContraintes, char AffichageDesTraces ) +{ +int Cnt; int il; int ilMax; double PlusGrandTerme; double PlusPetitTerme; +double X; char OnSupprime; int ilDeb; char ToutPetitsTermes; + +ToutPetitsTermes = NON_PNE; +PlusGrandTerme = -1; +PlusPetitTerme = LINFINI_SPX; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + X = fabs( A[il] ); + if( X != 0.0 ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + il++; + } +} + +if ( PlusGrandTerme / PlusPetitTerme < RAPPORT_ECRETEMENT_PETITS_TERMES ) return; + +/* +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + X = fabs( A[il] ); + if( X < SEUIL_ALERTE_ECRETEMENT ) { + OnSupprime = NON_SPX; + if ( X < SEUIL_ECRETEMENT_1 ) { + printf("Suppression d'un terme trop petit A fois delta X = %e SEUIL_ECRETEMENT_1 = %e\n",X * ( Xmax[Indcol[il]] - Xmin[Indcol[il]]),SEUIL_ECRETEMENT_1); + OnSupprime = OUI_SPX; + } + else if ( X * ( Xmax[Indcol[il]] - Xmin[Indcol[il]] ) < SEUIL_ECRETEMENT_2 ) { + printf("Suppression d'un terme trop petit A fois delta X = %e SEUIL_ECRETEMENT_2 = %e\n",X * ( Xmax[Indcol[il]] - Xmin[Indcol[il]]),SEUIL_ECRETEMENT_2); + OnSupprime = OUI_SPX; + } + if ( OnSupprime == OUI_SPX ) { + if ( NbTerm[Cnt] > 1 ) { + ilMax--; + A[il] = A[ilMax]; + Indcol[il] = Indcol[ilMax]; + NbTerm[Cnt]--; + continue; + } + } + } + il++; + } +} +*/ + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilDeb = il; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + X = fabs( A[il] ); + if( X < SEUIL_ALERTE_ECRETEMENT ) { + /* On regarde si on peut supprimer quelque chose a condition qu'il n'y ait pas que des petits termes dans la contrainte */ + PlusGrandTerme = -1; + PlusPetitTerme = LINFINI_SPX; + il = ilDeb; + while ( il < ilMax ) { + X = fabs( A[il] ); + if( X != 0.0 ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + il++; + } + if ( PlusGrandTerme / PlusPetitTerme < RAPPORT_ECRETEMENT_PETITS_TERMES_PAR_CONTRAINTE ) { + /* On prefere tout garder */ + break; + } + /* On essai d'enlever les petits termes */ + il = ilDeb; + while ( il < ilMax ) { + X = fabs( A[il] ); + if( X < SEUIL_ALERTE_ECRETEMENT ) { + OnSupprime = NON_SPX; + if ( X < SEUIL_ECRETEMENT_1 ) { + /* + printf("Suppression d'un terme trop petit A fois delta X = %e SEUIL_ECRETEMENT_1 = %e\n",X * ( Xmax[Indcol[il]] - Xmin[Indcol[il]]),SEUIL_ECRETEMENT_1); + */ + OnSupprime = OUI_SPX; + ToutPetitsTermes = OUI_PNE; + } + else if ( X * ( Xmax[Indcol[il]] - Xmin[Indcol[il]] ) < SEUIL_ECRETEMENT_2 ) { + /* + printf("Suppression d'un terme trop petit A fois delta X = %e SEUIL_ECRETEMENT_2 = %e\n",X * ( Xmax[Indcol[il]] - Xmin[Indcol[il]]),SEUIL_ECRETEMENT_2); + */ + ToutPetitsTermes = OUI_PNE; + OnSupprime = OUI_SPX; + } + if ( OnSupprime == OUI_SPX ) { + /* Il est preferable de mettre 0 */ + A[il] = 0.0; + /* + if ( NbTerm[Cnt] > 1 ) { + ilMax--; + A[il] = A[ilMax]; + Indcol[il] = Indcol[ilMax]; + NbTerm[Cnt]--; + continue; + } + */ + } + } + il++; + } + break; + } + il++; + } +} + +if ( AffichageDesTraces == OUI_PNE ) { + if ( ToutPetitsTermes == OUI_PNE ) { + printf("Constraints containing terms very close to zero where detected, making the problem harder to solve:\n"); + printf(".. whenever possible, please keep an eye on this issue when computing your constraints coefficients\n"); + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_enrichir_probleme_avec_coupe.c b/src/ext/Sirius_Solver/pne/pne_enrichir_probleme_avec_coupe.c new file mode 100644 index 0000000000..0d0e5e8fa2 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_enrichir_probleme_avec_coupe.c @@ -0,0 +1,104 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul des coupes + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_EnrichirLeProblemeCourantAvecUneCoupe( PROBLEME_PNE * Pne, + char Type, + int NombreDeTermes, + double SecondMembre, + double Distance, + double * Coefficient, + int * IndicesDesVariables ) +{ +int i; + +/* Il faut d'abord stocker la coupe dans une structure temporaire qui sera exploitee pour la mise a + jour des coupes dans la partie branch and bound */ +/* Allocations si necessaire */ +if ( Pne->NombreDeCoupesCalculees == 0 ) { + Pne->CoupesCalculees = ( COUPE_CALCULEE **) malloc( ( Pne->NombreDeCoupesCalculees + 1 ) * sizeof( void * ) ); +} +else { + Pne->CoupesCalculees = ( COUPE_CALCULEE **) realloc( Pne->CoupesCalculees, + ( Pne->NombreDeCoupesCalculees + 1 ) * sizeof( void * ) ); +} +if ( Pne->CoupesCalculees == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_EnrichirLeProblemeCourantAvecUneCoupe \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} + +/* Stockage de la coupe */ +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees] = ( COUPE_CALCULEE * ) malloc( sizeof( COUPE_CALCULEE ) ); +if ( Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees] == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_CalculerUneGomoryEnVariablesMixtes \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} + +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->Type = Type; +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->IndexDansCliques = -1; +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->IndexDansCoupesDeProbing = -1; +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->IndexDansContraintesDeBorneVariable = -1; +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->IndexDansKNegligees = -1; +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->IndexDansGNegligees = -1; +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->NumeroDeLaContrainte = Pne->Coupes.NombreDeContraintes; +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->NombreDeTermes = NombreDeTermes; + +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->Coefficient = (double *) malloc( NombreDeTermes * sizeof( double ) ); +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->IndiceDeLaVariable = (int *) malloc( NombreDeTermes * sizeof( int ) ); +if ( Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->Coefficient == NULL || + Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->IndiceDeLaVariable == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_CalculerUneGomoryEnVariablesMixtes \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env, Pne->AnomalieDetectee ); +} + +for ( i = 0 ; i < NombreDeTermes ; i++ ) { + Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->Coefficient[i] = Coefficient[i]; + Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->IndiceDeLaVariable[i] = IndicesDesVariables[i]; +} + +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->SecondMembre = SecondMembre; +Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees]->Distance = Distance; + +Pne->NombreDeCoupesCalculees++; + +Pne->NombreDeCoupesAjoute++; + +return; +} + + + diff --git a/src/ext/Sirius_Solver/pne/pne_fixation_sur_critere.c b/src/ext/Sirius_Solver/pne/pne_fixation_sur_critere.c new file mode 100644 index 0000000000..a4d448bb03 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_fixation_sur_critere.c @@ -0,0 +1,225 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Il s'agit de la reprise d'une partie du presolve. + On cherche a fixer les variables entieres dont le cout est nul. + - Si toutes les inegalites ou elle a un coeff negatif sont telles + que la plus grande borne inf induite par ces inegalites est inferieure + ou egale a sa borne native alors on fixe la variable a sa borne + inf native. + - Si toutes les inegalites ou elle a un coeff positif sont telles + que la plus petite borne sup induite par ces inegalites est superieure + ou egale a sa borne native alors on fixe la variable a sa borne + sup native. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_FixationDesVariablesEntieresSurCritere( PROBLEME_PNE * Pne ) +{ +int Var; int Var1; int * TypeDeBorneTrav; int * TypeDeVariableTrav; double * UminTrav; double * UmaxTrav; +double * LTrav; int * CdebTrav; int * CsuiTrav; double * ATrav; char OnPeutFixer; double Ai; int Cnt; +char * SensContrainteTrav; int * NumContrainteTrav; int ic; int il; int ilMax; double S; double A; +double PlusGrandeBorneInf; double PlusPetiteBorneSup; int * MdebTrav; int * NbTermTrav; int * NuvarTrav; double * BTrav; +char OnPeutEssayerDeFixerAuMin; char OnPeutEssayerDeFixerAuMax; double * UTrav; + +return; /* C'est pas concluant */ + +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; +LTrav = Pne->LTrav; +CdebTrav = Pne->CdebTrav; +CsuiTrav = Pne->CsuiTrav; +ATrav = Pne->ATrav; +SensContrainteTrav = Pne->SensContrainteTrav; +NumContrainteTrav = Pne->NumContrainteTrav; +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; +BTrav = Pne->BTrav; +UTrav = Pne->UTrav; + +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + + if ( TypeDeVariableTrav[Var] != ENTIER ) continue; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_FIXE ) continue; + if ( UminTrav[Var] == UmaxTrav[Var] ) continue; + + OnPeutEssayerDeFixerAuMin = NON_PNE; + OnPeutEssayerDeFixerAuMax = NON_PNE; + if ( LTrav[Var] == 0.0 ) { + OnPeutEssayerDeFixerAuMin = OUI_PNE; + OnPeutEssayerDeFixerAuMax = OUI_PNE; + } + else if ( LTrav[Var] < 0.0 ) OnPeutEssayerDeFixerAuMax = OUI_PNE; + else OnPeutEssayerDeFixerAuMin = OUI_PNE; + + /* 1- On cherche a la fixer sur la borne inf */ + if ( OnPeutEssayerDeFixerAuMin == OUI_PNE ) { + OnPeutFixer = OUI_PNE; + PlusGrandeBorneInf = -LINFINI_PNE; + ic = CdebTrav[Var]; + while ( ic >= 0 ) { + Ai = ATrav[ic]; + if ( Ai == 0.0 ) goto ContrainteSuivante_1; + Cnt = NumContrainteTrav[ic]; + if ( SensContrainteTrav[Cnt] == '=' ) { + OnPeutFixer = NON_PNE; + break; + } + /* On calcule la plus grande borne inf donnee par les inequations ou Var a un coeff negatif */ + S = 0.0; + if ( Ai < 0.0 ) { + /* On cherche a maximiser la partie restante */ + S = -BTrav[Cnt]; + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var1 = NuvarTrav[il]; + A = ATrav[il]; + if ( Var1 != Var ) { + if ( A > 0.0 ) { + /* On prend la borne sup */ + if ( TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + S += A * UmaxTrav[Var1]; + } + else if ( TypeDeBorneTrav[Var1] == VARIABLE_FIXE || UminTrav[Var1] == UmaxTrav[Var1] ) S += A * UTrav[Var1]; + else { + OnPeutFixer = NON_PNE; + break; + } + } + else if ( A < 0.0 ) { + /* On prend la borne inf */ + if ( TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_INFERIEUREMENT ) { + S += A * UminTrav[Var1]; + } + else if ( TypeDeBorneTrav[Var1] == VARIABLE_FIXE || UminTrav[Var1] == UmaxTrav[Var1] ) S += A * UTrav[Var1]; + else { + OnPeutFixer = NON_PNE; + break; + } + } + } + il++; + } + if ( OnPeutFixer == NON_PNE ) break; + /* Calcul de la borne inf */ + S /= fabs( Ai ); + if ( S > PlusGrandeBorneInf ) PlusGrandeBorneInf = S; + } + ContrainteSuivante_1: + ic = CsuiTrav[ic]; + } + if ( OnPeutFixer == OUI_PNE ) { + /* On cherche a fixer la variable a UminTrav */ + if ( PlusGrandeBorneInf <= UminTrav[Var] ) { + printf("Variable entiere %d fixee a %e (Umin)\n",Var,UminTrav[Var]); + UmaxTrav[Var] = UminTrav[Var]; + continue; + } + } + } + /* 2- On cherche a la fixer sur la borne sup */ + if ( OnPeutEssayerDeFixerAuMax == OUI_PNE ) { + OnPeutFixer = OUI_PNE; + PlusPetiteBorneSup = LINFINI_PNE; + ic = CdebTrav[Var]; + while ( ic >= 0 ) { + Ai = ATrav[ic]; + if ( Ai == 0.0 ) goto ContrainteSuivante_2; + Cnt = NumContrainteTrav[ic]; + if ( SensContrainteTrav[Cnt] == '=' ) { + OnPeutFixer = NON_PNE; + break; + } + /* On calcule la plus petite borne sup donnee par les inequations ou Var a un coeff positif */ + if ( Ai > 0.0 ) { + /* On cherche a minimiser la partie restante */ + S = BTrav[Cnt]; + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var1 = NuvarTrav[il]; + if ( Var1 != Var ) { + A = -ATrav[il]; + if ( A > 0.0 ) { + /* On prend la borne inf */ + if ( TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_INFERIEUREMENT ) { + S += A * UminTrav[Var1]; + } + else if ( TypeDeBorneTrav[Var1] == VARIABLE_FIXE || UminTrav[Var1] == UmaxTrav[Var1] ) S += A * UTrav[Var1]; + else { + OnPeutFixer = NON_PNE; + break; + } + } + else if ( A < 0.0 ) { + /* On prend la borne sup */ + if ( TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorneTrav[Var1] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + S += A * UmaxTrav[Var1]; + } + else if ( TypeDeBorneTrav[Var1] == VARIABLE_FIXE || UminTrav[Var1] == UmaxTrav[Var1] ) S += A * UTrav[Var1]; + else { + OnPeutFixer = NON_PNE; + break; + } + } + } + il++; + } + if ( OnPeutFixer == NON_PNE ) break; + /* Calcul de la borne inf */ + S /= Ai; + if ( S < PlusPetiteBorneSup ) PlusPetiteBorneSup = S; + } + ContrainteSuivante_2: + ic = CsuiTrav[ic]; + } + if ( OnPeutFixer == OUI_PNE ) { + /* On cherche a fixer la variable a UminTrav */ + if ( PlusPetiteBorneSup >= UmaxTrav[Var] ) { + printf("Variable entiere %d fixee a %e (Umax)\n",Var,UmaxTrav[Var]); + UminTrav[Var] = UmaxTrav[Var]; + } + } + } +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/pne/pne_fonctions.h b/src/ext/Sirius_Solver/pne/pne_fonctions.h new file mode 100644 index 0000000000..e5c553de78 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_fonctions.h @@ -0,0 +1,475 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef FONCTIONS_PNE_DEJA_DEFINIES +/*******************************************************************************************/ + +# include "pne_definition_arguments.h" /* C'est ce header qui continet le protoype de PNE_Solveur */ +# include "pne_define.h" /* Comme il contient aussi pne_constantes_externes.h il n'y a pas besoin + de l'inclure pne_constantes_externes.h dans l'appelant. cependant on + le recommande comme ca l'utilisateur sera tente d'aller voir ce qu'il + y a comme constantes externes ce qui n'est pas plus mal */ + +/*--------------------------------------------------------------------------------------------------*/ + +void PNE_SolveurProblemeReduit( PROBLEME_A_RESOUDRE * , CONTROLS * ); + +void PNE_ControleMacAdresse( void ); + +void PNE_SolveurCalculs( PROBLEME_A_RESOUDRE * , PROBLEME_PNE * ); + +void PNE_InitialiserLaPne( PROBLEME_PNE * , PROBLEME_A_RESOUDRE * ); + +void PNE_EnleverLesToutPetitsTermes( int * , int * , int * , double * , double * , double * , int , char ); + +void PNE_AjouterLaContrainteDeCoutMax( PROBLEME_PNE * ); + +void PNE_ClasserLesCoefficientsDesContraintesOrdreDecroissant( PROBLEME_PNE * ); + +void PNE_TranslaterLesBornes( PROBLEME_PNE * ); + +void PNE_DetecterLesGub( PROBLEME_PNE * ); + +void PNE_CompacterLaMatriceDesContraintes( PROBLEME_PNE * ); + +/* */ + +void PNE_SolvePbRlxPi( PROBLEME_PNE * , double * , int * ); + +void PNE_SolvePbRlxSpxPrimal( PROBLEME_PNE * , double , int , int , int , int , int * , int * , + int * , int * , double * , int * ); + +void PNE_SolvePbRlxSpxDual( PROBLEME_PNE * , char , double , int , int , int * , int * , int * , int * ); + +void PNE_CloneProblemeSpxDuNoeudRacine( PROBLEME_PNE * Pne , int * , int * , int * ); + +MATRICE_DE_CONTRAINTES * PNE_ConstruireMatriceDeContraintesDuSimplexeAuNoeudRacine( PROBLEME_PNE * , int * , int , int * ); + +void PNE_LibererMatriceDeContraintesDuSimplexeAuNoeudRacine( MATRICE_DE_CONTRAINTES * ); + +void PNE_CalculerLaValeurDuCritere( PROBLEME_PNE * ); + +void PNE_DeterminerLesVariablesFractionnaires( PROBLEME_PNE * , int * ); + +void PNE_StrongBranching( PROBLEME_PNE * , double * , double * , int * , int * , int * , + int * , int * , int * , int * , char * , char ); + +void PNE_StrongBranchingClasserLeResultat( PROBLEME_PNE * , char , char , char , double , double, + double, double, double , double , double *, double *, + int , char * , char * , double , + double *, double *, + int * , int * , int *, int *, int , int *, char * , + int * , int * , int *, int *, int , int *, char * , + int * ); + +char PNE_Gub( PROBLEME_PNE * , int * , int * , char * , int * , int * , char * , + double , double , double * , double , double * , double * , + int * , int * , int * , int * , int * , int * , int * ); + +void PNE_ChoixDesVariablesAInstancier( PROBLEME_PNE * , int * , int * , int ** , int * , int * , int ** ); + +double PNE_ValeurOptimaleDuProblemeCourantAvantNouvellesCoupes( PROBLEME_PNE * ); + +void PNE_ClasserLesVariableFractionnaires( PROBLEME_PNE * , int , double ); + +void PNE_RecupererLaSolutionEtCalculerLeCritere( PROBLEME_PNE * , PROBLEME_A_RESOUDRE * ); + +void PNE_ConstruireLeChainageDeLaTransposee( PROBLEME_PNE * ); + +void PNE_CalculerLesCoupes( PROBLEME_PNE * ); + +void PNE_EnrichirLeProblemeCourantAvecUneCoupe( PROBLEME_PNE * , char , /*int ,*/ int , double , double , double * , int * ); + +void PNE_TrierLesCoupesCalculees( PROBLEME_PNE * , int , int , char , char * , char * , char * ); + +void PNE_ActualiserLesCoupesAPrendreEnCompte( PROBLEME_PNE * ); + +void PNE_CalculerLesCoupesDIntersection( PROBLEME_PNE * ); + +void PNE_Gomory( PROBLEME_PNE * ); + +void PNE_CalculerUneGomoryEnVariablesMixtes( PROBLEME_PNE * , int , double ); + +void PNE_NormaliserUnCoupe( double * , double * , int , double ); + +void PNE_InsererUneContrainte( PROBLEME_PNE * , int , double * , int * , double , char , char ); + +void PNE_RecupererLeProblemeInitial( PROBLEME_PNE * ); + +void PNE_RechercheDesContraintesSaturees( PROBLEME_PNE * , int , int * ); + +void PNE_BranchAndBoundSolvePbRlx( PROBLEME_PNE * , char , int , char * , char , int * , int * , char * , double * , int * , + int * , int * , int * , int * , double * , int * , int * , int * , double * , double * , + double * , double * , int * , int * , int * , int * , int * , int * , int * ); + +char PNE_ReducedCostFixing( PROBLEME_PNE * , int * ); + +void PNE_ArchivagesPourReducedCostFixingAuNoeudRacine( PROBLEME_PNE * , int * , double * , double ); + +void PNE_ReducedCostFixingAuNoeudRacine( PROBLEME_PNE * ); + +void PNE_RelanceDuSimplexeAuNoeudRacine( PROBLEME_PNE * , int * ); + +void PNE_FixationDesVariablesEntieresSurCritere( PROBLEME_PNE * ); + +void PNE_CalculerLesRestrictionsDeBornes( PROBLEME_PNE * , int * , char * , char ); + +void PNE_ArchiverLaSolutionCourante( PROBLEME_PNE * ); + +void PNE_RestituerLaSolutionArchivee( PROBLEME_PNE * ); + +void PNE_AllocProbleme( PROBLEME_PNE * , int , int * , int * , double * , double * , int , int * , int * , int * , double * ); + +void PNE_AllocationsPourLePostSolve( PROBLEME_PNE * ); + +void PNE_AllocTablesDeSubstitution( PROBLEME_PNE * ); + +void PNE_CleanPostSolve( PROBLEME_PNE * ); + +void PNE_AugmenterLeNombreDeVariables( PROBLEME_PNE * ); + +void PNE_AugmenterLeNombreDeContraintes( PROBLEME_PNE * ); + +void PNE_AugmenterLaTailleDeLaMatriceDesContraintes( PROBLEME_PNE * ); + +void PNE_AllocCoupes( PROBLEME_PNE * ); + +void PNE_AugmenterLeNombreDeCoupes( PROBLEME_PNE * ); + +void PNE_AugmenterLaTailleDeLaMatriceDesCoupes( PROBLEME_PNE * ); + +void PNE_LibereProbleme( PROBLEME_PNE * ); + +void PNE_LireJeuDeDonneesMPS( void ); + +void PNE_PrendreEnCompteLesContraintesRangeMPS( void ); + +void PNE_EcrireJeuDeDonneesMPS( PROBLEME_PNE * , PROBLEME_A_RESOUDRE * ); + +void PNE_EcrirePresolvedMPS( PROBLEME_PNE * ); + +void PNE_CreerHashCodeContrainteMPS( void /*int **/ ); + +void PNE_CreerHashCodeVariableMPS( void /*int **/ ); + +int PNE_HashCode( char * , int ); + +void PNE_RechercheDuNumeroDeContrainteMPS( /*int , int ,*/ int * , char * ); + +void PNE_RechercheDuNumeroDeVariableMPS( /*int , int ,*/ int * , char * ); + +void PNE_ClasserVariablesDansContraintesMPS( void ); + +/* */ + +void PNE_ClasserVariablesDansContraintes( PROBLEME_PNE * ); + +double PNE_SRand( double ); + +double PNE_Rand( double ); + +/* Heuristiques */ + +void PNE_HeuristiquePilotage( PROBLEME_PNE * , char * ); + +void PNE_Heuristique( PROBLEME_PNE * , double , int , int * , int , int * ); + +void PNE_HeuristiqueArrondis( PROBLEME_PNE * , char * ); + +MATRICE_DE_CONTRAINTES * PNE_HeuristiqueConstruireMatriceDeContraintes( PROBLEME_PNE * ); + +void PNE_HeuristiqueLibererMatriceDeContraintes( MATRICE_DE_CONTRAINTES * ); + +char PNE_HeuristiqueEvaluerTailleDuProbleme( PROBLEME_PNE * ); + +void PNE_HeuristiqueArchivageSolutionEtMajBranchAndBound( PROBLEME_PNE * , double ); + +char PNE_HeuristiqueResolutionBranchAndBoundReduit( PROBLEME_PNE * , MATRICE_DE_CONTRAINTES * ); + +char PNE_HeuristiqueRINS( PROBLEME_PNE * ); + +char PNE_HeuristiqueVariablesEntieresFixees( PROBLEME_PNE * ); + +void PNE_HeuristiqueRechercheEnProfondeur( PROBLEME_PNE * , char * ); + + +/* */ + +void PNE_AnalyseInitialeDesBornesVariables( PROBLEME_PNE * ); + +void PNE_DetecterLesContraintesMixtes( PROBLEME_PNE * ); + +void PNE_DetecterLesVariablesBigM( PROBLEME_PNE * ); + +void PNE_AnalyseInitialeDesKnapsack( PROBLEME_PNE * ); + +void PNE_CoverKnapsackSimple( PROBLEME_PNE * ); + +void PNE_KnapsackSurCombinaisonsComplexesDeContraintes( PROBLEME_PNE * ); + +void PNE_KnapsackSurCombinaisonsDeContraintes( PROBLEME_PNE * , int , int , int * , double * , double , char * , char * ); + +void PNE_GreedyCoverKnapsack( PROBLEME_PNE * , int , int , int * , double * , double , char , char * , + char , double , int , int * , char * , double * ); + +void PNE_FreeTasGreedyCoverKnapsack( char * ); + +int PNE_MajorantKnapsack( int , int * , double * , double , char ); + +void PNE_KnapsackCoeffEntiers( int , double * , double * , double * ); + +int PNE_PartitionTriRapide( double * , int * , int , int , char ); + +void PNE_TriRapide( double * , int * , int , int , char ); + +void PNE_ReclasserCsurA( int , char * , int * , double * , int , int * , double * , double * , int * ); + +void PNE_RechercherUneCouvertureMinimale( int , double * , double * , int * , char * , double , + char * , double * , int * , double * , int * , double * , int * , + double * , int * , char ); + +void PNE_SequenceIndependantCoverKnapsackLifting( int , double * , double * , double , int * , double * , int * , double * , + double * , char * , double * , int * , char * ); + +double PNE_ProgrammationDynamiqueKnapsackSeparation( int , double * , double * , double ); + +void PNE_KnapsackLifterLaVariableContinue( double * , int , double * , double , int , int * , double * , + double , double, double * ); + +void PNE_Knapsack_0_1_AvecVariableContinue( PROBLEME_PNE * , int , int * , double * , double , double , int , + int * , char * , double * ); + +double PNE_G_de_D( double , double ); +double PNE_TesterUneMIR( int , int * , double * , double * , double , double , double , double , + double * , char ); + +void PNE_TesterUneMIRpourUneValeurDeDelta( PROBLEME_PNE * , double , int , double , int * , double * , double , double * , double , + double * , double * , double * , char * , double * , char ); + +char PNE_C_MIR( PROBLEME_PNE * , int , int * , double * , double * , double * , double ); + +void PNE_SyntheseEtStockageMIR( PROBLEME_PNE * , int , int * , double * , double , double , + int , int * , char * , double * ); + +char PNE_BoundSubstitution( PROBLEME_PNE * ,int , int , int * , double * , double , int * , int * , + double * , double * , double * , double * , int * , int * , char * , double * , char * ); + +char PNE_Agregation( PROBLEME_PNE * , char * , int * , int * , int * , double * , double * , char * , char * , int * , int * , int * , int * ); + +void PNE_MIRMarchandWolsey( PROBLEME_PNE * ); + +void PNE_MIRMarchandWolseySurContrainteConcateeGrapheDeConflits( PROBLEME_PNE * , double * , int * , char * , char * , double * , int * , + char * , double * , int * , char * , char * ); + +void PNE_SubstitutionVarContinuesPourK( PROBLEME_PNE * ); + +void PNE_CalculerUneKnapsackSurGomoryOuIntersection( PROBLEME_PNE * , double * , int * , double , int , double ); + +/*********************** Node presolve et probing ********************************/ + +void PNE_NodePresolve( PROBLEME_PNE * , int * ); + +void PNE_PresolveSimplifie( PROBLEME_PNE * , char * , char , int * ); +void PNE_PresolveSimplifieVariableProbing( PROBLEME_PNE * , int * , char * ); +void PNE_PresolveSimplifieContraintesDeBornesVariables( PROBLEME_PNE * , int * , char * ); + +PROBLEME_PNE * PNE_AllocPnePbReduit( PROBLEME_PNE * , int * ); + +void PNE_ProbingNodePresolveAlloc( PROBLEME_PNE * , char * ); + +void PNE_InitBorneInfBorneSupDesVariables( PROBLEME_PNE * ); + +void PNE_ProbingModifierLaMatriceDesContraintes( PROBLEME_PNE * , PROBING_OU_NODE_PRESOLVE * ); + +void PNE_AmeliorerLesCoefficientsDesVariablesBinaires( PROBLEME_PNE * , void * , char ); + +void PNE_CalculMinEtMaxDesContraintes( PROBLEME_PNE * , int * ); + +char PNE_DeterminerForcingConstraint( PROBLEME_PNE * , PROBING_OU_NODE_PRESOLVE * , int , char , char , char , double , double , double ); + +void PNE_NodePresolveInitBornesDesContraintes( PROBLEME_PNE * , int * ); + +void PNE_NodePresolveMajBminBmax( PROBLEME_PNE * , int * , int * , int * , double * , double * , double * , + double * , double * , int , double , char ); + +void PNE_NodePresolveGrapheDeConflit( PROBLEME_PNE * , int * , int * , int * , double * , double * , double * , + double * , double * , double * , double * , int , double , int * ); + +void PNE_NodePresolveAppliquerContraintesDeBornesVariables( PROBLEME_PNE * , int * ); + +void PNE_CalculMinContrainte( PROBLEME_PNE * , double , double , int , double * ); + +void PNE_CalculMaxContrainte( PROBLEME_PNE * , double , double , int , double * ); + +void PNE_MajIndicateursDeBornes( PROBLEME_PNE * , double * , double * , char * , char * , double , int , char , char ); + +void PNE_ModifierLaBorneDUneVariable( PROBLEME_PNE * , int , char , char , double , char , double , + double * , char * , char * , int * ); + +void PNE_CalculXiXs( PROBLEME_PNE * , double , int , int , char * , char * , double * , double * ); + +void PNE_CalculXiXsContrainteAUneSeuleVariable( PROBLEME_PNE * , int * , int , int , int , double * , int * , + char * , double * , char * , char * , double * , double * ); + +void PNE_ProbingNodePresolveFixerVariablesSurCritere( PROBLEME_PNE * , char * ); + +void PNE_VariableProbing( PROBLEME_PNE * ); +void PNE_VariableProbingSauvegardesDonnees( PROBLEME_PNE * ); +void PNE_VariableProbingReinitDonnees( PROBLEME_PNE * ); +void PNE_VariableProbingPreparerInstanciation( PROBLEME_PNE * , int , double ); +void PNE_VariableProbingFixerUneVariableInstanciee( PROBLEME_PNE * , PROBING_OU_NODE_PRESOLVE * , int , double ); +void PNE_VariableProbingRazContraintesAAnalyser( PROBLEME_PNE * , PROBING_OU_NODE_PRESOLVE * ); +void PNE_VariableProbingRazCoupesDeProbingPotentielles( PROBING_OU_NODE_PRESOLVE * ); + +void PNE_PostProbing( PROBLEME_PNE * ); + +void PNE_ProbingInitVariablesAInstancierApresLePresolve( PROBLEME_PNE * , PROBING_OU_NODE_PRESOLVE * ); + +void PNE_ProbingInitVariablesAInstancier( PROBLEME_PNE * , PROBING_OU_NODE_PRESOLVE * ); + +void PNE_ProbingMajVariablesAInstancier( PROBLEME_PNE * , PROBING_OU_NODE_PRESOLVE * ); + +void PNE_ProbingMajFlagVariablesAInstancier( PROBLEME_PNE * , int , double ); + +void PNE_ProbingMajBminBmax( PROBLEME_PNE * , int , double , char ); + +void PNE_VariableProbingAppliquerLeConflictGraph( PROBLEME_PNE * , int , double , char , char ); + +void PNE_AnalyseListeDeContraintes( PROBLEME_PNE * ); + +void PNE_InitListeDesContraintesAExaminer( PROBLEME_PNE * , int , double , char ); + +void PNE_MajConflictGraph( PROBLEME_PNE * , int , double ); + +void PNE_AllocConflictGraph( PROBLEME_PNE * ); + +void PNE_ReallocConflictGraph( PROBLEME_PNE * ); + +void PNE_CliquesConflictGraph( PROBLEME_PNE * ); + +void PNE_TransformerCliquesEnEgalites( PROBLEME_PNE * ); + +void PNE_ArchiverMaxClique( PROBLEME_PNE * , int , int * ); + +void PNE_ExtendConflictGraph( PROBLEME_PNE * ); + +void PNE_ConflictGraphFixerVariables( PROBLEME_PNE * ); + +void PNE_ConflictGraphSupprimerUnArc( int , int , int * , int * , int * ); + +void PNE_ConflictGraphSupprimerUnNoeud( int , int * , int * , int * ); + +void PNE_DetectionDesCliquesViolees( PROBLEME_PNE * ); + +void PNE_DetectionDesCoupesDeProbingViolees( PROBLEME_PNE * ); + +void PNE_DetectionKnapsackNegligeesViolees( PROBLEME_PNE * ); + +void PNE_DetectionGomoryNegligeesViolees( PROBLEME_PNE * ); + +void PNE_ControleCliquesAvantResolutionProblemeRelaxe( PROBLEME_PNE * , int * ); + +void PNE_ReducedCostFixingNoeudRacineConflictGraph( PROBLEME_PNE * , int , double ); + +void PNE_ReducedCostFixingConflictGraph( PROBLEME_PNE * , int , double , double * , double , double * , double * , double * , + int * , int * , int * , int * , int * ); + +void PNE_ConflictGraphFixerLesNoeudsVoisinsDunNoeud( PROBLEME_PNE * , int ); + +void PNE_CreerLesCoupesDeProbing( PROBLEME_PNE * , PROBING_OU_NODE_PRESOLVE * ); + +void PNE_ProbingInitDetectionDesBornesVariables( PROBLEME_PNE * ); + +void PNE_ProbingCloseDetectionDesBornesVariables( PROBLEME_PNE * ); + +void PNE_ProbingConstruireContraintesDeBornes( PROBLEME_PNE * , PROBING_OU_NODE_PRESOLVE * , double * , double * ); + +void PNE_DetectionDesContraintesDeBorneVariableViolees( PROBLEME_PNE * ); + +void PNE_CreerUneCoupeDeProbing( PROBLEME_PNE * , int , double , int , char , int , double ); + +void PNE_CreerUneCoupeKNegligee( PROBLEME_PNE * , int ); + +void PNE_CreerUneCoupeGNegligee( PROBLEME_PNE * , int ); + +void PNE_TwoStepMirSurContrainte( PROBLEME_PNE * ); + +void PNE_TwoStepMirSurTableau( PROBLEME_PNE * , int , double ); + +void PNE_RechercheSymetries( PROBLEME_PNE * , int , int * ); + +void PNE_PostSolve( PROBLEME_PNE * , PROBLEME_A_RESOUDRE * ); + +void PNE_PostSolveVariablesSubstituees( PROBLEME_PNE * , PROBLEME_A_RESOUDRE * , int , char ); + +void PNE_PostSolveVariablesColineaires( PROBLEME_PNE * , int ); + +void PNE_PostSolveContraintesSingleton( PROBLEME_PNE * , int , double * ); + +void PNE_PostSolveForcingConstraints( PROBLEME_PNE * , PROBLEME_A_RESOUDRE * , void * , int ); + +void PNE_PostSolveContraintesColineaires( PROBLEME_PNE * , PROBLEME_A_RESOUDRE * , int ); + +void PNE_ChangerLesTypesDeVariables( PROBLEME_PNE * Pne ); + +void PNE_BranchAndBoundIntermediare( PROBLEME_PNE * , double ); + +void PNE_PostSolveSiUniquementPresolve( PROBLEME_PNE * , PROBLEME_A_RESOUDRE * ); + +/* +void PNE_NodeDumalgeMendelsonMatriceDesContraintes( PROBLEME_PNE * , double * , double * , + char * , char * , char * , int * ); + +void * PNE_DumalgeFactoriserMatrice( PROBLEME_PNE * , void ** , int , int , int , int , int , int , + void * , void * , int * , int * , char * , char , char ); + +void PNE_DumalgeResoudrePrimal( PROBLEME_PNE * , void * , void * , int , int , int , int , int , int , + void * , void * , int * , int * , double * , char * , char , + double * , double * , char * , char * , char * ); +*/ + +double PNE_Round( double , double ); + +void PNE_MiseAJourSeuilCoupes( PROBLEME_PNE * , char , double * ); +void PNE_MiseAJourDesSeuilDeSelectionDesCoupes( PROBLEME_PNE * ); + +/* En test: pour detecter les contraintes d'egalite sur des entiere infaisables */ +void PNE_DetectionContraintesEntieresInfaisable( PROBLEME_PNE * ); + +/*******************************************************************************************/ +# define FONCTIONS_PNE_DEJA_DEFINIES +# endif +# ifdef __cplusplus + } +# endif + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_gomory_negligees.c b/src/ext/Sirius_Solver/pne/pne_gomory_negligees.c new file mode 100644 index 0000000000..e0d2e80856 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_gomory_negligees.c @@ -0,0 +1,262 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Stockage des coupes de Gomory negligees. + Remarque: on peut faire qq chose de commun avec les K. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 0 + +# define SIZE_ALLOC_COUPES 100 /* Nombre de coupes allouees */ +# define SIZE_ALLOC_TERMES_COUPES (SIZE_ALLOC_COUPES*25) + +void PNE_AllocCoupesGNegligees( PROBLEME_PNE * ); +void PNE_AugmenterNombreDeCoupesGNegligees( PROBLEME_PNE * ); +void PNE_AugmenterLaTailleDesCoupesGNegligees( PROBLEME_PNE * ); + +/*----------------------------------------------------------------------------*/ + +void PNE_AllocCoupesGNegligees( PROBLEME_PNE * Pne ) +{ +COUPES_G_NEGLIGEES * CoupesGNegligees; + +CoupesGNegligees = (COUPES_G_NEGLIGEES *) malloc( sizeof( COUPES_G_NEGLIGEES ) ); +if ( CoupesGNegligees == NULL ) return; + +CoupesGNegligees->SecondMembre = (double *) malloc( SIZE_ALLOC_COUPES * sizeof( double ) ); +if ( CoupesGNegligees->SecondMembre == NULL ) { + return; +} +CoupesGNegligees->LaCoupeEstDansLePool = (char *) malloc( SIZE_ALLOC_COUPES * sizeof( char ) ); +if ( CoupesGNegligees->LaCoupeEstDansLePool == NULL ) { + free( CoupesGNegligees->SecondMembre ); + return; +} +CoupesGNegligees->First = (int *) malloc( SIZE_ALLOC_COUPES * sizeof( int ) ); +if ( CoupesGNegligees->First == NULL ) { + free( CoupesGNegligees->SecondMembre ); + free( CoupesGNegligees->LaCoupeEstDansLePool ); + return; +} +CoupesGNegligees->NbElements = (int *) malloc( SIZE_ALLOC_COUPES * sizeof( int ) ); +if ( CoupesGNegligees->NbElements == NULL ) { + free( CoupesGNegligees->SecondMembre ); + free( CoupesGNegligees->LaCoupeEstDansLePool ); + free( CoupesGNegligees->First ); + return; +} +CoupesGNegligees->NombreDeCoupesAllouees = SIZE_ALLOC_COUPES; + +CoupesGNegligees->Colonne = (int *) malloc( SIZE_ALLOC_TERMES_COUPES * sizeof( int ) ); +if ( CoupesGNegligees->Colonne == NULL ) { + free( CoupesGNegligees->SecondMembre ); + free( CoupesGNegligees->LaCoupeEstDansLePool ); + free( CoupesGNegligees->First ); + free( CoupesGNegligees->NbElements ); + return; +} +CoupesGNegligees->Coefficient = (double *) malloc( SIZE_ALLOC_TERMES_COUPES * sizeof( double ) ); +if ( CoupesGNegligees->Coefficient == NULL ) { + free( CoupesGNegligees->SecondMembre ); + free( CoupesGNegligees->LaCoupeEstDansLePool ); + free( CoupesGNegligees->First ); + free( CoupesGNegligees->NbElements ); + free( CoupesGNegligees->Colonne ); + return; +} +CoupesGNegligees->TailleCoupesAllouee = SIZE_ALLOC_TERMES_COUPES; + +CoupesGNegligees->IndexLibre = 0; +CoupesGNegligees->NombreDeCoupes = 0; +CoupesGNegligees->Full = NON_PNE; +Pne->CoupesGNegligees = CoupesGNegligees; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AugmenterNombreDeCoupesGNegligees( PROBLEME_PNE * Pne ) +{ +COUPES_G_NEGLIGEES * CoupesGNegligees; int Size; double * SecondMembre; char * LaCoupeEstDansLePool; +int * First; int * NbElements; + +CoupesGNegligees = Pne->CoupesGNegligees; +Size = CoupesGNegligees->NombreDeCoupesAllouees + SIZE_ALLOC_COUPES; + +SecondMembre = (double *) realloc( CoupesGNegligees->SecondMembre, Size * sizeof( double ) ); +if ( SecondMembre == NULL ) { + CoupesGNegligees->Full = OUI_PNE; + return; +} +LaCoupeEstDansLePool = (char *) realloc( CoupesGNegligees->LaCoupeEstDansLePool, Size * sizeof( char ) ); +if ( LaCoupeEstDansLePool == NULL ) { + free( SecondMembre ); + CoupesGNegligees->Full = OUI_PNE; + return; +} +First = (int *) realloc( CoupesGNegligees->First, Size * sizeof( int ) ); +if ( First == NULL ) { + free( SecondMembre ); + free( LaCoupeEstDansLePool ); + CoupesGNegligees->Full = OUI_PNE; + return; +} +NbElements = (int *) realloc( CoupesGNegligees->NbElements, Size * sizeof( int ) ); +if ( NbElements == NULL ) { + free( SecondMembre ); + free( LaCoupeEstDansLePool ); + free( First ); + CoupesGNegligees->Full = OUI_PNE; + return; +} +CoupesGNegligees->NombreDeCoupesAllouees = Size; +CoupesGNegligees->SecondMembre = SecondMembre; +CoupesGNegligees->LaCoupeEstDansLePool = LaCoupeEstDansLePool; +CoupesGNegligees->First = First; +CoupesGNegligees->NbElements = NbElements; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AugmenterLaTailleDesCoupesGNegligees( PROBLEME_PNE * Pne ) +{ +COUPES_G_NEGLIGEES * CoupesGNegligees; int Size; int * Colonne; double * Coefficient; + +CoupesGNegligees = Pne->CoupesGNegligees; +Size = CoupesGNegligees->TailleCoupesAllouee + SIZE_ALLOC_TERMES_COUPES; + +Colonne = (int *) realloc( CoupesGNegligees->Colonne, Size * sizeof( int ) ); +if ( Colonne == NULL ) { + CoupesGNegligees->Full = OUI_PNE; + return; +} +Coefficient = (double *) realloc( CoupesGNegligees->Coefficient, Size * sizeof( double ) ); +if ( Coefficient == NULL ) { + free( Colonne ); + CoupesGNegligees->Full = OUI_PNE; + return; +} +CoupesGNegligees->TailleCoupesAllouee = Size; +CoupesGNegligees->Colonne = Colonne; +CoupesGNegligees->Coefficient = Coefficient; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CreerUneCoupeGNegligee( PROBLEME_PNE * Pne, int NumeroDeCoupe ) +{ +COUPES_G_NEGLIGEES * CoupesGNegligees; int il; int NombreDeCoupes; +int Nb; int * First; int * NbElements; int * Colonne; int * Mdeb; int * NbTerm; +int * Nuvar; double * Coefficient; double * A; int il1; int ilMax; + +return; + +Mdeb = Pne->Coupes.Mdeb; +NbTerm = Pne->Coupes.NbTerm; +Nuvar = Pne->Coupes.Nuvar; +A = Pne->Coupes.A; + +CoupesGNegligees = Pne->CoupesGNegligees; +if ( CoupesGNegligees == NULL ) { + PNE_AllocCoupesGNegligees( Pne ); + CoupesGNegligees = Pne->CoupesGNegligees; + if ( CoupesGNegligees == NULL ) return; /* Saturation memoire */ +} + +NombreDeCoupes = CoupesGNegligees->NombreDeCoupes; + +/* Place suffisante */ +if ( NombreDeCoupes >= CoupesGNegligees->NombreDeCoupesAllouees ) { + /* On augmente la taille */ + PNE_AugmenterNombreDeCoupesGNegligees( Pne ); + if ( Pne->CoupesGNegligees == NULL ) return; + if ( CoupesGNegligees->Full == OUI_PNE ) return; +} + +/* Place suffisante */ +il1 = CoupesGNegligees->IndexLibre; +while ( il1 + NbTerm[NumeroDeCoupe] + 1 >= CoupesGNegligees->TailleCoupesAllouee ) { + /* On augmente la taille */ + PNE_AugmenterLaTailleDesCoupesGNegligees( Pne ); + if ( Pne->CoupesGNegligees == NULL ) return; + if ( CoupesGNegligees->Full == OUI_PNE ) return; +} + +First = CoupesGNegligees->First; +NbElements = CoupesGNegligees->NbElements; +Coefficient = CoupesGNegligees->Coefficient; +Colonne = CoupesGNegligees->Colonne; + +First[NombreDeCoupes] = il1; +Nb = 0; +il = Mdeb[NumeroDeCoupe]; +ilMax = il + NbTerm[NumeroDeCoupe]; +while ( il < ilMax ) { + if ( A[il] != 0 ) { + Coefficient[il1] = A[il]; + Colonne[il1] = Nuvar[il]; + il1++; + Nb++; + } + il++; +} +NbElements[NombreDeCoupes] = Nb; + +CoupesGNegligees->SecondMembre[NombreDeCoupes] = Pne->Coupes.B[NumeroDeCoupe]; + +# if TRACES == 1 + printf("Coupe de G negligee: %d\n",NombreDeCoupes); + il = First[NombreDeCoupes]; + ilMax = il + NbElements[NombreDeCoupes]; + while ( il < ilMax ) { + if ( Pne->TypeDeVariableTrav[Colonne[il]] == ENTIER ) printf("%e (%d I) ",Coefficient[il],Colonne[il]); + else printf("%e (%d R) ",Coefficient[il],Colonne[il]); + il++; + } + printf(" SecondMembre %e\n",CoupesGNegligees->SecondMembre[NombreDeCoupes]); +# endif + +CoupesGNegligees->IndexLibre = il1; +CoupesGNegligees->LaCoupeEstDansLePool[NombreDeCoupes] = NON_PNE; +CoupesGNegligees->NombreDeCoupes++; + +return; +} + + diff --git a/src/ext/Sirius_Solver/pne/pne_gomory_negligees_violees.c b/src/ext/Sirius_Solver/pne/pne_gomory_negligees_violees.c new file mode 100644 index 0000000000..1b70f381b7 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_gomory_negligees_violees.c @@ -0,0 +1,132 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Detection des coupes de knapsack negliges violees. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define PROFONDEUR_LIMITE_COUPES_DE_G 10 + +/*----------------------------------------------------------------------------*/ + +void PNE_DetectionGomoryNegligeesViolees( PROBLEME_PNE * Pne ) +{ +double S; int Cnt; double E; int * First; int * NbElements; int NbV; double NormeV; +int il; int ilMax; double * Coeff; int * Indice; double B; int NbT; double * X; +int * Colonne; char * LaCoupeEstDansLePool; double * SecondMembre; +double * Coefficient; COUPES_G_NEGLIGEES * CoupesGNegligees; double Marge; +int * TypeDeBorne; BB * Bb; + +Marge = 0.1; + +Bb = Pne->ProblemeBbDuSolveur; +if ( Bb->NoeudEnExamen->ProfondeurDuNoeud > PROFONDEUR_LIMITE_COUPES_DE_G ) return; + +if ( Pne->CoupesGNegligees == NULL ) return; +CoupesGNegligees = Pne->CoupesGNegligees; + +TypeDeBorne = Pne->TypeDeBorneTrav; +X = Pne->UTrav; +Coeff = Pne->Coefficient_CG; +Indice = Pne->IndiceDeLaVariable_CG; + +First = CoupesGNegligees->First; +LaCoupeEstDansLePool = CoupesGNegligees->LaCoupeEstDansLePool; +NbElements = CoupesGNegligees->NbElements; +SecondMembre = CoupesGNegligees->SecondMembre; +Colonne = CoupesGNegligees->Colonne; +Coefficient = CoupesGNegligees->Coefficient; + +NbV = 0; +NormeV = 0.0; + +for ( Cnt = 0 ; Cnt < CoupesGNegligees->NombreDeCoupes ; Cnt++ ) { + if ( First[Cnt] < 0 ) continue; + if ( LaCoupeEstDansLePool[Cnt] == OUI_PNE ) continue; + il = First[Cnt]; + ilMax = il + NbElements[Cnt]; + S = 0; + NbT = 0; + B = CoupesGNegligees->SecondMembre[Cnt]; + while ( il < ilMax ) { + if ( TypeDeBorne[Colonne[il]] != VARIABLE_FIXE ) { + /* Car sinon il n'y a pas de variable correspondante dans le simplexe */ + S += Coefficient[il] * X[Colonne[il]]; + Coeff[NbT] = Coefficient[il]; + Indice[NbT] = Colonne[il]; + NbT++; + } + else { + B -= Coefficient[il] * X[Colonne[il]]; + } + il++; + } + if ( S > B + Marge && NbT > 0 ) { + /* + printf("NbT %d depassement %e\n",NbT,S-B); + for ( il = 0 ; il < NbT ; il++ ) { + printf(" %e (%d) ",Coeff[il],Indice[il]); + } + printf("< %e\n",B); + */ + E = S - B; + NormeV += E; + /* On Stocke la coupe */ + NbV++; + PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'G', NbT, B, E, Coeff, Indice ); + Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees-1]->IndexDansGNegligees = Cnt; + } +} + +if ( Pne->AffichageDesTraces == OUI_PNE && NbV > 0 ) { + printf("Adding %d initially neglected Gomory cuts violated by %e\n",NbV,NormeV); + fflush( stdout ); +} + +return; +} + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_gub.c b/src/ext/Sirius_Solver/pne/pne_gub.c new file mode 100644 index 0000000000..daa827f3df --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_gub.c @@ -0,0 +1,477 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: En presence de contraintes Gub, generation d'un schema + de branchement particulier. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define NOMBRE_MIN_DE_VARIABLES_A_ARBITRER 3 + +# define NOMBRE_MAX_DE_GUB_TESTEES 1000 + +/*----------------------------------------------------------------------------*/ + +char PNE_Gub( PROBLEME_PNE * Pne, + int * PosVarAGauche , int * ComplBaseAGauche, + char * PositionDeLaVariableDEcartAGauche , + int * PosVarADroite , int * ComplBaseADroite, + char * PositionDeLaVariableDEcartADroite , + double CritereInfini, double Marge , + double * SupDeNouveauCritere , double SeuilNouveauCout, + /* */ + double * MinorantEspereAGauche, + double * MinorantEspereADroite, + /* Base correspondante pour l'instanciation a gauche */ + int * PositionDeLaVariableAGauche , + int * NbVarDeBaseComplementairesAGauche, + int * ComplementDeLaBaseAGauche , + /* Base correspondante pour l'instanciation a droite */ + int * PositionDeLaVariableADroite , + int * NbVarDeBaseComplementairesADroite, + int * ComplementDeLaBaseADroite , + /* Indicateur de disponibilite des bases a entier sup et inf */ + int * BasesFilsDisponibles + ) +{ +int i ; int j ; int il ; int ilMax; int Cnt ; char OnInverse; int NbVarCnt; +int Var; int * NumeroDeVariable ; int r ; double S ; char NextCnt ; char YaUn ; +int * NombreDeTermesLibresDeLaGub; double * XmaxSV ; double F ; double X ; +int VariableInstanciee ; double * MesureEntierete ; + +int ExistenceDUneSolAGauche; int ExistenceDUneSolADroite; char TypeDeSolution; +int NbVarComplAGauche ; int NbVarComplADroite ; + +char ExistenceSolutionAGauche; char ExistenceSolutionADroite; +char ChoixDuTypeDeVariation ; + +double CritereAGauche; double CritereADroite; char ChoixDefinitif; char ChoixAmeliorant; +double DeltaXAGauche ; double DeltaXADroite ; + +int NbVarGauche ; int * PaquetDeGauche; int NbVarDroite; int * PaquetDeDroite; +int ValeurAGauche; int ValeurADroite ; char OnYVa ; int NbGubTestees ; + +double SupEcartDInstanciation; char YaLaVariableFractionnaire; + +Pne->NbVarGauche = 0; +Pne->NbVarDroite = 0; + +ChoixDefinitif = NON_PNE; + +OnYVa = OUI_PNE; + +printf(" Nombre de Gub : %d\n",Pne->NombreDeGub); fflush(stdout); +/* +if ( Pne->YaUneSolutionEntiere != OUI_PNE ) OnYVa = NON_PNE; +*/ +if ( Pne->NombreDeGub <= 0 ) OnYVa = NON_PNE; + +if ( OnYVa == NON_PNE ) return( ChoixDefinitif ); + +/*printf("Test des Gub\n");*/ +SupEcartDInstanciation = 1.e-7; + +NbGubTestees = 0; + +NumeroDeVariable = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +NombreDeTermesLibresDeLaGub = (int *) malloc( Pne->NombreDeGub * sizeof( int ) ); +MesureEntierete = (double *) malloc( Pne->NombreDeGub * sizeof( double ) ); +XmaxSV = (double *) malloc( Pne->DimBranchementGub * sizeof( double ) ); +PaquetDeGauche = (int *) malloc( Pne->DimBranchementGub * sizeof( int ) ); +PaquetDeDroite = (int *) malloc( Pne->DimBranchementGub * sizeof( int ) ); +if ( NumeroDeVariable == NULL || NombreDeTermesLibresDeLaGub == NULL || MesureEntierete == NULL || + XmaxSV == NULL || PaquetDeGauche == NULL || PaquetDeDroite == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_Gub \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} + +/* Mesure de la fractionalite de l'ensemble des variables de chaque GUB */ +for ( j = 0 ; j < Pne->NombreDeGub ; j++ ) { + NombreDeTermesLibresDeLaGub[j] = 0; + MesureEntierete [j] = 2. * Pne->NombreDeVariablesTrav; + Cnt = Pne->NumeroDeContrainteDeLaGub[j]; + if ( Cnt < 0 ) continue; + /* Decompte du nombre de variables non encore fixees */ + NbVarCnt = 0; + F = 0.; + il = Pne->MdebTrav[Cnt]; + ilMax = il + Pne->NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var = Pne->NuvarTrav [il]; + if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) { + if ( fabs( Pne->UminTrav[Var] - Pne->UmaxTrav[Var] ) > TOLERANCE_SUR_LES_ENTIERS ) { + /* Norme L1 */ + F+= fabs( 0.5 - Pne->UTrav[Var] ); + NbVarCnt++; + } + } + il++; + } + /* Si pas assez de variables entieres, on n'arbitre pas sur la Gub */ + if ( NbVarCnt >= NOMBRE_MIN_DE_VARIABLES_A_ARBITRER ) { + MesureEntierete[j] = F; + } + NombreDeTermesLibresDeLaGub[j] = NbVarCnt; +} + +/* On reclasse les Gub */ +OnInverse = OUI_PNE; +while ( OnInverse == OUI_PNE ) { + OnInverse = NON_PNE; + for ( j = 0 ; j < Pne->NombreDeGub - 1 ; j++ ) { + if ( Pne->NumeroDeContrainteDeLaGub[j] >= 0 && Pne->NumeroDeContrainteDeLaGub[j+1] >= 0 ) { + if ( NombreDeTermesLibresDeLaGub[j] < NombreDeTermesLibresDeLaGub[j+1] ) { + OnInverse = OUI_PNE; + il = Pne->NumeroDeContrainteDeLaGub[j+1]; + Pne->NumeroDeContrainteDeLaGub[j+1] = Pne->NumeroDeContrainteDeLaGub[j]; + Pne->NumeroDeContrainteDeLaGub[j] = il; + + F = MesureEntierete[j+1]; + MesureEntierete[j+1] = MesureEntierete[j]; + MesureEntierete[j] = F; + + il = NombreDeTermesLibresDeLaGub[j+1]; + NombreDeTermesLibresDeLaGub[j+1] = NombreDeTermesLibresDeLaGub[j]; + NombreDeTermesLibresDeLaGub[j] = il; + + } + } + } +} + +/* On balaye les contraintes Gub */ +for ( j = 0 ; j < Pne->NombreDeGub && NbGubTestees < NOMBRE_MAX_DE_GUB_TESTEES ; j++ ) { + Cnt = Pne->NumeroDeContrainteDeLaGub[j]; + if ( Cnt < 0 ) continue; + /* Decompte du nombre de variables non encore fixees */ + NbVarCnt = 0; + NextCnt = NON_PNE; + YaUn = NON_PNE; + YaLaVariableFractionnaire = NON; + il = Pne->MdebTrav[Cnt]; + ilMax = il + Pne->NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var = Pne->NuvarTrav [il]; + + if ( Var == Pne->VariableLaPlusFractionnaire ) YaLaVariableFractionnaire = OUI; + + if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) { + + if ( fabs( Pne->UminTrav[Var] - Pne->UmaxTrav[Var] ) > TOLERANCE_SUR_LES_ENTIERS ) { + /* La variable n'a pas été instanciee */ + NumeroDeVariable[NbVarCnt] = Var; + NbVarCnt++; + if ( fabs( Pne->UmaxTrav[Var] - Pne->UTrav[Var] ) < TOLERANCE_SUR_LES_ENTIERS ) { + /* La variable se trouve sur borne max apres optimisation relaxee */ + /*NextCnt = OUI_PNE;*/ + } + } + else { + /* La variable est soit instanciee, soit deja fixee en entree */ + if ( Pne->UminTrav[Var] == 0.0 ) { + /* On verifie que la variable n'etait pas fixee des le depart */ + if ( Pne->TypeDeBorneTrav[Var] != VARIABLE_FIXE ) { + /*NextCnt = OUI_PNE;*/ + } + } + else { + /* La variable a ete instanciee ou fixee en entree a 1 */ + YaUn = OUI_PNE; + break; + } + } + + } + + il++; + } + + /*printf(" Gub %d YaLaVariableFractionnaire %d\n",j,YaLaVariableFractionnaire);*/ + + if ( YaUn == OUI_PNE ) continue; + if ( NbVarCnt < NOMBRE_MIN_DE_VARIABLES_A_ARBITRER ) continue; + if ( NextCnt == OUI_PNE ) continue; + + if ( YaLaVariableFractionnaire == NON ) continue; + + /* Classement des variables en fonction de U */ + OnInverse = OUI_PNE; + while ( OnInverse == OUI_PNE ) { + OnInverse = NON_PNE; + for ( i = 0 ; i < NbVarCnt - 1 ; i++ ) { + if ( Pne->UTrav[NumeroDeVariable[i]] < Pne->UTrav[NumeroDeVariable[i+1]] ) { + Var = NumeroDeVariable[i+1]; + NumeroDeVariable[i+1] = NumeroDeVariable[i]; + NumeroDeVariable[i] = Var; + OnInverse = OUI_PNE; + } + } + } + + /* Determination des paquets a instancier a 0 */ + S = 0.0; + r = -1; + for ( i = 0 ; i < NbVarCnt ; i++ ) { + /* Il faut que les variables ne soient pas sur borne ou presque */ + X = Pne->UTrav[NumeroDeVariable[i]]; + /*if ( X > 0.99) continue;*/ + S+= X; + if ( /*X < 0.5*/ /* <-old new ->*/ S > 0.5 ) { + /* r = i-1; <- old */ + r = i; + break; + } + } + /* Partitionnement refuse si r >= NbVarCnt - 1 */ + + r = (int) floor( NbVarCnt * 0.5 ); /* Test */ + + if ( r >= NbVarCnt - 1 ) continue; + if ( r < 0 ) continue; + if ( r == 0 || r >= NbVarCnt - 2 ) continue; /* Si une seule variable instanciee, on ne le fait pas */ + + /*if ( r <= 0 ) continue;*/ /* Car cela revient a separer sur une variable */ + + ValeurAGauche = 0; + ValeurADroite = 0; + /* Construction du paquet de gauche */ + NbVarGauche = 0; + DeltaXAGauche = 0.0/*1.0*/; /* Pourquoi pas 0 ? */ + + printf(" gauche: \n"); + + for ( i = 0 ; i <= r ; i++ ) { + if ( NbVarGauche >= Pne->DimBranchementGub ) goto FinDeBoucle; + PaquetDeGauche[NbVarGauche] = NumeroDeVariable[i]; + DeltaXAGauche+= Pne->UTrav[NumeroDeVariable[i]]; + + printf(" %e ",Pne->UTrav[NumeroDeVariable[i]]); + + NbVarGauche++; + } + /*printf("\n");*/ + /* Construction du paquet de droite */ + NbVarDroite = 0; + DeltaXADroite = 0.0; + + printf("\n droite: \n"); + + for ( i = r+1 ; i < NbVarCnt ; i++ ) { + if ( NbVarDroite >= Pne->DimBranchementGub ) goto FinDeBoucle; + PaquetDeDroite[NbVarDroite] = NumeroDeVariable[i]; + DeltaXADroite+= Pne->UTrav[NumeroDeVariable[i]]; + + printf(" %e ",Pne->UTrav[NumeroDeVariable[i]]); + + NbVarDroite++; + } + printf("\n"); fflush(stdout); + + NbGubTestees++; + + memcpy( (char *) Pne->UStrongBranching, (char *) Pne->UTrav, Pne->NombreDeVariablesTrav * sizeof( double ) ); + NbVarComplAGauche = 0; + + SPX_DualStrongBranchingGUB( + (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur, + /* Les variables a brancher */ + NbVarGauche , + PaquetDeGauche, + XmaxSV, /* Tableau de sauvegarde dimension nombre de variables a brancher */ + /* Sortie */ + &ExistenceDUneSolAGauche, + &TypeDeSolution , + Pne->UStrongBranching , + PosVarAGauche , + &NbVarComplAGauche , + ComplBaseAGauche , + /* Donnees initiales du probleme (elles sont utilisees par SPX_RecupererLaSolution)*/ + Pne->NombreDeVariablesTrav , + Pne->TypeDeBorneTrav , + Pne->NombreDeContraintesTrav, + /* Dans le but de recuperer les informations sur les coupes*/ + Pne->Coupes.NombreDeContraintes, + Pne->Coupes.NbTerm, + PositionDeLaVariableDEcartAGauche + ); + /* Calcul du critere apres strong branching */ + if ( ExistenceDUneSolAGauche == OUI_SPX ) { + ExistenceSolutionAGauche = OUI_PNE; + for ( CritereAGauche = Pne->Z0 , Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + CritereAGauche+= Pne->LTrav[Var] * Pne->UStrongBranching[Var]; + } + } + else { + ExistenceSolutionAGauche = NON_PNE; + CritereAGauche = CritereInfini; + #if VERBOSE_PNE + printf("Pas de solution a gauche\n"); + #endif + } + + #if VERBOSE_PNE + printf(" CritereAGauche : %e \n",CritereAGauche); + #endif + + memcpy( (char *) Pne->UStrongBranching, (char *) Pne->UTrav , Pne->NombreDeVariablesTrav * sizeof( double ) ); + NbVarComplADroite = 0; + + /*if ( NbVarDroite > Pne->DimBranchementGub ) exit(0);*/ /* A supprimer */ + + SPX_DualStrongBranchingGUB( + (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur, + /* Les variables a brancher */ + NbVarDroite, + PaquetDeDroite, + XmaxSV, /* Tableau de sauvegarde dimension nombre de variables a brancher */ + /* Sortie */ + &ExistenceDUneSolADroite, + &TypeDeSolution , + Pne->UStrongBranching , + PosVarADroite , + &NbVarComplADroite , + ComplBaseADroite , + /* Donnees initiales du probleme (elles sont utilisees par SPX_RecupererLaSolution)*/ + Pne->NombreDeVariablesTrav , + Pne->TypeDeBorneTrav , + Pne->NombreDeContraintesTrav, + /* Dans le but de recuperer les informations sur les coupes*/ + Pne->Coupes.NombreDeContraintes, + Pne->Coupes.NbTerm, + PositionDeLaVariableDEcartADroite + ); + /* Calcul du critere apres strong branching */ + if ( ExistenceDUneSolADroite == OUI_SPX ) { + ExistenceSolutionADroite = OUI_PNE; + for ( CritereADroite = Pne->Z0 , Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + CritereADroite+= Pne->LTrav[Var] * Pne->UStrongBranching[Var]; + } + } + else { + /* On multiplie par 2 pour que s'il n'y a pas de solution ni a entier inf. ni a entier sup., la variable + puisse etre choisie */ + ExistenceSolutionADroite = NON_PNE; + CritereADroite = 2 * CritereInfini; + #if VERBOSE_PNE + printf("Pas de solution a droite \n"); + #endif + } + + #if VERBOSE_PNE + printf(" CritereADroite : %e\n",CritereADroite); + #endif + + printf("CritereAGauche: %e CritereADroite: %e SeuilNouveauCout: %e\n",CritereAGauche,CritereADroite,SeuilNouveauCout); + /* + ChoixDuTypeDeVariation = PENTE_DE_LA_VARIATION; + if ( DeltaXAGauche <= 0.0 ) { + CritereAGauche = Pne->Critere; + DeltaXAGauche = 1.0; + } + if ( DeltaXADroite <= 0.0 ) { + DeltaXADroite = Pne->Critere; + DeltaXADroite = 0.0; + } + */ + ChoixDuTypeDeVariation = VALEUR_ABSOLUE_DE_LA_VARIATION; + ChoixDuTypeDeVariation = PENTE_DE_LA_VARIATION; + + VariableInstanciee = -1; + + /* Mise en commentaires car test sur branchement a partir des couts reduits */ + + PNE_StrongBranchingClasserLeResultat( Pne , ChoixDuTypeDeVariation , + ExistenceSolutionAGauche , ExistenceSolutionADroite , + CritereAGauche , DeltaXAGauche , + CritereADroite , DeltaXADroite , + CritereInfini , Marge , + SupDeNouveauCritere , &SupEcartDInstanciation , VariableInstanciee, + &ChoixDefinitif , &ChoixAmeliorant , + SeuilNouveauCout , + MinorantEspereAGauche , MinorantEspereADroite , + PositionDeLaVariableAGauche, NbVarDeBaseComplementairesAGauche, + ComplementDeLaBaseAGauche , PosVarAGauche , + NbVarComplAGauche , ComplBaseAGauche , + PositionDeLaVariableDEcartAGauche, + PositionDeLaVariableADroite , NbVarDeBaseComplementairesADroite, + ComplementDeLaBaseADroite , PosVarADroite , + NbVarComplADroite , ComplBaseADroite , + PositionDeLaVariableDEcartADroite, + BasesFilsDisponibles + ); + + + if ( ChoixAmeliorant == OUI_PNE ) { + Pne->ValeurAGauche = ValeurAGauche; + Pne->ValeurADroite = ValeurADroite; + Pne->NbVarGauche = NbVarGauche; + Pne->NbVarDroite = NbVarDroite; + memcpy( Pne->PaquetDeGauche , PaquetDeGauche , NbVarGauche * sizeof( int ) ); + memcpy( Pne->PaquetDeDroite , PaquetDeDroite , NbVarDroite * sizeof( int ) ); + } + + /* On se contente de ce partitionnement */ + if ( ChoixDefinitif == OUI_PNE ) { + + printf("ChoixDefinitif %d ChoixAmeliorant %d\n",ChoixDefinitif,ChoixAmeliorant); + printf("Strong branching accepte sur la contrainte Gub %d r %d NbVarCnt %d\n",Cnt,r,NbVarCnt); + + break; + } + FinDeBoucle: + continue; +} + + +free( NumeroDeVariable ); +free( NombreDeTermesLibresDeLaGub ); +NumeroDeVariable = NULL; +NombreDeTermesLibresDeLaGub = NULL; + +free( MesureEntierete ); +free( XmaxSV ); +free( PaquetDeGauche ); +free( PaquetDeDroite ); +MesureEntierete = NULL; +XmaxSV = NULL; +PaquetDeGauche = NULL; +PaquetDeDroite = NULL; + +/*printf("Pne->NbVarGauche %d Pne->NbVarDroite %d SupDeNouveauCritere %e\n",Pne->NbVarGauche,Pne->NbVarDroite,*SupDeNouveauCritere);*/ + +return( ChoixDefinitif ); + +} + diff --git a/src/ext/Sirius_Solver/pne/pne_heuristique.c b/src/ext/Sirius_Solver/pne/pne_heuristique.c new file mode 100644 index 0000000000..5d7f7ccaf6 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_heuristique.c @@ -0,0 +1,434 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recherche heuristique en tentant de fixer des variables + proches de leurs bornes. + Attention, ne peut etre appelee qu'apres le calcul des + coupes et le strong branching car ca change les matrices + internes du simplexe. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_constantes_externes.h" +# include "spx_definition_arguments.h" +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define SEUIL_MIN_DE_FRACTIONNALITE_MOYENNE 2.e+2 +# define SEUIL_MIN_DE_FRACTIONNALITE 2.e+2 + +# define POURCENTAGE_MIN_DE_VARIABLES_ENTIERES 0.1 + +void PNE_HeuristiqueResoudreLeProblemeRestreint( PROBLEME_PNE * , int * , int * , int * , char * , + double * , double * , char * , double * , double , + int ); + +/*----------------------------------------------------------------------------*/ + +void PNE_HeuristiqueResoudreLeProblemeRestreint( PROBLEME_PNE * Pne, int * PosVarHeuristique, + int * NbVarBaseComplementairesHeuristique, + int * ComplementDeLaBaseHeuristique, + char * PosVarEcartCoupesHeuristique, + double * VarDualesContraintesHeuristique, + double * CoutsRedHeuristique, + char * YaUneSolution, + double * Critere, + double CoutMax, + int UtiliserCoutMax ) +{ +double Crit; int i; PROBLEME_SIMPLEXE Probleme; +/* Lancement d'un simplexe */ +Probleme.Contexte = BRANCH_AND_BOUND_OU_CUT_NOEUD; +Probleme.NombreMaxDIterations = -1; +Probleme.DureeMaxDuCalcul = -1.; + +Probleme.CoutLineaire = Pne->LTrav; +Probleme.X = Pne->UTrav; +Probleme.Xmin = Pne->UminTrav; +Probleme.Xmax = Pne->UmaxTrav; +Probleme.NombreDeVariables = Pne->NombreDeVariablesTrav; +Probleme.TypeDeVariable = Pne->TypeDeBorneTrav; + +Probleme.NombreDeContraintes = Pne->NombreDeContraintesTrav; +Probleme.IndicesDebutDeLigne = Pne->MdebTrav; +Probleme.NombreDeTermesDesLignes = Pne->NbTermTrav; +Probleme.IndicesColonnes = Pne->NuvarTrav; +Probleme.CoefficientsDeLaMatriceDesContraintes = Pne->ATrav; +Probleme.Sens = Pne->SensContrainteTrav; +Probleme.SecondMembre = Pne->BTrav; + +Probleme.ChoixDeLAlgorithme = SPX_DUAL; + +Probleme.TypeDePricing = PRICING_STEEPEST_EDGE; +Probleme.FaireDuScaling = OUI_SPX; +Probleme.StrategieAntiDegenerescence = AGRESSIF; + +Probleme.BaseDeDepartFournie = OUI_SPX; +Probleme.PositionDeLaVariable = PosVarHeuristique; +Probleme.NbVarDeBaseComplementaires = *NbVarBaseComplementairesHeuristique; +Probleme.ComplementDeLaBase = ComplementDeLaBaseHeuristique; + +Probleme.LibererMemoireALaFin = NON_SPX; + +Probleme.CoutMax = CoutMax; +Probleme.UtiliserCoutMax = UtiliserCoutMax; + +Probleme.NombreDeContraintesCoupes = Pne->Coupes.NombreDeContraintes; +Probleme.BCoupes = Pne->Coupes.B; +Probleme.PositionDeLaVariableDEcartCoupes = PosVarEcartCoupesHeuristique; +Probleme.MdebCoupes = Pne->Coupes.Mdeb; +Probleme.NbTermCoupes = Pne->Coupes.NbTerm; +Probleme.NuvarCoupes = Pne->Coupes.Nuvar; +Probleme.ACoupes = Pne->Coupes.A; + +Probleme.CoutsMarginauxDesContraintes = VarDualesContraintesHeuristique; + +Probleme.CoutsReduits = CoutsRedHeuristique; + +Probleme.AffichageDesTraces = Pne->AffichageDesTraces; + +Pne->ProblemeSpxDuSolveur = SPX_Simplexe( &Probleme , Pne->ProblemeSpxDuSolveur ); + +*YaUneSolution = OUI_PNE; +if ( Probleme.ExistenceDUneSolution != OUI_SPX ) { + printf("--> On tombe sur une solution non realisable dans l'heuristique <--\n"); + *YaUneSolution = NON_PNE; + return; +} +*NbVarBaseComplementairesHeuristique = Probleme.NbVarDeBaseComplementaires; + +Crit = Pne->Z0; +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) Crit+= Pne->LTrav[i] * Pne->UTrav[i]; + +*Critere = Crit; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_Heuristique( PROBLEME_PNE * Pne, + double CoutMax, + int UtiliserCoutMax, + int * PositionDeLaVariable, + int NbVarDeBaseComplementaires, + int * ComplementDeLaBase + ) +{ +int i; char OnFixe; int NombreDeMacroIterations ; int NombreMaxDeMacroIterations; + +double * UTravSv; double * UminTravSv; double * UmaxTravSv; +double * CoutsRedHeuristique; double * VarDualesContraintesHeuristique; +int * PosVarHeuristique ; int * ComplementDeLaBaseHeuristique ; char * PosVarEcartCoupesHeuristique; + +int NbVarBaseComplementairesHeuristique; double Critere; int VariableAInstancier; int SeuilMinDeVariablesEntieres; + +char LeNoeudEstTerminal; char YaUneSolution; +double CritereAuMax; BB * Bb; +int * NuVarFrac; int Nb; int Var; int kMax; int k; + +double * UminX; double * UmaxX; double * UX; int * PX; +double * UminM; double * UmaxM; double * UM; int * PM; + +int NbX; +int * CplX; char * PecX; +int * CplM; char * PecM; + +return; /* Heuristique de fixation pas concluante il y a encore des problemes a regler */ + +Bb = (BB *) Pne->ProblemeBbDuSolveur; + +/* 1er test avant les alloc: on regarde s'il y a lieu de faire l'heuristique */ +/* La determination de la fractionnalite a deja ete faite */ +if ( Pne->NombreDeVariablesAValeurFractionnaire <= 1 ) return; +if ( Pne->NormeDeFractionnalite/Pne->NombreDeVariablesAValeurFractionnaire > SEUIL_MIN_DE_FRACTIONNALITE_MOYENNE ) return; + +SeuilMinDeVariablesEntieres = (int) ceil( POURCENTAGE_MIN_DE_VARIABLES_ENTIERES * Pne->NombreDeVariablesEntieresTrav ); +if ( SeuilMinDeVariablesEntieres < 10 ) SeuilMinDeVariablesEntieres = 10; + +/*SeuilMinDeVariablesEntieres = Pne->NombreDeVariablesEntieresTrav;*/ +/*printf(" SeuilMinDeVariablesEntieres %d NombreDeVariablesEntieres %d \n",SeuilMinDeVariablesEntieres,Pne->NombreDeVariablesEntieresTrav);*/ + +if ( Pne->NombreDeVariablesAValeurFractionnaire > SeuilMinDeVariablesEntieres ) return; + +printf("On tente l'heuristique \n"); + +NombreDeMacroIterations = 0; +NombreMaxDeMacroIterations = (int) (20 * Pne->NombreDeVariablesAValeurFractionnaire); +LeNoeudEstTerminal = NON_PNE; + +VariableAInstancier = Pne->VariableLaPlusFractionnaire; /* Sauvegarde apres le strong branching */ + +/* Sauvegardes */ +UTravSv = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +UminTravSv = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +UmaxTravSv = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +PosVarHeuristique = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +CoutsRedHeuristique = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); + + +UminX = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +UmaxX = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +UX = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +PX = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +UminM = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +UmaxM = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +UM = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +PM = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +CplX = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); +PecX = (char *) malloc( Pne->Coupes.NombreDeContraintes * sizeof( char ) ); +CplM = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); +PecM = (char *) malloc( Pne->Coupes.NombreDeContraintes * sizeof( char ) ); + + +if ( UTravSv == NULL || UminTravSv == NULL || UmaxTravSv == NULL || PosVarHeuristique == NULL || + CoutsRedHeuristique == NULL ) { + printf("PNE, memoire insuffisante dans le sous programme PNE_Heuristique \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} +memcpy( (char *) UTravSv , (char *) Pne->UTrav , Pne->NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char *) UminTravSv , (char *) Pne->UminTrav , Pne->NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char *) UmaxTravSv , (char *) Pne->UmaxTrav , Pne->NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char *) PosVarHeuristique , (char *) PositionDeLaVariable , Pne->NombreDeVariablesTrav * sizeof( int ) ); + +ComplementDeLaBaseHeuristique = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); +VarDualesContraintesHeuristique = (double *) malloc( ( Pne->NombreDeContraintesTrav + Pne->Coupes.NombreDeContraintes ) * sizeof( double ) ); +if ( ComplementDeLaBaseHeuristique == NULL || VarDualesContraintesHeuristique == NULL ) { + printf("PNE, memoire insuffisante dans le sous programme PNE_Heuristique \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +NbVarBaseComplementairesHeuristique = NbVarDeBaseComplementaires; +memcpy( (char *) ComplementDeLaBaseHeuristique , (char *) ComplementDeLaBase , Pne->NombreDeContraintesTrav * sizeof( int ) ); + +PosVarEcartCoupesHeuristique = (char *) malloc( Pne->Coupes.NombreDeContraintes * sizeof( char ) ); +if ( PosVarEcartCoupesHeuristique == NULL ) { + printf("PNE, memoire insuffisante dans le sous programme PNE_Heuristique \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} +memcpy( (char *) PosVarEcartCoupesHeuristique , (char *) Pne->Coupes.PositionDeLaVariableDEcart , Pne->Coupes.NombreDeContraintes * sizeof( char ) ); + +TentativeDeFixationDeBorne: + +/* On regarde quelle borne on peut fixer */ +if ( Pne->NombreDeVariablesAValeurFractionnaire > 0 ) { + if ( NombreDeMacroIterations > NombreMaxDeMacroIterations ) { + /* Echec */ + printf("Fin heuristique par depassement du nombre de macroiterations\n"); + goto ArretHeuristique; + } + /* On tente de fixer des bornes */ + /* On regarde si la fractionnalite de toutes les variables est inferieure a un seuil */ + OnFixe = OUI_PNE; + + if ( Pne->NombreDeVariablesAValeurFractionnaire > SeuilMinDeVariablesEntieres ) OnFixe = NON_PNE; + + if ( OnFixe == NON_PNE ) goto ArretHeuristique; + + + /* On fixe toutes les variables qui ont pris une valeur entiere */ + /* + for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( Pne->LaVariableAUneValeurFractionnaire[i] == OUI_PNE ) continue; + if ( Pne->UTrav[i] - Pne->UminTrav[i] < Pne->UmaxTrav[i] - Pne->UTrav[i] ) { + Pne->UmaxTrav[i] = Pne->UminTrav[i]; Pne->UTrav[i] = Pne->UminTrav[i]; + } + else { + Pne->UminTrav[i] = Pne->UmaxTrav[i]; Pne->UTrav[i] = Pne->UmaxTrav[i]; + } + } + */ + + /* On fixe un paquet de variables les moins fractionnaires */ + NuVarFrac = (int *) malloc( Pne->NombreDeVariablesAValeurFractionnaire * sizeof( int ) ); + Nb = 0; + i = Pne->PremFrac; + while ( i >= 0 ) { + NuVarFrac[Nb] = i; + Nb++; + i = Pne->SuivFrac[i]; + } + k = 0; + kMax = 10; + for ( i = Nb-1; i >= 0 ; i-- ) { + Var = NuVarFrac[i]; + if ( fabs( Pne->UTrav[Var] - Pne->UminTrav[Var] ) < fabs( Pne->UmaxTrav[Var] - Pne->UTrav[Var] ) ) { + Pne->UmaxTrav[Var] = Pne->UminTrav[Var]; + /*printf("Fixation de la variable %d U %e Umin %e Umax %e\n",Var,Pne->UTrav[Var],Pne->UminTrav[Var],Pne->UmaxTrav[Var]);*/ + Pne->UTrav[Var] = Pne->UminTrav[Var]; + k++; + } + else { + Pne->UminTrav[Var] = Pne->UmaxTrav[Var]; + /*printf("Fixation de la variable %d U %e Umin %e Umax %e\n",Var,Pne->UTrav[Var],Pne->UminTrav[Var],Pne->UmaxTrav[Var]);*/ + Pne->UTrav[Var] = Pne->UmaxTrav[Var]; + k++; + } + if ( k >= kMax ) break; + } + free( NuVarFrac ); + + /* On resout */ + PNE_HeuristiqueResoudreLeProblemeRestreint( Pne, PosVarHeuristique, &NbVarBaseComplementairesHeuristique, + ComplementDeLaBaseHeuristique, PosVarEcartCoupesHeuristique, + VarDualesContraintesHeuristique, CoutsRedHeuristique, + &YaUneSolution, &Critere, + CoutMax, UtiliserCoutMax ); + CritereAuMax = 2 * LINFINI_PNE; + if ( YaUneSolution == OUI_PNE ) { + printf("Critere %e\n",Critere); + CritereAuMax = Critere; + memcpy( (char *) UminX , (char *) Pne->UminTrav , Pne->NombreDeVariablesTrav * sizeof( double ) ); + memcpy( (char *) UmaxX , (char *) Pne->UmaxTrav , Pne->NombreDeVariablesTrav * sizeof( double ) ); + memcpy( (char *) UX , (char *) Pne->UTrav , Pne->NombreDeVariablesTrav * sizeof( double ) ); + memcpy( (char *) PX , (char *) PosVarHeuristique , Pne->NombreDeVariablesTrav * sizeof( int ) ); + + NbX = NbVarBaseComplementairesHeuristique; + memcpy( (char *) CplX , (char *) ComplementDeLaBaseHeuristique , Pne->NombreDeContraintesTrav * sizeof( int ) ); + memcpy( (char *) PecX , (char *) PosVarEcartCoupesHeuristique , Pne->Coupes.NombreDeContraintes * sizeof( char ) ); + + } + + if ( CritereAuMax > LINFINI_PNE ) { + /* Pas de solution ni au min ni au max */ + goto ArretHeuristique; + } + memcpy( (char *) Pne->UminTrav , (char *) UminX , Pne->NombreDeVariablesTrav * sizeof( double ) ); + memcpy( (char *) Pne->UmaxTrav , (char *) UmaxX , Pne->NombreDeVariablesTrav * sizeof( double ) ); + memcpy( (char *) Pne->UTrav , (char *) UX , Pne->NombreDeVariablesTrav * sizeof( double ) ); + memcpy( (char *) PosVarHeuristique , (char *) PX , Pne->NombreDeVariablesTrav * sizeof( int ) ); + NbVarBaseComplementairesHeuristique = NbX; + memcpy( (char *) ComplementDeLaBaseHeuristique , (char *) CplX , Pne->NombreDeContraintesTrav * sizeof( int ) ); + memcpy( (char *) PosVarEcartCoupesHeuristique , (char *) PecX , Pne->Coupes.NombreDeContraintes * sizeof( char ) ); + /* Le simplexe a trouve une solution */ + PNE_DeterminerLesVariablesFractionnaires( Pne, PosVarHeuristique ); + NombreDeMacroIterations++; + goto TentativeDeFixationDeBorne; +} +else if ( Pne->NombreDeVariablesAValeurFractionnaire == 0 ) { + /* L'heuristique a trouve une solution entiere */ + Critere = Pne->Z0; + for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) Critere+= Pne->LTrav[i] * Pne->UTrav[i]; + printf("!!!!!!!!!!!!!!!!!!!! critere de l'heuristique %e valeur courante optimale %e\n",Critere,Pne->CoutOpt); + + if ( fabs( Critere - Pne->Critere ) < 1.e-7 ) { + printf("Solution entiere trouvee le noeud sera un noeud terminal \n"); + LeNoeudEstTerminal = OUI_PNE; + } + if ( Critere < Pne->CoutOpt ) { + printf("On archive la solution trouvee par l'heuristique\n"); + /* On archive quand meme la solution dans la partie PNE mais attention, les variables duales archivees ne sont pas bonnes. + Cependant on les aura pour la solution optimale */ + PNE_ArchiverLaSolutionCourante( Pne ); + /* Il faut mettre les valeurs des variables duales en accord avec la solution archivee */ + for ( i = 0 ; i < Pne->NombreDeContraintesTrav ; i++ ) { + Pne->VariablesDualesDesContraintesTrav[i] = VarDualesContraintesHeuristique[i]; + } + + /* On met a jour la partie branch and bound */ + + /* Attention ce n'est pas encore parfait du point de vue du branch and bound */ + + Bb->CoutDeLaMeilleureSolutionEntiere = Critere; /* Afin de pouvoir la trouver */ + Bb->NoeudDeLaMeilleureSolutionEntiere = Bb->NoeudEnExamen; /* Ce qui n'est pas tout a fait exact mais cela n'est pas genant */ + Bb->NumeroDeProblemeDeLaSolutionAmeliorante = Bb->NombreDeProblemesResolus; + + Bb->UtiliserCoutDeLaMeilleureSolutionEntiere = OUI_SPX; + Bb->NombreDeSolutionsEntieresTrouvees++; + + } + + goto ArretHeuristique; + +} + +/* Recuperation des donnees initiales et liberation memoire */ +ArretHeuristique: + +if ( LeNoeudEstTerminal == NON_PNE ) { + Pne->VariableLaPlusFractionnaire = VariableAInstancier; + Pne->CestTermine = NON_PNE; + /* Si le noeud n'est pas terminal on recupere les valeurs initiales */ + memcpy( (char *) Pne->UTrav , (char *) UTravSv , Pne->NombreDeVariablesTrav * sizeof( double ) ); + memcpy( (char *) Pne->UminTrav , (char *) UminTravSv , Pne->NombreDeVariablesTrav * sizeof( double ) ); + memcpy( (char *) Pne->UmaxTrav , (char *) UmaxTravSv , Pne->NombreDeVariablesTrav * sizeof( double ) ); +} +else { + /* Si le noeud est terminal on garde les valeurs et on renseigne les couts reduits et les variables duales */ + Pne->VariableLaPlusFractionnaire = -1; + Pne->CestTermine = OUI_PNE; + memcpy( (char *) Pne->CoutsReduits , (char *) CoutsRedHeuristique , Pne->NombreDeVariablesTrav * sizeof( double ) ); + for ( i = 0 ; i < Pne->NombreDeContraintesTrav ; i++ ) { + Pne->VariablesDualesDesContraintesTrav[i] = VarDualesContraintesHeuristique[i]; + } +} + +free( UTravSv ); +free( UminTravSv ); +free( UmaxTravSv ); +free( PosVarHeuristique ); +free( CoutsRedHeuristique ); +free( ComplementDeLaBaseHeuristique ); +free( VarDualesContraintesHeuristique ); +free( PosVarEcartCoupesHeuristique ); + +free( UminX ); +free( UmaxX ); +free( UX ); +free( PX ); +free( UminM ); +free( UmaxM ); +free( UM ); +free( PM ); +free( CplX ); +free( PecX ); +free( CplM ); +free( PecM ); + +return; +} + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_heuristique_RINS.c b/src/ext/Sirius_Solver/pne/pne_heuristique_RINS.c new file mode 100644 index 0000000000..815c958489 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_heuristique_RINS.c @@ -0,0 +1,148 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Methode RINS Danna - Rothberg - Le Pape + + Attention, lorsque ce module est appele les variables + UminTrav UmaxTrav et TypeDeBorneTrav on ete remises a leur + valeur du noeud racine. Donc leurs valeurs n'inclut pas + les instanciations faites en amont du noeud a partir duquel + on demarre. + Par contre les structures du simplexe se trouvent dans l'etat + du dernier noeud resolu (bornes et types de bornes). + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 1 + +/*----------------------------------------------------------------------------*/ +/* Methode RINS Danna - Rothberg - Le Pape */ +char PNE_HeuristiqueRINS( PROBLEME_PNE * Pne ) +{ +int Var; double * UOpt; double * U; int NombreDeVariables; double Zero; int * TypeDeBorne; +double * Umin; double * Umax; int NbFix; BB * Bb; char OK; double * USv; int NbFixInit; +int NbLibres; MATRICE_DE_CONTRAINTES * Contraintes; char ProblemeTropGros; + +ProblemeTropGros = NON_PNE; + +Bb = (BB *) Pne->ProblemeBbDuSolveur; +Contraintes = NULL; + +/* On fixe les variables qui ont la meme valeur dans la solution courante et dans la + meilleure solution entiere */ +Zero = 1.e-7; +NombreDeVariables = Pne->NombreDeVariablesTrav; +UOpt = Pne->UOpt; +U = Pne->UTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +Umin = Pne->UminTrav; +Umax = Pne->UmaxTrav; +NbFix = 0; +NbFixInit = 0; +NbLibres = 0; + +USv = Pne->ValeurLocale; +memcpy( (char *) USv, (char *) U, NombreDeVariables * sizeof( double ) ); + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) NbFixInit++; + else if ( Umin[Var] == Umax[Var] ) NbFixInit++; + if ( Pne->TypeDeVariableTrav[Var] != ENTIER && 0 ) continue; + if ( fabs( U[Var] - UOpt[Var] ) < Zero ) { + TypeDeBorne[Var] = VARIABLE_FIXE; + U[Var] = UOpt[Var]; + Umin[Var] = UOpt[Var]; + Umax[Var] = UOpt[Var]; + NbFix++; + } +} + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBorne[Var] != VARIABLE_FIXE ) { + if ( Umin[Var] != Umax[Var] ) NbLibres++; + } +} + +printf("Methode RINS NbFix = %d NbFixInit = %d NbLibres = %d NombreDeVariables = %d\n",NbFix,NbFixInit,NbLibres,NombreDeVariables); + +if ( NbFix <= 0 ) goto Termine; + +OK = PNE_HeuristiqueEvaluerTailleDuProbleme( Pne ); +if ( OK == NON_PNE ) ProblemeTropGros = OUI_PNE; + +if ( OK == OUI_PNE ) { + /* Construction de ma matrice des contraintes */ + Contraintes = PNE_HeuristiqueConstruireMatriceDeContraintes( Pne ); + if ( Contraintes == NULL ) goto Termine; + + /* Resolution du branch and bound reduit */ + OK = PNE_HeuristiqueResolutionBranchAndBoundReduit( Pne, Contraintes ); +} + +if ( OK == NON_PNE ) { + Pne->NombreDEchecsSuccessifsHeuristiqueRINS++; + if ( Pne->NombreDEchecsSuccessifsHeuristiqueRINS >= NB_MAX_ECHECS_SUCCESSIFS_HEURISTIQUE && 0 ) { + Pne->FaireHeuristiqueRINS = NON_PNE; + if ( Pne->NombreDeSolutionsHeuristiqueRINS <= 0 ) Pne->NombreDeReactivationsSansSuccesHeuristiqueRINS++; + if ( Pne->NombreDeReactivationsSansSuccesHeuristiqueRINS > NB_MAX_REACTIVATION_SANS_SUCCES ) { + Pne->StopHeuristiqueRINS = OUI_PNE; + printf("****************** arret definitif RINS \n"); + } + else printf(" !!!!!!!!!!!! On positionne a FaireHeuristiqueRINS NON_PNE \n"); + } + goto Termine; +} + +/* On a trouve une solution et elle a ete controlee et archivee */ + +Pne->NombreDEchecsSuccessifsHeuristiqueRINS = 0; +Pne->NombreDeSolutionsHeuristiqueRINS++; +Pne->NombreDeReactivationsSansSuccesHeuristiqueRINS = 0; + +Termine: + +Pne->CestTermine = NON_PNE; + +memcpy( (char *) U, (char *) USv, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) TypeDeBorne, (char *) Pne->TypeDeBorneTravSv, NombreDeVariables * sizeof( int ) ); +memcpy( (char *) Umax, (char *) Pne->UmaxTravSv, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) Umin, (char *) Pne->UminTravSv, NombreDeVariables * sizeof( double ) ); + +PNE_HeuristiqueLibererMatriceDeContraintes( Contraintes ); + +return( ProblemeTropGros ); +} + + diff --git a/src/ext/Sirius_Solver/pne/pne_heuristique_pilotage.c b/src/ext/Sirius_Solver/pne/pne_heuristique_pilotage.c new file mode 100644 index 0000000000..497ba459cc --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_heuristique_pilotage.c @@ -0,0 +1,164 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Heuristique, on fixe des variables peu fractionnaires et + on resout le probleme dans l'espoir de trouver une solution + entiere. + Attention, lorsque ce module est appele les variables + UminTrav UmaxTrav et TypeDeBorneTrav on ete remises a leur + valeur du noeud racine. Donc leurs valeurs n'inclut pas + les instanciations faites en amont du noeud a partir duquel + on demarre. + Par contre les structures du simplexe se trouvent dans l'etat + du dernier noeud resolu (bornes et types de bornes). + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 1 + +/*----------------------------------------------------------------------------*/ + +void PNE_HeuristiquePilotage( PROBLEME_PNE * Pne, char * PasDeSolutionEntiereDansSousArbre ) +{ +BB * Bb; CONTROLS * ControlsDuProblemeEnCours; char ProblemeTropGros; + +*PasDeSolutionEntiereDansSousArbre = NON_PNE; + +return; + +if ( Pne->PremFrac < 0 ) return; + +ControlsDuProblemeEnCours = Pne->Controls; +if ( ControlsDuProblemeEnCours != NULL ) { + /* On est deja dans un sous probleme: pas d'heuristique */ + return; +} + +/* Test */ +if ( Pne->YaUneSolutionEntiere == OUI_PNE ) return; +Bb = (BB *) Pne->ProblemeBbDuSolveur; +if ( Bb->NoeudEnExamen->ProfondeurDuNoeud > 0 ) return; +if ( Pne->NombreDeVariablesAValeurFractionnaire > 50 ) { + if ( Pne->NombreDeVariablesAValeurFractionnaire > 0.1 * Pne->NombreDeVariablesEntieresNonFixes ) { + return; + } +} +/* Fin test */ + +/* Si le cout du noeud relaxe est trop grand on a toutes les chances de trouver une + solution trop chere */ +if ( Pne->Critere > 0.9999 * Pne->CoutOpt && Pne->Critere > Pne->CoutOpt - 10 ) { + printf(" critere pas assez en dessous de cout opt pour lancer une heuristique\n"); + return; +} + +Bb = (BB *) Pne->ProblemeBbDuSolveur; + +# if RELANCE_PERIODIQUE_DU_SIMPLEXE_AU_NOEUD_RACINE == OUI_PNE + if ( Bb->NombreDeProblemesResolus % 30 == 0 ) { + PNE_RelanceDuSimplexeAuNoeudRacine( Pne, &ExistenceDUneSolution ); + if ( ExistenceDUneSolution == OUI_PNE ) { + printf("Relance ReducedCostFixingAuNoeudRacine \n"); + PNE_ReducedCostFixingAuNoeudRacine( Pne ); + } + } +# endif + +if ( Bb->NoeudEnExamen->ProfondeurDuNoeud > 2 && 0 ) return; + +/* Au dela d'une certaine profondeur on ne fait les heuristiques qu'a une frequence pas trop + grande. La profondeur du noeud racine est 0 */ +if ( Bb->NoeudEnExamen->ProfondeurDuNoeud > 1 ) { + /* NombreDeProblemesResolus est egal au nombre de noeuds resolus */ + if ( Bb->NombreDeProblemesResolus % CYCLE_HEURISTIQUES != 0 ) return; +} + +ProblemeTropGros = NON_PNE; +if ( Pne->YaUneSolutionEntiere == OUI_PNE ) { + if ( Pne->StopHeuristiqueRINS == NON_PNE ) { + if ( Pne->FaireHeuristiqueRINS == NON_PNE ) { + Pne->NombreDeRefusSuccessifsHeuristiqueRINS++; + if ( Pne->NombreDeRefusSuccessifsHeuristiqueRINS > NB_MAX_REFUS_SUCCESSIFS ) { + Pne->FaireHeuristiqueRINS = OUI_PNE; + Pne->NombreDeSolutionsHeuristiqueRINS = 0; + Pne->NombreDEchecsSuccessifsHeuristiqueRINS = 0; + Pne->NombreDeRefusSuccessifsHeuristiqueRINS = 0; + } + } + if ( Pne->FaireHeuristiqueRINS == OUI_PNE && 0 ) { + printf("PNE_HeuristiqueRINS:\n"); + ProblemeTropGros = PNE_HeuristiqueRINS( Pne ); + if ( ProblemeTropGros == NON_PNE && 0 ) return; + } + } +} + +if ( Pne->StopHeuristiqueFixation == NON_PNE && Pne->YaUneSolutionEntiere == NON_PNE ) { + if ( Pne->FaireHeuristiqueFixation == NON_PNE ) { + Pne->NombreDeRefusSuccessifsHeuristiqueFixation++; + if ( Pne->NombreDeRefusSuccessifsHeuristiqueFixation > NB_MAX_REFUS_SUCCESSIFS ) { + Pne->FaireHeuristiqueFixation = OUI_PNE; + Pne->NombreDeSolutionsHeuristiqueFixation = 0; + Pne->NombreDeRefusSuccessifsHeuristiqueFixation = 0; + Pne->NombreDEchecsSuccessifsHeuristiqueFixation = 0; + } + } + if ( Pne->FaireHeuristiqueFixation == OUI_PNE ) { + /*printf("PNE_HeuristiqueVariablesEntieresFixees:\n");*/ + ProblemeTropGros = PNE_HeuristiqueVariablesEntieresFixees( Pne ); + /*if ( ProblemeTropGros == NON_PNE ) return;*/ + if ( Pne->YaUneSolutionEntiere == OUI_PNE ) return; + } +} + +if ( Pne->StopHeuristiqueFractionalDive == NON_PNE ) { + if ( Pne->FaireHeuristiqueFractionalDive == NON_PNE ) { + Pne->NombreDeRefusSuccessifsHeuristiqueFractionalDive++; + if ( Pne->NombreDeRefusSuccessifsHeuristiqueFractionalDive > NB_MAX_REFUS_SUCCESSIFS ) { + Pne->FaireHeuristiqueFractionalDive = OUI_PNE; + Pne->NombreDeSolutionsHeuristiqueFractionalDive = 0; + Pne->NombreDeRefusSuccessifsHeuristiqueFractionalDive = 0; + Pne->NombreDEchecsSuccessifsHeuristiqueFractionalDive = 0; + } + } + if ( Pne->FaireHeuristiqueFractionalDive == OUI_PNE && 0 ) { + printf("PNE_HeuristiqueRechercheEnProfondeur:\n"); + PNE_HeuristiqueRechercheEnProfondeur( Pne, PasDeSolutionEntiereDansSousArbre ); + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_heuristique_recherche_en_profondeur.c b/src/ext/Sirius_Solver/pne/pne_heuristique_recherche_en_profondeur.c new file mode 100644 index 0000000000..1206955362 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_heuristique_recherche_en_profondeur.c @@ -0,0 +1,407 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recherche en prodondeur a partir du noeud courant. + + ATTENTION c'est a faire + + Attention, lorsque ce module est appele les variables + UminTrav UmaxTrav et TypeDeBorneTrav on ete remises a leur + valeur du noeud racine. Donc leurs valeurs n'inclut pas + les instanciations faites en amont du noeud a partir duquel + on demarre. + Par contre les structures du simplexe se trouvent dans l'etat + du dernier noeud resolu (bornes et types de bornes). + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define NB_MAX_CYCLES 10 +# define NB_MAX_ITERATIONS 100 +# define TAILLE_MOYENNE_MOBILE 3 +# define FIXER_VARIABLES_AU_DEPART OUI_PNE + +# define VARIABLE_LA_MOINS_FRACTIONNAIRE 1 +# define VARIABLE_LA_PLUS_FRACTIONNAIRE 2 +# define TYPE_DE_FIXATION VARIABLE_LA_MOINS_FRACTIONNAIRE + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PNE_HeuristiqueRechercheEnProfondeur( PROBLEME_PNE * Pne, char * PasDeSolutionEntiereDansSousArbre ) +{ +int i ; int j ; int k; int YaUneSolution; int PremFrac; int * SuivFrac; double X; +double * UTrav; char OK; double * UminTrav; double * UmaxTrav; int NombreDeVariablesFixees; +int * NumerosDesVariablesArrondies; double * NouvelleBorneMin; double * NouvelleBorneMax; +int * NumeroDesVariablesPeuFractionnaire; int * PositionDeLaVariable_E; int NbVarDeBaseComplementaires_E; +int * ComplementDeLaBase_E; int NombreMaxDIterations; char * Flag; int NbCycles; +double * USv; int VariableLaPlusFractionnaireSv; double Critere; +int NbMaxCycles; int NombreDeVariablesAValeurFractionnaireSv; double NormeDeFractionnaliteSv; +int NbFix; int NbVarEntFix; int NbVarEntNonFix; int Seuil; +PROBLEME_SPX * Spx; BB * Bb; int NombreDeVariablesEntieresFixees; +int NombreDeVariablesEntieresNonFixesAuDepart; int NombreDeVariablesAValeurFractionnaire[TAILLE_MOYENNE_MOBILE]; +int IndexMoyenneMobile; int SommePourMoyenneMobilePrecedente; int SommePourMoyenneMobile; + +printf("HeuristiqueRechercheEnProfondeur \n"); + +*PasDeSolutionEntiereDansSousArbre = NON_PNE; + +Bb = (BB *) Pne->ProblemeBbDuSolveur; + +NumerosDesVariablesArrondies = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +NouvelleBorneMin = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +NouvelleBorneMax = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +if ( NumerosDesVariablesArrondies == NULL || NouvelleBorneMin == NULL || NouvelleBorneMax == NULL ) { + free( NumerosDesVariablesArrondies ); free( NouvelleBorneMin ); free( NouvelleBorneMax ); + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_HeuristiqueArrondis \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +NbMaxCycles = NB_MAX_CYCLES; + +VariableLaPlusFractionnaireSv = Pne->VariableLaPlusFractionnaire; +NombreDeVariablesAValeurFractionnaireSv = Pne->NombreDeVariablesAValeurFractionnaire; +NormeDeFractionnaliteSv = Pne->NormeDeFractionnalite; + +NumeroDesVariablesPeuFractionnaire = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +Flag = (char *) malloc( Pne->NombreDeVariablesTrav * sizeof( char ) ); +PositionDeLaVariable_E = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +ComplementDeLaBase_E = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); + +USv = Pne->ValeurLocale; +memcpy( (char *) USv, (char *) Pne->UTrav, Pne->NombreDeVariablesTrav * sizeof( double ) ); + +memset( (char *) Flag, 0, Pne->NombreDeVariablesTrav * sizeof( char ) ); + +UTrav = Pne->UTrav; +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; + +NbCycles = 0; +NbFix = 0; +Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur; + +IndexMoyenneMobile = 0; +SommePourMoyenneMobilePrecedente = Pne->NombreDeVariablesAValeurFractionnaire * TAILLE_MOYENNE_MOBILE; + +NbVarEntFix = 0; +NbVarEntNonFix = 0; +NombreDeVariablesFixees = 0; + +NombreDeVariablesEntieresFixees = 0; +NombreDeVariablesEntieresNonFixesAuDepart = 0; +# if FIXER_VARIABLES_AU_DEPART == OUI_PNE + /* 1ere etape: on fixe les variables qui ont deja une valeur entiere */ + for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( Pne->TypeDeVariableTrav[i] != ENTIER ) continue; + if ( Pne->TypeDeBorneTrav[i] == VARIABLE_FIXE ) continue; + if ( Pne->UminTrav[i] == Pne->UmaxTrav[i] ) continue; + NombreDeVariablesEntieresNonFixesAuDepart++; + if ( Pne->LaVariableAUneValeurFractionnaire[i] == OUI_PNE ) continue; + NombreDeVariablesEntieresFixees++; + /* La variable fractionnaire a une variable entiere */ + Flag[i] = 1; + NumerosDesVariablesArrondies[NombreDeVariablesFixees] = i; + if ( fabs( UTrav[i] - UminTrav[i] ) < fabs( UmaxTrav[i] - UTrav[i] ) ) { + NouvelleBorneMin[NombreDeVariablesFixees] = UminTrav[i]; + NouvelleBorneMax[NombreDeVariablesFixees] = UminTrav[i]; + } + else { + NouvelleBorneMin[NombreDeVariablesFixees] = UmaxTrav[i]; + NouvelleBorneMax[NombreDeVariablesFixees] = UmaxTrav[i]; + } + NombreDeVariablesFixees++; + NbFix++; + } +# endif + +NbVarEntNonFix = NombreDeVariablesEntieresNonFixesAuDepart - NombreDeVariablesFixees; + +printf("NbVarEntNonFix %d NombreDeVariablesEntieresNonFixesAuDepart %d\n",NbVarEntNonFix,NombreDeVariablesEntieresNonFixesAuDepart); + +if ( Pne->YaUneSolutionEntiere == OUI_PNE ) { + Seuil = 0.1 * NombreDeVariablesEntieresNonFixesAuDepart; + if ( Seuil < 50 ) Seuil = 50; + if ( NbVarEntNonFix > Seuil ) { + printf("Pas d'heuristique DIVE\n"); + goto Fin; + } +} + +if ( NbMaxCycles < NbVarEntNonFix + 10 ) NbMaxCycles = NbVarEntNonFix + 10; + +if ( NombreDeVariablesFixees > 0 ) { + /* Pour fixer les variables a valeur entiere dans le simplexe */ + + NombreMaxDIterations = 50 * NombreDeVariablesFixees; + if ( NombreMaxDIterations > NB_MAX_ITERATIONS ) NombreMaxDIterations = NB_MAX_ITERATIONS; + + SPX_HeuristiqueArrondis( Spx, + &YaUneSolution, + Pne->NombreDeVariablesTrav, + UTrav, + Pne->TypeDeBorneTrav, + Pne->NombreDeContraintesTrav, + PositionDeLaVariable_E , + &NbVarDeBaseComplementaires_E , + ComplementDeLaBase_E, + NombreMaxDIterations, + NombreDeVariablesFixees, + NumerosDesVariablesArrondies, + NouvelleBorneMin, + NouvelleBorneMax + ); + + + if ( YaUneSolution != OUI_SPX ) { + printf("Fin heuristique DIVE par echec du simplexe apres NbCycles = %d\n",NbCycles); + Pne->NombreDEchecsSuccessifsHeuristiqueFractionalDive++; + if ( Pne->NombreDEchecsSuccessifsHeuristiqueFractionalDive >= NB_MAX_ECHECS_SUCCESSIFS_HEURISTIQUE ) { + Pne->FaireHeuristiqueFractionalDive = NON_PNE; + if ( Pne->NombreDeSolutionsHeuristiqueFractionalDive <= 0 ) Pne->NombreDeReactivationsSansSuccesHeuristiqueFractionalDive++; + if ( Pne->NombreDeReactivationsSansSuccesHeuristiqueFractionalDive > NB_MAX_REACTIVATION_SANS_SUCCES ) { + Pne->StopHeuristiqueFractionalDive = OUI_PNE; + printf("****************** arret definitif DIVE \n"); + } + else printf(" !!!!!!!!!!!! On positionne DIVE a NON_PNE \n"); + } + goto Fin; + } +} + +Debut: + +PremFrac = Pne->PremFrac; +SuivFrac = Pne->SuivFrac; + +/* A ce stade on dispose deja des variables fractionnaires */ + +j = 0; +k = -1; +# if TYPE_DE_FIXATION == VARIABLE_LA_PLUS_FRACTIONNAIRE + i = PremFrac; + while ( i >= 0 ) { + if ( Flag[i] == 0 ) { + k = i; /* La variable n'a pas ete deja fixee */ + break; + } + i = SuivFrac[i]; + } + +# elif TYPE_DE_FIXATION == VARIABLE_LA_MOINS_FRACTIONNAIRE + i = PremFrac; + if ( Flag[i] == 0 ) k = i; /* La variable n'a pas ete deja fixee */ + while ( i >= 0 ) { + if ( Flag[i] == 0 ) k = i; /* La variable n'a pas ete deja fixee */ + i = SuivFrac[i]; + } +# endif + +if ( k == -1 ) { + /* Rien a instancier */ + goto Fin; +} + +X = UTrav[k]; +if ( X - floor( X ) < ceil( X ) - X ) { + Flag[k] = 1; + NumerosDesVariablesArrondies[j] = k; + NouvelleBorneMin[j] = UminTrav[k]; + NouvelleBorneMax[j] = UminTrav[k]; + # if TRACES == 1 + printf("Fixation %d a %e valeur %e\n",k,UminTrav[k],X); + # endif + j++; + +} +else { + Flag[k] = 1; + NumerosDesVariablesArrondies[j] = k; + NouvelleBorneMin[j] = UmaxTrav[k]; + NouvelleBorneMax[j] = UmaxTrav[k]; + # if TRACES == 1 + printf("Fixation %d a %e valeur %e\n",k,UmaxTrav[k],X); + # endif + j++; +} + +NombreDeVariablesFixees = j; + +NbFix += NombreDeVariablesFixees; + +if ( NombreDeVariablesFixees == 0 ) { + printf("Fin par NombreDeVariablesFixees = %d\n",NombreDeVariablesFixees); + goto Fin; +} + +NombreMaxDIterations = 50 * NombreDeVariablesFixees; +if ( NombreMaxDIterations > NB_MAX_ITERATIONS ) NombreMaxDIterations = NB_MAX_ITERATIONS; + +NombreMaxDIterations = -1; + +SPX_HeuristiqueArrondis( Spx, + &YaUneSolution, + Pne->NombreDeVariablesTrav, + UTrav, + Pne->TypeDeBorneTrav, + Pne->NombreDeContraintesTrav, + PositionDeLaVariable_E , + &NbVarDeBaseComplementaires_E , + ComplementDeLaBase_E, + NombreMaxDIterations, + NombreDeVariablesFixees, + NumerosDesVariablesArrondies, + NouvelleBorneMin, + NouvelleBorneMax + ); + +OK = OUI_PNE; +if ( YaUneSolution != OUI_SPX ) { + + printf("Fin heuristique DIVE par echec du simplexe apres NbCycles = %d\n",NbCycles); + + # if TRACES == 1 + printf("Pas de solution dans l'heuristique NbFix %d\n",NbFix); + if ( Spx->Iteration < NombreMaxDIterations - 10 ) { + printf(" et on n'est pas sorti par Max Iteration \n"); + } + else printf(" Nombre max d'iterations atteint Spx->Iteration %d NombreMaxDIterations %d\n",Spx->Iteration,NombreMaxDIterations); + # endif + OK = NON_PNE; +} +else { + Critere = Pne->Z0; + for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) Critere += Pne->LTrav[i] * UTrav[i]; + if ( Critere >= Pne->CoutOpt ) { + printf("Critere >= Pne->CoutOpt CoutOpt %e\n",Pne->CoutOpt); + OK = NON_PNE; + } +} + +if ( OK == OUI_PNE ) { + PNE_DeterminerLesVariablesFractionnaires( Pne, PositionDeLaVariable_E ); + if ( Pne->NombreDeVariablesAValeurFractionnaire > 0 ) { + /* Controle de la decroissance du nombre de variables a valeur fractionnaire */ + if ( IndexMoyenneMobile < TAILLE_MOYENNE_MOBILE ) { + NombreDeVariablesAValeurFractionnaire[IndexMoyenneMobile] = Pne->NombreDeVariablesAValeurFractionnaire; + IndexMoyenneMobile++; + } + else { + /* On fait de la place a la fin */ + for ( i = 0 ; i < TAILLE_MOYENNE_MOBILE - 1 ; i++ ) { + NombreDeVariablesAValeurFractionnaire[i] = NombreDeVariablesAValeurFractionnaire[i+1]; + } + /* On range la valeur a la fin */ + NombreDeVariablesAValeurFractionnaire[TAILLE_MOYENNE_MOBILE - 1] = Pne->NombreDeVariablesAValeurFractionnaire; + } + + SommePourMoyenneMobile = 0; + if ( IndexMoyenneMobile == TAILLE_MOYENNE_MOBILE ) { + /* Calcul de la moyenne mobile */ + for ( i = 0 ; i < TAILLE_MOYENNE_MOBILE ; i++ ) SommePourMoyenneMobile += NombreDeVariablesAValeurFractionnaire[i]; + } + if ( SommePourMoyenneMobile <= SommePourMoyenneMobilePrecedente ) { + if ( IndexMoyenneMobile == TAILLE_MOYENNE_MOBILE ) SommePourMoyenneMobilePrecedente = SommePourMoyenneMobile; + NbCycles++; + if ( NbCycles < NbMaxCycles ) goto Debut; + } + + # if TRACES == 1 + printf("Fin heuristique par nombre de cycles atteint\n"); + # endif + + if ( SommePourMoyenneMobile <= SommePourMoyenneMobilePrecedente ) { + printf("Fin heuristique DIVE par nombre max de cycles \n"); + } + else { + printf("Fin heuristique DIVE SommePourMoyenneMobile %d SommePourMoyenneMobilePrecedente %d\n", + SommePourMoyenneMobile,SommePourMoyenneMobilePrecedente); + } + + OK = NON_PNE; + + } +} + +if ( OK == NON_PNE ) { + Pne->NombreDEchecsSuccessifsHeuristiqueFractionalDive++; + if ( Pne->NombreDEchecsSuccessifsHeuristiqueFractionalDive >= NB_MAX_ECHECS_SUCCESSIFS_HEURISTIQUE ) { + Pne->FaireHeuristiqueFractionalDive = NON_PNE; + if ( Pne->NombreDeSolutionsHeuristiqueFractionalDive <= 0 ) Pne->NombreDeReactivationsSansSuccesHeuristiqueFractionalDive++; + if ( Pne->NombreDeReactivationsSansSuccesHeuristiqueFractionalDive > NB_MAX_REACTIVATION_SANS_SUCCES ) { + Pne->StopHeuristiqueFractionalDive = OUI_PNE; + printf("****************** arret definitif DIVE \n"); + } + else printf(" !!!!!!!!!!!! On positionne DIVE a NON_PNE \n"); + } + goto Fin; +} + +# if TRACES == 1 + printf("Heuristic found Critere %e \n",Critere); +# endif +printf("Heuristic found \n"); + +/* Solution trouvee */ + +/* On archive la solution: attention il faudra aussi y mettre VariablesDualesDesContraintesTravEtDesCoupes */ + +PNE_HeuristiqueArchivageSolutionEtMajBranchAndBound( Pne, Critere ); + +Fin: + +free( NumeroDesVariablesPeuFractionnaire ); +free( PositionDeLaVariable_E ); +free( ComplementDeLaBase_E ); +free( Flag ); + +Pne->CestTermine = NON_PNE; + +memcpy( (char *) Pne->UTrav, (char *) USv, Pne->NombreDeVariablesTrav * sizeof( double ) ); + +Pne->VariableLaPlusFractionnaire = VariableLaPlusFractionnaireSv; +Pne->NombreDeVariablesAValeurFractionnaire = NombreDeVariablesAValeurFractionnaireSv; +Pne->NormeDeFractionnalite = NormeDeFractionnaliteSv; + +SPX_RAZHeuristiqueArrondis( (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur ); + +free( NumerosDesVariablesArrondies ); +free( NouvelleBorneMin ); +free( NouvelleBorneMax ); + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_heuristique_resolution_branch_and_bound_reduit.c b/src/ext/Sirius_Solver/pne/pne_heuristique_resolution_branch_and_bound_reduit.c new file mode 100644 index 0000000000..2cbff842f8 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_heuristique_resolution_branch_and_bound_reduit.c @@ -0,0 +1,255 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution d'un branch and bound reduit pour les heuristiques. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PNE_HeuristiqueArchivageSolutionEtMajBranchAndBound( PROBLEME_PNE * Pne, double Critere ) +{ +int Var; BB * Bb; double X; int NbNonFix; int * TypeDeVariable; int * TypeDeBorne; +double * Xmin; double * Xmax; double EcartBorneInf; + +Bb = (BB *) Pne->ProblemeBbDuSolveur; + +/* On archive la solution: attention il faudra aussi y mettre VariablesDualesDesContraintesTravEtDesCoupes */ + +PNE_ArchiverLaSolutionCourante( Pne ); +Bb->CoutDeLaMeilleureSolutionEntiere = Critere; +Bb->UtiliserCoutDeLaMeilleureSolutionEntiere = OUI_SPX; +Bb->NombreDeProblemesResolus++; + +/* Si on met SolutionEntiereTrouveeParHeuristique = OUI, la recherche en profondeur s'arrete. + Sinon elle continue tant qu'elle ne trouve pas de solution entiere par elle meme dans la limite + d'un certain nombre de problemes */ + +BB_RechercherLeMeilleurMinorant( Bb, RECHERCHER_LE_PLUS_PETIT ); +X = fabs( Bb->ValeurDuMeilleurMinorant ); +X = 0.01 * ( X + 1.e-7 ); +EcartBorneInf = (Bb->CoutDeLaMeilleureSolutionEntiere - Bb->ValeurDuMeilleurMinorant) / X; +EcartBorneInf = fabs( EcartBorneInf ); + +if ( EcartBorneInf > 100 ) { + /* La solution heuristique est mauvaise on prefere continuer dans la recherche en profondeur */ + Bb->SolutionEntiereTrouveeParHeuristique = NON; +} +else { + Bb->SolutionEntiereTrouveeParHeuristique = OUI; +} + +/* Pour evaluer une profondeur on compte le nombre de variables entieres qui n'etaient pas fixees */ + +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; + +NbNonFix = 0; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( TypeDeVariable[Var] != ENTIER ) continue; + if ( TypeDeBorne[Var] != VARIABLE_FIXE && Xmin[Var] != Xmax[Var] ) NbNonFix++; +} + + +if ( Bb->NombreDeSolutionsEntieresTrouvees == 0 ) { + Bb->NombreDeSolutionsEntieresTrouvees++; + Bb->ProfondeurMoyenneDesSolutionsEntieres = NbNonFix; +} +else { + X = 0.; + if ( Bb->ProfondeurMoyenneDesSolutionsEntieres >= 0 ) { + X = Bb->ProfondeurMoyenneDesSolutionsEntieres * Bb->NombreDeSolutionsEntieresTrouvees; + } + X += NbNonFix; + Bb->NombreDeSolutionsEntieresTrouvees++; + X /= Bb->NombreDeSolutionsEntieresTrouvees; + Bb->ProfondeurMoyenneDesSolutionsEntieres = (int) ceil( X ); +} + +Bb->ForcerAffichage = OUI; + +return; +} + +/*----------------------------------------------------------------------------*/ + +char PNE_HeuristiqueResolutionBranchAndBoundReduit( PROBLEME_PNE * Pne, + MATRICE_DE_CONTRAINTES * Contraintes ) +{ +int Var; double Critere; char OK; PROBLEME_A_RESOUDRE Probleme; int NbMaxSol; CONTROLS Controls; +int Cnt; int il; int ilMax; double ToleranceViolation; double S; + +Probleme.NombreDeVariables = Pne->NombreDeVariablesTrav; +Probleme.TypeDeVariable = Pne->TypeDeVariableTrav; +Probleme.TypeDeBorneDeLaVariable = Pne->TypeDeBorneTrav; +Probleme.X = Pne->UTrav; +Probleme.Xmax = Pne->UmaxTrav; +Probleme.Xmin = Pne->UminTrav; +Probleme.CoutLineaire = Pne->LTrav; +Probleme.NombreDeContraintes = Contraintes->NombreDeContraintes; +Probleme.SecondMembre = Contraintes->SecondMembre; +Probleme.Sens = Contraintes->Sens; +Probleme.IndicesDebutDeLigne = Contraintes->IndexDebut; +Probleme.NombreDeTermesDesLignes = Contraintes->NombreDeTermes; +Probleme.CoefficientsDeLaMatriceDesContraintes = Contraintes->Coefficient; +Probleme.IndicesColonnes = Contraintes->Colonne; +Probleme.VariablesDualesDesContraintes = NULL; +Probleme.SortirLesDonneesDuProbleme = OUI_PNE; +Probleme.AlgorithmeDeResolution = SIMPLEXE; /* SIMPLEXE ou POINT_INTERIEUR */ +Probleme.CoupesLiftAndProject = NON_PNE; + +Probleme.AffichageDesTraces = OUI_PNE; + +Probleme.FaireDuPresolve = NON_PNE /* OUI_PNE */; + +Probleme.TempsDExecutionMaximum = 10; + +NbMaxSol = -1 /*1*/; + +Probleme.NombreMaxDeSolutionsEntieres = NbMaxSol; + +Probleme.ToleranceDOptimalite = 1.e-0; /* C'est en % donc 1.e-4 ca fait 1.e-6 */ + +Controls.Pne = Pne; +Controls.PneFils = NULL; +/*Controls.PresolveFils = NULL;*/ +Controls.PresolveUniquement = NON_PNE; +Controls.FaireDuVariableProbing = OUI_PNE; +Controls.RechercherLesCliques = OUI_PNE; + +/*printf("NombreDeVariablesAValeurFractionnaire %d NombreDeVariablesEntieresTrav %d Nombre de contraintes %d \n", + Pne->NombreDeVariablesAValeurFractionnaire,Pne->NombreDeVariablesEntieresTrav,Contraintes->NombreDeContraintes);*/ + +PNE_SolveurProblemeReduit( &Probleme, &Controls ); + +/*printf("Probleme.ExistenceDUneSolution %d\n",Probleme.ExistenceDUneSolution);*/ + +OK = NON_PNE; +if ( Probleme.ExistenceDUneSolution == SOLUTION_OPTIMALE_TROUVEE ) { + /*printf("Solution optimale trouvee\n");*/ + OK = OUI_PNE; +} +if ( Probleme.ExistenceDUneSolution == ARRET_PAR_LIMITE_DE_TEMPS_AVEC_SOLUTION_ADMISSIBLE_DISPONIBLE ) OK = OUI_PNE; + +/* Controle du cout de la solution */ +if ( OK == OUI_PNE ) { + Critere = Pne->Z0; + for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) Critere += Pne->LTrav[Var] * Pne->UTrav[Var]; + + if ( Critere >= Pne->CoutOpt + 1.e-4 && Pne->YaUneSolutionEntiere == OUI_PNE ) { + /* Solution plus chere */ + OK = NON_PNE; + /*printf("!!!! Warning dans l'Heuristique Critere %e Pne->CoutOpt %e --------------------\n", + Critere,Pne->CoutOpt);*/ + /*exit(0);*/ + } +} + +if ( OK == NON_PNE ) goto Termine; + + +/* Verification admissibilite */ +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_FIXE ) continue; + if ( Pne->UTrav[Var] > Pne->UmaxTrav[Var] + 1.e-6 ) { + /*printf("!!!!!!! Var %d UTrav %e UmaxTrav %e\n",Var,Pne->UTrav[Var],Pne->UmaxTrav[Var]);*/ + /*exit(0);*/ + OK = NON_PNE; + break; + } + if ( Pne->UTrav[Var] < Pne->UminTrav[Var] - 1.e-6 ) { + /*printf("!!!!!!! Var %d UTrav %e UminTrav %e\n",Var,Pne->UTrav[Var],Pne->UminTrav[Var]);*/ + /*exit(0);*/ + OK = NON_PNE; + break; + } +} + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + /* Verifier les violations de contraintes */ + S = 0.; + il = Pne->MdebTrav[Cnt]; + ilMax = il + Pne->NbTermTrav[Cnt]; + while ( il < ilMax ) { + S += Pne->ATrav[il] * Pne->UTrav[Pne->NuvarTrav[il]]; + il++; + } + ToleranceViolation = 1.e-6; + if ( Pne->SensContrainteTrav[Cnt] == '=' ) { + if ( fabs( S - Pne->BTrav[Cnt] ) > ToleranceViolation ) { + /*printf("!!!!!!!!! Contrainte d'egalite %d violee: valeur calculee %e second membre %e violation %e\n",Cnt,S, + Pne->BTrav[Cnt],fabs( S - Pne->BTrav[Cnt] ));*/ + /*exit(0);*/ + OK = NON_PNE; + break; + } + } + else if ( Pne->SensContrainteTrav[Cnt] == '<' ) { + if ( S > Pne->BTrav[Cnt] + ToleranceViolation ) { + /*printf("!!!!!!!!!!!!!!! Contrainte %d de type < ou = violee: valeur calculee %e second membre %e violation %e\n",Cnt,S, + Pne->BTrav[Cnt],fabs( S - Pne->BTrav[Cnt] ));*/ + /*exit(0);*/ + OK = NON_PNE; + break; + } + } + else if ( Pne->SensContrainteTrav[Cnt] == '>' ) { + if ( S < Pne->BTrav[Cnt] - ToleranceViolation ) { + /*printf("Contrainte %d de type > ou = violee: valeur calculee %e second membre %e violation %e\n",Cnt,S, + Pne->BTrav[Cnt],fabs( S - Pne->BTrav[Cnt] ));*/ + /*exit(0);*/ + OK = NON_PNE; + break; + } + } +} + +if ( OK == NON_PNE ) goto Termine; +/* Solution trouvee */ + +/* On archive la solution: attention il faudra aussi y mettre VariablesDualesDesContraintesTravEtDesCoupes */ + +PNE_HeuristiqueArchivageSolutionEtMajBranchAndBound( Pne, Critere ); + +Termine: + +return( OK ); + +} + diff --git a/src/ext/Sirius_Solver/pne/pne_heuristique_utilitaires.c b/src/ext/Sirius_Solver/pne/pne_heuristique_utilitaires.c new file mode 100644 index 0000000000..6b8dd9ad4a --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_heuristique_utilitaires.c @@ -0,0 +1,267 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Utilitaires de creation de matrice de contraintes pour les + heuristiques. + Attention, lorsque ce module est appele les variables + UminTrav UmaxTrav et TypeDeBorneTrav on ete remises a leur + valeur du noeud racine. Donc leurs valeurs n'inclut pas + les instanciations faites en amont du noeud a partir duquel + on demarre. + Par contre les structures du simplexe se trouvent dans l'etat + du dernier noeud resolu (bornes et types de bornes). + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define EPS_COUT_OPT 1.e-4 +# define MARGE_OPTIMALITE 1.e-6 + +/*----------------------------------------------------------------------------*/ +void PNE_HeuristiqueLibererMatriceDeContraintes( MATRICE_DE_CONTRAINTES * Contraintes ) +{ +if ( Contraintes == NULL ) return; +free( Contraintes->IndexDebut ); +free( Contraintes->NombreDeTermes ); +free( Contraintes->SecondMembre ); +free( Contraintes->Sens ); +free( Contraintes->Colonne ); +free( Contraintes->Coefficient ); +free( Contraintes ); +return; +} +/*----------------------------------------------------------------------------*/ + +MATRICE_DE_CONTRAINTES * PNE_HeuristiqueConstruireMatriceDeContraintes( PROBLEME_PNE * Pne ) +{ +int NombreDeContraintesNatives; int NbTermesNecessaires; int * IndexDebut; int * NombreDeTermes; +int NombreDeVariablesNatives; int il; int NbTermesNatif; int NombreDeContraintes; +int NbContraintesNecessaires; double * SecondMembre; char * Sens; int * Colonne; double * Coefficient; +MATRICE_DE_CONTRAINTES * Contraintes; +# if UTILISER_UNE_CONTRAINTE_DE_COUT_MAX == NON_PNE + double Marge; int Nb; double * L; int Var; +# endif +# if UTILISER_LES_COUPES == OUI_PNE + int Cnt; int ilC; int ilCmax; +# endif + +Contraintes = NULL; +/* Allocation */ +Contraintes = (MATRICE_DE_CONTRAINTES *) malloc( sizeof( MATRICE_DE_CONTRAINTES ) ); +if ( Contraintes == NULL ) return( NULL ); + +NombreDeContraintesNatives = Pne->NombreDeContraintesTrav; +NombreDeVariablesNatives = Pne->NombreDeVariablesTrav; +NbContraintesNecessaires = NombreDeContraintesNatives; +if ( Pne->YaUneSolutionEntiere == OUI_PNE ) { + /* Pour la borne sur le cout */ + NbContraintesNecessaires++; +} +# if UTILISER_LES_COUPES == OUI_PNE + NbContraintesNecessaires += Pne->Coupes.NombreDeContraintes; +# endif + +NbTermesNatif = Pne->TailleAlloueePourLaMatriceDesContraintes; + +NbTermesNecessaires = NbTermesNatif; + +# if UTILISER_UNE_CONTRAINTE_DE_COUT_MAX == OUI_PNE + if ( Pne->YaUneSolutionEntiere == OUI_PNE ) { + /* Pour la borne sur le cout */ + NbTermesNecessaires += NombreDeVariablesNatives; + } +# endif + +# if UTILISER_LES_COUPES == OUI_PNE + /* Les coupes */ + for ( Cnt = 0 ; Cnt < Pne->Coupes.NombreDeContraintes ; Cnt++ ) NbTermesNecessaires += Pne->Coupes.Mdeb[Cnt] + Pne->Coupes.NbTerm[Cnt]; +# endif + +IndexDebut = (int *) malloc( NbContraintesNecessaires * sizeof( int ) ); +NombreDeTermes = (int *) malloc( NbContraintesNecessaires * sizeof( int ) ); +SecondMembre = (double *) malloc( NbContraintesNecessaires * sizeof( double ) ); +Sens = (char *) malloc( NbContraintesNecessaires * sizeof( char ) ); +Colonne = (int *) malloc( NbTermesNecessaires * sizeof( int ) ); +Coefficient = (double *) malloc( NbTermesNecessaires * sizeof( double ) ); +if ( IndexDebut == NULL || NombreDeTermes == NULL || SecondMembre == NULL || Sens == NULL || Colonne == NULL || Coefficient == NULL ) { + free( IndexDebut ); free( NombreDeTermes ); free( SecondMembre ); free( Sens ); free( Colonne ); free( Coefficient ); + free( Contraintes ); + return( NULL ); +} +Contraintes->IndexDebut = IndexDebut; +Contraintes->NombreDeTermes = NombreDeTermes; +Contraintes->SecondMembre = SecondMembre; +Contraintes->Sens = Sens; +Contraintes->Colonne = Colonne; +Contraintes->Coefficient = Coefficient; + +/* Recopie de la matrice des contraintes natives */ +/* Attention on suppose que les contraintes sont rangees dans l'ordre */ +memcpy( (char *) IndexDebut, (char *) Pne->MdebTrav, NombreDeContraintesNatives * sizeof( int ) ); +memcpy( (char *) NombreDeTermes, (char *) Pne->NbTermTrav, NombreDeContraintesNatives * sizeof( int ) ); +memcpy( (char *) SecondMembre, (char *) Pne->BTrav, NombreDeContraintesNatives * sizeof( double ) ); +memcpy( (char *) Sens, (char *) Pne->SensContrainteTrav, NombreDeContraintesNatives * sizeof( char ) ); +memcpy( (char *) Colonne, (char *) Pne->NuvarTrav, NbTermesNatif * sizeof( int ) ); +memcpy( (char *) Coefficient, (char *) Pne->ATrav, NbTermesNatif * sizeof( double ) ); + +NombreDeContraintes = NombreDeContraintesNatives; +il = NbTermesNatif; + +# if UTILISER_UNE_CONTRAINTE_DE_COUT_MAX == OUI_PNE + /* creation de la contrainte de cout max */ + if ( Pne->YaUneSolutionEntiere == OUI_PNE ) { + L = Pne->LTrav; + IndexDebut[NombreDeContraintes] = il; + Nb = 0; + for ( Var = 0 ; Var < NombreDeVariablesNatives ; Var++ ) { + if ( L[Var] != 0.0 ) { + Colonne[il] = Var; + Coefficient[il] = L[Var]; + il++; Nb++; + } + } + NombreDeTermes[NombreDeContraintes] = Nb; + + Marge = EPS_COUT_OPT * fabs( Pne->CoutOpt ); + + SecondMembre[NombreDeContraintes] = Pne->CoutOpt - Marge - MARGE_OPTIMALITE; + Sens[NombreDeContraintes] = '<'; + NombreDeContraintes++; + } +# endif + +# if UTILISER_LES_COUPES == OUI_PNE + /* Les coupes */ + for ( Cnt = 0 ; Cnt < Pne->Coupes.NombreDeContraintes ; Cnt++ ) { + ilC = Pne->Coupes.Mdeb[Cnt] ; + ilCmax = ilC + Pne->Coupes.NbTerm[Cnt]; + Nb = 0; + IndexDebut[NombreDeContraintes] = il; + while ( ilC < ilCmax ) { + Colonne[il] = Pne->Coupes.Nuvar[ilC]; + Coefficient[il] = Pne->Coupes.A[ilC]; + ilC++; il++; Nb++; + } + NombreDeTermes[NombreDeContraintes] = Nb; + SecondMembre[NombreDeContraintes] = Pne->Coupes.B[Cnt]; + Sens[NombreDeContraintes] = '<'; + NombreDeContraintes++; + } +# endif + +Contraintes->NombreDeContraintes = NombreDeContraintes; + +return( Contraintes ); +} + +/*----------------------------------------------------------------------------*/ +/* On calcule le nombre de variables non fixes et le nombre de contraintes + qui en en resulte lorque qu'on utilise une heuristique qui consiste a fixer + certaines variables */ +char PNE_HeuristiqueEvaluerTailleDuProbleme( PROBLEME_PNE * Pne ) +{ +int NbCntRestantes; int NbVarRestantes; int NbNTermesNonNulsRestants; int Cnt; +int il; int ilMax; int * Mdeb; int * NbTerm; int * TypeDeBorne; double * Xmin; +double * Xmax; int Var; int Nbt; int * NuVar; char OK; int NbVarEntieresRestantes; +int * NumerosDesVariablesEntieresTrav; + +NbCntRestantes = 0; +NbVarRestantes = 0; +NbVarEntieresRestantes = 0; +NbNTermesNonNulsRestants = 0; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +NuVar = Pne->NuvarTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; +NumerosDesVariablesEntieresTrav = Pne->NumerosDesVariablesEntieresTrav; + +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( TypeDeBorne[Var] != VARIABLE_FIXE && Xmin[Var] != Xmax[Var] ) NbVarRestantes++; +} + +for ( il = 0 ; il < Pne->NombreDeVariablesEntieresTrav ; il++ ) { + Var = NumerosDesVariablesEntieresTrav[il]; + if ( TypeDeBorne[Var] != VARIABLE_FIXE && Xmin[Var] != Xmax[Var] ) NbVarEntieresRestantes++; +} + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + Nbt = 0; + /* On ne compte pas les contraintes a 1 terme car il y a beaucoup de chances pour qu'elles + ne soient pas penalisantes */ + while ( il < ilMax ) { + Var = NuVar[il]; + if ( TypeDeBorne[Var] != VARIABLE_FIXE && Xmin[Var] != Xmax[Var] ) Nbt++; + il++; + } + + if ( Nbt > 1 ) { + NbNTermesNonNulsRestants += Nbt; + NbCntRestantes++; + } + +} + +OK = NON_PNE; +ilMax = Mdeb[Pne->NombreDeContraintesTrav-1] + NbTerm[Pne->NombreDeContraintesTrav-1]; +if ( NbNTermesNonNulsRestants < 0.1 * ilMax || 1) { + OK = OUI_PNE; + /*printf("On accepte l'heuristique NbNTermesNonNulsRestants %d seuil %d\n",NbNTermesNonNulsRestants, (int) (0.10 * ilMax) );*/ +} +else if ( NbCntRestantes < 0.5 * Pne->NombreDeContraintesTrav ) { + OK = OUI_PNE; + /*printf("On accepte l'heuristique NbCntRestantes %d seuil %d\n",NbCntRestantes,(int) ( 0.5 * Pne->NombreDeContraintesTrav ));*/ +} +else if ( ( NbVarRestantes < (int) ( 0.5 * Pne->NombreDeVariablesNonFixes ) && + NbVarEntieresRestantes < (int) ( 0.1 * Pne->NombreDeVariablesEntieresNonFixes ) ) || + ( NbVarRestantes <= 100 && NbVarEntieresRestantes <= 10 ) ) { + OK = OUI_PNE; + /* + printf("On accepte l'heuristique NbVarRestantes %d seuil %d NbVarEntieresRestantes %d seuil %d\n", + NbVarRestantes,(int) ( 0.5 * Pne->NombreDeVariablesNonFixes ), + NbVarEntieresRestantes,(int) ( 0.1 * Pne->NombreDeVariablesEntieresNonFixes ) ); + */ +} +if ( OK == NON_PNE ) { + /* + printf("NbNTermesNonNulsRestants %d NbVarRestantes %d NbVarEntieresRestantes %d\n",NbNTermesNonNulsRestants,NbVarRestantes,NbVarEntieresRestantes); + printf("Refus lancement heuristique\n"); + */ +} + +return( OK ); +} diff --git a/src/ext/Sirius_Solver/pne/pne_heuristique_variables_entieres_fixees.c b/src/ext/Sirius_Solver/pne/pne_heuristique_variables_entieres_fixees.c new file mode 100644 index 0000000000..3789df590f --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_heuristique_variables_entieres_fixees.c @@ -0,0 +1,155 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Heuristique, on fixe des variables fractionnaires qui ont pris + une valeur entiere dans le probleme courant et + on resout le probleme par un branch and bound de probleme + reduit dans l'espoir de trouver une solution + entiere. + Attention, lorsque ce module est appele les variables + UminTrav UmaxTrav et TypeDeBorneTrav on ete remises a leur + valeur du noeud racine. Donc leurs valeurs n'inclut pas + les instanciations faites en amont du noeud a partir duquel + on demarre. + Par contre les structures du simplexe se trouvent dans l'etat + du dernier noeud resolu (bornes et types de bornes). + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 1 + +/*----------------------------------------------------------------------------*/ + +char PNE_HeuristiqueVariablesEntieresFixees( PROBLEME_PNE * Pne ) +{ +int i; BB * Bb; double * UTravSv; int NbFix; char OK; MATRICE_DE_CONTRAINTES * Contraintes; +char ProblemeTropGros; + +ProblemeTropGros = NON_PNE; + +Bb = (BB *) Pne->ProblemeBbDuSolveur; +Contraintes = NULL; + +UTravSv = Pne->ValeurLocale; +memcpy( (char *) UTravSv, (char *) Pne->UTrav, Pne->NombreDeVariablesTrav * sizeof( double ) ); + +memcpy( (char *) Pne->TypeDeBorneTrav , (char *) Pne->TypeDeBorneTravSv, Pne->NombreDeVariablesTrav * sizeof( int ) ); + +NbFix = 0; + +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + + if ( Pne->TypeDeVariableTrav[i] != ENTIER ) continue; + if ( Pne->LaVariableAUneValeurFractionnaire[i] == OUI_PNE ) continue; + if ( fabs( Pne->CoutsReduits[i] ) < 1.e-8 ) continue; /* Cas hors base degeneree */ + /* La variable a pris une valeur entiere */ + + /* Probleme: UmaxTrav et UminTrav ne sont pas ceux du noeud resolu mais ceux du noeud racine */ + if ( fabs( Pne->UmaxTrav[i] - Pne->UTrav[i] ) < 10 * Pne->SeuilDeFractionnalite[i] ) { + Pne->TypeDeBorneTrav[i] = VARIABLE_FIXE; + NbFix++; + Pne->UTrav[i] = Pne->UmaxTrav[i]; + Pne->UminTrav[i] = Pne->UmaxTrav[i]; + } + else if ( fabs( Pne->UTrav[i] - Pne->UminTrav[i] ) < 10 * Pne->SeuilDeFractionnalite[i] ) { + Pne->TypeDeBorneTrav[i] = VARIABLE_FIXE; + NbFix++; + Pne->UTrav[i] = Pne->UminTrav[i]; + Pne->UmaxTrav[i] = Pne->UminTrav[i]; + } + +} + +OK = PNE_HeuristiqueEvaluerTailleDuProbleme( Pne ); +if ( OK == NON_PNE ) ProblemeTropGros = OUI_PNE; + +if ( OK == OUI_PNE ) { + + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Starting heuristic with %d binaries fixed over %d\n",NbFix,Pne->NombreDeVariablesEntieresNonFixes); + } + + /* Construction de ma matrice des contraintes */ + Contraintes = PNE_HeuristiqueConstruireMatriceDeContraintes( Pne ); + if ( Contraintes == NULL ) goto Termine; + + /* Resolution du branch and bound reduit */ + OK = PNE_HeuristiqueResolutionBranchAndBoundReduit( Pne, Contraintes ); +} + +if ( OK == NON_PNE ) { + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Heuristic failed ...\n"); + } + Pne->NombreDEchecsSuccessifsHeuristiqueFixation++; + if ( Pne->NombreDEchecsSuccessifsHeuristiqueFixation >= NB_MAX_ECHECS_SUCCESSIFS_HEURISTIQUE ) { + Pne->NombreDeRefusSuccessifsHeuristiqueFixation = 0; + Pne->FaireHeuristiqueFixation = NON_PNE; + if ( Pne->NombreDeSolutionsHeuristiqueFixation <= 0 ) Pne->NombreDeReactivationsSansSuccesHeuristiqueFixation++; + if ( Pne->NombreDeReactivationsSansSuccesHeuristiqueFixation > NB_MAX_REACTIVATION_SANS_SUCCES ) { + Pne->StopHeuristiqueFixation = OUI_PNE; + /*printf("****************** arret definitif HeuristiqueFixation \n");*/ + } + /*printf(" !!!!!!!!!!!! On positionne a FaireHeuristiqueFixation NON_PNE \n");*/ + } + goto Termine; +} +else { + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Heuristic found ...\n"); + } +} + +/* On a trouve une solution et elle a ete controlee et archivee */ + +Pne->NombreDEchecsSuccessifsHeuristiqueFixation = 0; +Pne->NombreDeSolutionsHeuristiqueFixation++; +Pne->NombreDeReactivationsSansSuccesHeuristiqueFixation = 0; + +Termine: + +Pne->CestTermine = NON_PNE; + +memcpy( (char *) Pne->UTrav, (char *) UTravSv, Pne->NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char *) Pne->TypeDeBorneTrav, (char *) Pne->TypeDeBorneTravSv, Pne->NombreDeVariablesTrav * sizeof( int ) ); +memcpy( (char *) Pne->UmaxTrav, (char *) Pne->UmaxTravSv, Pne->NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char *) Pne->UminTrav, (char *) Pne->UminTravSv, Pne->NombreDeVariablesTrav * sizeof( double ) ); + +PNE_HeuristiqueLibererMatriceDeContraintes( Contraintes ); + +return( ProblemeTropGros ); + +} + diff --git a/src/ext/Sirius_Solver/pne/pne_init_pne.c b/src/ext/Sirius_Solver/pne/pne_init_pne.c new file mode 100644 index 0000000000..ac841e9859 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_init_pne.c @@ -0,0 +1,669 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "prs_fonctions.h" + +# define TOLERANCE_SUR_LES_VIOLATIONS_DE_CONTRAINTES 1.e-5 + +/*----------------------------------------------------------------------------*/ + +void PNE_InitialiserLaPne( PROBLEME_PNE * Pne, PROBLEME_A_RESOUDRE * Probleme ) +{ +int NombreDeVariablesE; int * TypeDeVariableE; int * TypeDeBorneTravE; +double * UE; double * UmaxE; double * UminE; double * LE; int NombreDeContraintesE; +double * BE; char * SensE; int * MdebE; int * NbtermE; double * AE; int * NuvarE; +double * VariablesDualesDesContraintesE; +int i ; int j ; int ilTrav ; int ilTravSv; int NouvelleContrainte; +int ilE ; int ilEmax ; int VarE ; double S ; double APrime ; +int iPrec; int Cnt ; int il ; int ilMax ; int NbContraintesIneg ; +int Var ; char Gub ; char OnInverse; char YaQueDesVarFixes; +double Amax; int ic; double * SeuilDeFractionnalite; int * TypeDeVariableTrav; +int * TypeDeBorneTrav; int * CdebTrav; int * CsuiTrav; double * ATrav; + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Attention nouvelle version de INIT pne qui conserve les variables fixes d'entree\n"); +} + +NombreDeVariablesE = Probleme->NombreDeVariables; +TypeDeVariableE = Probleme->TypeDeVariable; +TypeDeBorneTravE = Probleme->TypeDeBorneDeLaVariable; +UE = Probleme->X; +UmaxE = Probleme->Xmax; +UminE = Probleme->Xmin; +LE = Probleme->CoutLineaire; +NombreDeContraintesE = Probleme->NombreDeContraintes; +BE = Probleme->SecondMembre; +SensE = Probleme->Sens; +MdebE = Probleme->IndicesDebutDeLigne; +NbtermE = Probleme->NombreDeTermesDesLignes; +AE = Probleme->CoefficientsDeLaMatriceDesContraintes; +NuvarE= Probleme->IndicesColonnes; +VariablesDualesDesContraintesE = Probleme->VariablesDualesDesContraintes; + +Pne->DernierTauxParCoupe = -1.; + +Pne->YaDesVariablesEntieres = NON_PNE; +Pne->NumeroDeLaContrainteDeCoutMax = -1; +Pne->NumeroDeLaVariableDEcartPourCoutMax = -1; + +Pne->PrioriteDansSpxAuxVariablesSortantesEntieres = NON_PNE; + +Pne->ChainageTransposeeExploitable = NON_PNE; + +Pne->NombreDeGub = 0; + +Pne->Z0 = 0.0; /* Cout fixe lie aux transformation: translations de borne, presolve etc.. */ + +NbContraintesIneg = 0; + + +/* On met une valeur invalide afin de pouvoir verifier a la fin si toutes les valeurs ont ete initialisees */ +S = 2 * VALEUR_NON_INITIALISEE; +if ( VariablesDualesDesContraintesE != NULL ) { + for ( i = 0 ; i < NombreDeContraintesE ; i++ ) VariablesDualesDesContraintesE[i] = S; +} + +/* On conserve les variables fixes dans le probleme pne */ +for ( j = 0 , i = 0 ; i < NombreDeVariablesE ; i++ ) { + Pne->CorrespondanceVarEntreeVarNouvelle[i] = -1; + + Pne->TypeDeVariableTrav[j] = TypeDeVariableE[i]; + if ( Pne->TypeDeVariableTrav[j] == ENTIER ) { + if ( Pne->SolveurPourLeProblemeRelaxe == SIMPLEXE || MPCC_DANS_PI == OUI_PNE ) Pne->YaDesVariablesEntieres = OUI_PNE; + else Pne->TypeDeVariableTrav[j] = REEL; + if ( TypeDeBorneTravE[i] != VARIABLE_BORNEE_DES_DEUX_COTES && TypeDeBorneTravE[i] != VARIABLE_FIXE ) { + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Erreur dans les donnees, la variable %d est entiere mais elle n'est pas bornee des 2 cotes\n",i); + printf("Arret du solveur car seules les variables entieres de type binaire sont acceptees\n"); + } + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); + } + if ( UmaxE[i] - UminE[i] != 1.0 && TypeDeBorneTravE[i] != VARIABLE_FIXE ) { + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Erreur dans les donnees, la variable %d est entiere mais elle n'est pas de type binaire\n",i); + printf("Min %e Max %e Ecart %20.17f\n",UminE[i],UmaxE[i],UmaxE[i]-UminE[i]); + printf("Arret du solveur car seules les variables entieres de type binaire sont acceptees\n"); + } + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); + } + } + Pne->TypeDeBorneTrav [j] = TypeDeBorneTravE[i]; + Pne->VariableAInverser [j] = NON_PNE; + Pne->UTrav [j] = UE[i]; /* Pour disposer de la valeur des variables qui sont fixes en entree */ + Pne->UmaxTrav[j] = UmaxE[i]; + Pne->UminTrav[j] = UminE[i]; + if ( TypeDeBorneTravE[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Pne->UmaxTrav[j] = LINFINI_PNE; + } + else if ( TypeDeBorneTravE[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Pne->UminTrav[j] = -LINFINI_PNE; + } + else if ( TypeDeBorneTravE[i] == VARIABLE_NON_BORNEE ) { + Pne->UmaxTrav[j] = LINFINI_PNE; + Pne->UminTrav[j] = -LINFINI_PNE; + } + Pne->LTrav[j] = LE[i]; + Pne->CorrespondanceVarEntreeVarNouvelle[i] = j; + j++; + if ( j >= Pne->NombreDeVariablesAllouees ) PNE_AugmenterLeNombreDeVariables( Pne ); + +} + +Pne->NombreDeVariablesElimineesSansValeur = 0; + +Pne->NombreDeVariablesTrav = j; + +/* Cas particulier ou toutes les variables sont fixes: on verifie que la solution est bonne */ +/* Alexandre Ortiz m'a sorti un cas ou toutes les variables etaient fixes */ +if ( Pne->NombreDeVariablesTrav == 0 ) { + for ( i = 0 ; i < NombreDeContraintesE ; i++ ) { + S = 0.0; + ilE = MdebE[i]; + ilEmax = MdebE[i] + NbtermE[i] - 1; + /* Correction du 15/3/13: si la contrainte est desactivee en entree, il n'y a pas lieu de faire un test */ + if ( ilE < 0 || NbtermE[i] <= 0 ) { + if ( VariablesDualesDesContraintesE != NULL ) VariablesDualesDesContraintesE[i] = 0.0; + continue; /* Car en realite la contrainte n'existe pas */ + } + while ( ilE <= ilEmax ) { + S += AE[ilE] * UE[NuvarE[ilE]]; + ilE++; + } + if ( SensE[i] == '=' ) { + if ( fabs( S - BE[i] ) > TOLERANCE_SUR_LES_VIOLATIONS_DE_CONTRAINTES ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + break; + } + } + else if ( SensE[i] == '<' ) { + if ( S > BE[i] + TOLERANCE_SUR_LES_VIOLATIONS_DE_CONTRAINTES ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + break; + } + } + else if ( SensE[i] == '>' ) { + if ( S < BE[i] - TOLERANCE_SUR_LES_VIOLATIONS_DE_CONTRAINTES ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + break; + } + } + } +} + +/* Transfert dans les tableaux de travail: les contraintes de type > + sont transformees en contraintes de type < et les variables fixées sont + eliminees du probleme */ + +Pne->NombreDeContraintesTrav = 0; +for ( ilTrav = -1 , i = 0 ; i < NombreDeContraintesE ; i++ ) { + /* Correction du 15/3/13: si la contrainte est desactivee en entree, il n'y a pas lieu de continuer dans la boucle */ + if ( MdebE[i] < 0 || NbtermE[i] <= 0 ) { + /* Car en realite la contrainte n'existe pas */ + if ( VariablesDualesDesContraintesE != NULL ) VariablesDualesDesContraintesE[i] = 0.0; + continue; + } + NouvelleContrainte = NON_PNE; + Pne->NombreDeContraintesTrav++; + if ( Pne->NombreDeContraintesTrav >= Pne->NombreDeContraintesAllouees ) PNE_AugmenterLeNombreDeContraintes( Pne ); + + ilTravSv = ilTrav; + + ilE = MdebE[i]; + ilEmax = MdebE[i] + NbtermE[i] - 1; + + if ( ( ilTrav + 1 ) >= Pne->TailleAlloueePourLaMatriceDesContraintes ) PNE_AugmenterLaTailleDeLaMatriceDesContraintes( Pne ); + + Pne->MdebTrav [Pne->NombreDeContraintesTrav - 1] = ilTrav + 1; + Pne->NbTermTrav[Pne->NombreDeContraintesTrav - 1] = 0; + + S = 0.; iPrec = -1; + + while ( ilE <= ilEmax ) { + VarE = NuvarE[ilE]; + if ( iPrec == VarE ) { + if ( Pne->AffichageDesTraces == OUI_PNE ) printf("Erreur, la contrainte %i contient 2 fois la variable %d\n",i,iPrec); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } + + if ( TypeDeBorneTravE[VarE] != VARIABLE_FIXE ) NouvelleContrainte = OUI_PNE; + else { + APrime = AE[ilE]; + if ( SensE[i] == '>' ) APrime = -AE[ilE]; + /* printf("Variable fixee dans TRANSFERT PROB \n");*/ + S += APrime * UE[VarE]; + } + Pne->NbTermTrav[Pne->NombreDeContraintesTrav - 1]++; + ilTrav++; + if ( ilTrav >= Pne->TailleAlloueePourLaMatriceDesContraintes ) PNE_AugmenterLaTailleDeLaMatriceDesContraintes( Pne ); + Pne->ATrav[ilTrav] = AE[ilE]; + if ( SensE[i] == '>' ) Pne->ATrav[ilTrav] = -AE[ilE]; + + j = Pne->CorrespondanceVarEntreeVarNouvelle[VarE]; + if ( j >= 0 ) Pne->NuvarTrav[ilTrav] = j; + else if ( Pne->AffichageDesTraces == OUI_PNE ) printf("BUG dans PNE_InitialiserLaPne, vecteur CorrespondanceVarEntreeVarNouvelle mal initialise\n"); + + iPrec = NuvarE[ilE]; + ilE++; + } + + if ( NouvelleContrainte == NON_PNE ) { + if ( VariablesDualesDesContraintesE != NULL ) VariablesDualesDesContraintesE[i] = 0.0; + Pne->NombreDeContraintesTrav--; + ilTrav = ilTravSv; + /* On controle la satisfaction de la contrainte */ + if ( SensE[i] == '=' ) { + if ( fabs( S - BE[i] ) > SEUIL_DADMISSIBILITE ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + } + } + else if ( SensE[i] == '<' ) { + if ( S > BE[i] + SEUIL_DADMISSIBILITE ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + } + } + else { + /* Contrainte de type > */ + /* Copier coller de la ligne ci-dessus malencontreux !!!!!!!!!!!!!!!!*/ + /* Comme on a change le signe des coefficients pour anticiper le changement de sens de l'inegalite, + on doit faire pareil pour le second membre */ + /*if ( S > BE[i] + SEUIL_DADMISSIBILITE ) {*/ + if ( S > -BE[i] + SEUIL_DADMISSIBILITE ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + } + } + } + else { + Pne->CorrespondanceCntPneCntEntree[Pne->NombreDeContraintesTrav - 1] = i; + Pne->BTrav [Pne->NombreDeContraintesTrav - 1] = BE[i]; + Pne->SensContrainteTrav[Pne->NombreDeContraintesTrav - 1] = SensE[i]; + if ( SensE[i] == '>' ) { + Pne->BTrav [Pne->NombreDeContraintesTrav - 1] = -BE[i]; + Pne->SensContrainteTrav[Pne->NombreDeContraintesTrav - 1] = '<'; + } + if ( Pne->SensContrainteTrav[Pne->NombreDeContraintesTrav - 1] != '=' ) NbContraintesIneg++; + /* On ajoute toujours de la marge utilisable pour le presolve */ + ilTrav += MARGE_EN_FIN_DE_CONTRAINTE; + if ( ilTrav >= Pne->TailleAlloueePourLaMatriceDesContraintes ) PNE_AugmenterLaTailleDeLaMatriceDesContraintes( Pne ); + } +} + +Pne->NombreDeContraintesDInegalite = NbContraintesIneg; +Pne->PremierIndexLibre = ilTrav + 1; + +# if PNE_ACTIVATION_SUPPRESSION_PETITS_TERMES == OUI_PNE + PNE_EnleverLesToutPetitsTermes( Pne->MdebTrav, Pne->NbTermTrav, Pne->NuvarTrav, Pne->ATrav, + Pne->UmaxTrav, Pne->UminTrav, Pne->NombreDeContraintesTrav, + Pne->AffichageDesTraces ); +# endif + +/* Presolve */ + +if ( Pne->FaireDuPresolve == OUI_PNE ) PNE_AllocationsPourLePostSolve( Pne ); + +PRS_Presolve( Pne ); + +if ( Pne->Controls != NULL ) { + if ( Pne->Controls->PresolveUniquement == OUI_PNE ) { + PNE_CleanPostSolve( Pne ); + return; + } +} + +/* Test: on essaie de transformer des variables entieres en variables continues */ +/*PNE_ChangerLesTypesDeVariables( Pne );*/ +/* Fin test */ + +PNE_CompacterLaMatriceDesContraintes( Pne ); + +# if UTILISER_LE_GRAPHE_DE_CONFLITS == OUI_PNE + # if PROBING_JUSTE_APRES_LE_PRESOLVE == OUI_PNE + if ( Pne->YaDesVariablesEntieres == OUI_PNE ) { + PNE_VariableProbing( Pne ); + if ( Pne->CoupesDeProbing != NULL ) { + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("%d probing cut(s) found\n",Pne->CoupesDeProbing->NombreDeCoupesDeProbing); + } + } + if ( Pne->ProbingOuNodePresolve != NULL ) { + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) Pne->YaUneSolution = NON_PNE; + else PNE_CliquesConflictGraph( Pne ); + } + /* Le variable probing peut conduire aussi a des possibilites d'amelioration de coeffs + de variables binaires */ + PNE_AmeliorerLesCoefficientsDesVariablesBinaires( Pne, NULL, MODE_PNE ); + + /* Pour tenir compte des coupes de probing */ + PNE_ProbingModifierLaMatriceDesContraintes( Pne, Pne->ProbingOuNodePresolve ); + /* Il se peut que des contraintes soient devenues inactives ou fixing */ + PNE_PostProbing( Pne ); + /* Nouveau compactage au cas ou des variables entieres auraient ete fixees */ + PNE_CompacterLaMatriceDesContraintes( Pne ); + } + # endif +# endif + +/* +PNE_EcrirePresolvedMPS( Pne ); +exit(0); +*/ + +if ( Pne->FaireDuPresolve == OUI_PNE ) PNE_CleanPostSolve( Pne ); + +PNE_TranslaterLesBornes( Pne ); + +/* Cas ou le solveur est appele par lui-meme */ +if ( Pne->Controls != NULL && Pne->YaUneSolution == OUI_PNE && 0 ) { + { int NbFix; int NbVarEnt; PROBLEME_PNE * PnePere; int NbNonFix; double Seuil; + NbFix = 0; + NbVarEnt = 0; + for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_FIXE ) NbFix++; + else if ( Pne->UmaxTrav[Var] == Pne->UminTrav[Var] ) NbFix++; + else if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) NbVarEnt++; + } + PnePere = (PROBLEME_PNE * ) (Pne->Controls->Pne); + NbNonFix = Pne->NombreDeVariablesTrav-NbFix; + if ( Pne->AffichageDesTraces == OUI_PNE ) + { + printf("Init PNE NombreDeContraintesTrav %d NombreDeVariablesTrav %d No non Fix %d \n",Pne->NombreDeContraintesTrav, + Pne->NombreDeVariablesTrav, NbNonFix); + + printf("Init PNE nombre de variables entieres non fixes %d et dans le pere %d \n", + NbVarEnt, PnePere->NombreDeVariablesEntieresNonFixes); + printf("Init PNE nombre de variables non fixes %d et dans le pere %d \n", + NbNonFix, PnePere->NombreDeVariablesNonFixes); + } + + Seuil = 0.1; + if ( PnePere->YaUneSolutionEntiere == NON_PNE ) Seuil = 0.5; + if ( NbVarEnt > (int) (Seuil * PnePere->NombreDeVariablesEntieresNonFixes) && NbVarEnt > 50 ) { + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Refus car trop de var ent NbVarEnt %d Seuil * PnePere->NombreDeVariablesEntieresNonFixes %d\n", + NbVarEnt,(int) (Seuil * PnePere->NombreDeVariablesEntieresNonFixes) ); + printf("NombreDeVariablesEntieresNonFixes %d\n", PnePere->NombreDeVariablesEntieresNonFixes); + } + Pne->YaUneSolution = NON_PNE; + } + if ( NbNonFix > (int) (Seuil * PnePere->NombreDeVariablesNonFixes) && NbNonFix > 50 ) { + if ( Pne->AffichageDesTraces == OUI_PNE ) printf("Refus car trop de var\n"); + Pne->YaUneSolution = NON_PNE; + } + } +} + +if ( Pne->YaDesVariablesEntieres == OUI_PNE ) { + + /* + printf("PNE_DetectionContraintesEntieresInfaisable\n"); + PNE_DetectionContraintesEntieresInfaisable( Pne ); + */ + + /* Recherche de GUB */ + PNE_DetecterLesGub( Pne ); + + Pne->CalculDeMIRmarchandWolsey = OUI_PNE; + Pne->NbEvitementsDeCalculsMIRmarchandWolsey = 0; + Pne->NbEchecsConsecutifsDeCalculsMIRmarchandWolsey = 0; + Pne->ProfondeurMirMarchandWolseTrouvees = 0; + + /* Detection des bornes variables */ + PNE_AnalyseInitialeDesBornesVariables( Pne ); + + /* Detection des contraintes sur lesquelles on pourrait faire des Knapsack */ + PNE_AnalyseInitialeDesKnapsack( Pne ); + + /* Detection des contraintes mixtes. Imperativement apres detection des bornes variables */ + PNE_DetecterLesContraintesMixtes( Pne ); + +} + +Pne->YaDesBigM = NON_PNE; +/* Detection de variables binaires avec un Big M */ +PNE_DetecterLesVariablesBigM( Pne ); + +/* Test recherche de epsilon des variables entieres */ +SeuilDeFractionnalite = Pne->SeuilDeFractionnalite; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; + +if ( Pne->ChainageTransposeeExploitable == NON_PNE ) PNE_ConstruireLeChainageDeLaTransposee( Pne ); + +CdebTrav = Pne->CdebTrav; +CsuiTrav = Pne->CsuiTrav; +ATrav = Pne->ATrav; + for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( TypeDeVariableTrav[Var] != ENTIER ) continue; + if ( TypeDeBorneTrav[Var] == VARIABLE_FIXE ) continue; + Amax = -1; + ic = CdebTrav[Var]; + while ( ic >= 0 ) { + if ( fabs( ATrav[ic] ) > Amax ) Amax = fabs( ATrav[ic] ); + ic = CsuiTrav[ic]; + } + SeuilDeFractionnalite[Var] = VALEUR_DE_FRACTIONNALITE_NULLE; + if ( Amax > 0 ) { + SeuilDeFractionnalite[Var] = SEUIL_DADMISSIBILITE / Amax; + if ( SeuilDeFractionnalite[Var] < 0.1 * VALEUR_DE_FRACTIONNALITE_NULLE ) { + SeuilDeFractionnalite[Var] = 0.1 * VALEUR_DE_FRACTIONNALITE_NULLE; + } + } +} + +Pne->Coupes.NombreDeContraintesAllouees = 0; +Pne->Coupes.TailleAlloueePourLaMatriceDesContraintes = 0; +Pne->Coupes.NombreDeContraintes = 0; + +Pne->DureeDuPremierSimplexe = -1.; + +/* Sauvegarde des bornes sup apres translation et scaling */ +memcpy( (char * ) Pne->UmaxTravSv, (char * ) Pne->UmaxTrav, Pne->NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char * ) Pne->UminTravSv, (char * ) Pne->UminTrav, Pne->NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char * ) Pne->TypeDeBorneTravSv, (char * ) Pne->TypeDeBorneTrav, Pne->NombreDeVariablesTrav * sizeof( int ) ); + +Pne->FaireHeuristiqueRINS = OUI_PNE; +Pne->StopHeuristiqueRINS = NON_PNE; +Pne->NombreDeSolutionsHeuristiqueRINS = 0; +Pne->NombreDEchecsSuccessifsHeuristiqueRINS = 0; +Pne->NombreDeRefusSuccessifsHeuristiqueRINS = 0; +Pne->NombreDeReactivationsSansSuccesHeuristiqueRINS = 0; + +Pne->FaireHeuristiqueFixation = OUI_PNE; +Pne->StopHeuristiqueFixation = NON_PNE; +Pne->NombreDeSolutionsHeuristiqueFixation = 0; +Pne->NombreDEchecsSuccessifsHeuristiqueFixation = 0; +Pne->NombreDeRefusSuccessifsHeuristiqueFixation = 0; +Pne->NombreDeReactivationsSansSuccesHeuristiqueFixation = 0; + +Pne->FaireHeuristiqueFractionalDive = OUI_PNE; +Pne->StopHeuristiqueFractionalDive = NON_PNE; +Pne->NombreDeSolutionsHeuristiqueFractionalDive = 0; +Pne->NombreDEchecsSuccessifsHeuristiqueFractionalDive = 0; +Pne->NombreDeRefusSuccessifsHeuristiqueFractionalDive = 0; +Pne->NombreDeReactivationsSansSuccesHeuristiqueFractionalDive = 0; + +/* Par precaution */ +if ( Pne->ChainageTransposeeExploitable == NON_PNE ) PNE_ConstruireLeChainageDeLaTransposee( Pne ); + +/* Si presence de variables entieres: + Contraintes de borne inf + ContrainteActivable */ +if ( Pne->YaDesVariablesEntieres == OUI_PNE ) { + Pne->ContrainteActivable = (char *) malloc( Pne->NombreDeContraintesTrav * sizeof( char ) ); + if ( Pne->ContrainteActivable == NULL ) { + if ( Pne->AffichageDesTraces == OUI_PNE ) printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_InitPne \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } + for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) Pne->ContrainteActivable[Cnt] = OUI_PNE; + + Pne->NombreDeK = 0; + Pne->SommeViolationsK = 0; + Pne->SeuilDeViolationK = SEUIL_VIOLATION_KNAPSACK; + + Pne->NombreDeMIR_MARCHAND_WOLSEY = 0; + Pne->SommeViolationsMIR_MARCHAND_WOLSEY = 0; + Pne-> SeuilDeViolationMIR_MARCHAND_WOLSEY = SEUIL_VIOLATION_MIR_MARCHAND_WOLSEY; + + Pne->NombreDeCliques = 0; + Pne->SommeViolationsCliques = 0; + Pne->SeuilDeViolationCliques = SEUIL_VIOLATION_CLIQUES; + + Pne->NombreDImplications = 0; + Pne->SommeViolationsImplications = 0; + Pne->SeuilDeViolationImplications = SEUIL_VIOLATION_IMPLICATIONS; + + Pne->NombreDeBornesVariables = 0; + Pne->SommeViolationsBornesVariables = 0; + Pne->SeuilDeViolationBornesVariables = SEUIL_VIOLATION_BORNES_VARIABLES; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_TranslaterLesBornes( PROBLEME_PNE * Pne ) +{ +int Var; int Cnt; int il ; int ilMax; double S; int * TypeDeBorne; int NombreDeVariables; +double * CoutLineaire; double * Xmin; double * Xmax; char * VariableAInverser; +int NombreDeContraintes; int * Mdeb; int * NbTerm; int * Nuvar; double * A; +double * XminEntre; double * XmaxEntre; double * B; + +# if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE +CONTRAITES_DE_BORNE_VARIABLE * ContraintesDeBorneVariable; int NombreDeContraintesDeBorne; +int * First; int * Colonne; double * SecondMembre; double * Coefficient; +# endif + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +CoutLineaire = Pne->LTrav; +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; +XminEntre = Pne->UminEntree; +XmaxEntre = Pne->UmaxEntree; + +VariableAInverser = Pne->VariableAInverser; + +/* Transformation interne: les variables de type BORNEE_SUPERIEUREMENT sont transformees + en BORNEE_INFERIEUREMENT par un simple changement de variable */ +/* Attention, on ne prevoit pas encore le cas de variables entieres negatives */ +/* 1- Partie cout et bornes */ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBorne[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + CoutLineaire[Var] = -CoutLineaire[Var]; + Xmin[Var] = -Xmax[Var]; + Xmax[Var] = LINFINI_PNE; + VariableAInverser[Var] = OUI_PNE; + } +} + +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +B = Pne->BTrav; + +/* 2- Partie matrice des contraintes */ +/* 2-a- Contraintes natives */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( TypeDeBorne[Nuvar[il]] == VARIABLE_BORNEE_SUPERIEUREMENT ) A[il] = -A[il]; + il++; + } +} +/* 2-b Variables bound constraintes ajoutees dans le variable probing */ +# if UTILISER_LE_GRAPHE_DE_CONFLITS == OUI_PNE && PROBING_JUSTE_APRES_LE_PRESOLVE == OUI_PNE && CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + ContraintesDeBorneVariable = Pne->ContraintesDeBorneVariable; + if ( ContraintesDeBorneVariable != NULL ) { + NombreDeContraintesDeBorne = ContraintesDeBorneVariable->NombreDeContraintesDeBorne; + First = ContraintesDeBorneVariable->First; + SecondMembre = ContraintesDeBorneVariable->SecondMembre; + Colonne = ContraintesDeBorneVariable->Colonne; + Coefficient = ContraintesDeBorneVariable->Coefficient; + for ( Cnt = 0 ; Cnt < NombreDeContraintesDeBorne ; Cnt++ ) { + if ( First[Cnt] < 0 ) continue; + il = First[Cnt]; + ilMax = il + 2; + while ( il < ilMax ) { + if ( TypeDeBorne[Colonne[il]] == VARIABLE_BORNEE_SUPERIEUREMENT ) Coefficient[il] = -Coefficient[il]; + il++; + } + } + } +# endif + +/* 3- Changement de variable */ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBorne[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) TypeDeBorne[Var] = VARIABLE_BORNEE_INFERIEUREMENT; +} +/* Fin de la transformation interne BORNEE_SUPERIEUREMENT -> BORNEE_INFERIEUREMENT */ + +memcpy( (char *) XmaxEntre , (char *) Xmax , NombreDeVariables * sizeof( double ) ); +memcpy( (char *) XminEntre , (char *) Xmin , NombreDeVariables * sizeof( double ) ); + +/* A ce stade il n'y a plus de variable de type VARIABLE_BORNEE_SUPERIEUREMENT */ + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBorne[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorne[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Xmax[Var] = XmaxEntre[Var] - XminEntre[Var]; + Pne->Z0 += CoutLineaire[Var] * XminEntre[Var]; + Xmin[Var] = 0.; + } +} + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++) { + S = 0.; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Nuvar[il]; + if ( TypeDeBorne[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorne[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) S += A[il] * XminEntre[Var]; + il++; + } + B[Cnt] -= S; +} + +/* Variables bound constraintes ajoutees dans le variable probing */ +# if UTILISER_LE_GRAPHE_DE_CONFLITS == OUI_PNE && PROBING_JUSTE_APRES_LE_PRESOLVE == OUI_PNE && CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + ContraintesDeBorneVariable = Pne->ContraintesDeBorneVariable; + if ( ContraintesDeBorneVariable != NULL ) { + NombreDeContraintesDeBorne = ContraintesDeBorneVariable->NombreDeContraintesDeBorne; + First = ContraintesDeBorneVariable->First; + SecondMembre = ContraintesDeBorneVariable->SecondMembre; + Colonne = ContraintesDeBorneVariable->Colonne; + Coefficient = ContraintesDeBorneVariable->Coefficient; + for ( Cnt = 0 ; Cnt < NombreDeContraintesDeBorne ; Cnt++ ) { + if ( First[Cnt] < 0 ) continue; + S = 0.; + il = First[Cnt]; + ilMax = il + 2; + while ( il < ilMax ) { + Var = Colonne[il]; + if ( TypeDeBorne[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorne[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) S += Coefficient[il] * XminEntre[Var]; + il++; + } + SecondMembre[Cnt] -= S; + } + } +# endif + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Fixed cost is %e\n",Pne->Z0); + fflush( stdout ); +} + +return; +} + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_inserer_une_contrainte.c b/src/ext/Sirius_Solver/pne/pne_inserer_une_contrainte.c new file mode 100644 index 0000000000..3c3e3fe07e --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_inserer_une_contrainte.c @@ -0,0 +1,97 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On insere une contrainte dans l'ensemble des coupes d'un + probleme relaxe. Les contraintes sont toujours de type <=. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void PNE_InsererUneContrainte( PROBLEME_PNE * Pne, + int NombreDeTermes, + double * Coefficient, + int * IndiceDeLaVariable, + double SecondMembre, + char ContrainteSaturee, + char TypeDeCoupe ) +{ +int i; int il; int DerniereContrainte; int * Mdeb; int * NbTerm; +double * A; int * Nuvar; + +if ( Pne->Coupes.NombreDeContraintesAllouees <= 0 ) PNE_AllocCoupes( Pne ); + +DerniereContrainte = Pne->Coupes.NombreDeContraintes - 1; + +Mdeb = Pne->Coupes.Mdeb; +NbTerm = Pne->Coupes.NbTerm; +Nuvar = Pne->Coupes.Nuvar; +A = Pne->Coupes.A; + +il = 0; +if ( DerniereContrainte >= 0 ) { + il = Mdeb[DerniereContrainte] + NbTerm[DerniereContrainte]; + + if ( il >= Pne->Coupes.TailleAlloueePourLaMatriceDesContraintes ) { + PNE_AugmenterLaTailleDeLaMatriceDesCoupes( Pne ); + Nuvar = Pne->Coupes.Nuvar; + A = Pne->Coupes.A; + } + +} + +Mdeb [Pne->Coupes.NombreDeContraintes] = il; +NbTerm[Pne->Coupes.NombreDeContraintes] = NombreDeTermes; + +/* La Contrainte */ +for ( i = 0 ; i < NombreDeTermes ; i++ ) { + A [il] = Coefficient[i]; + Nuvar[il] = IndiceDeLaVariable[i]; + il++; + if ( il >= Pne->Coupes.TailleAlloueePourLaMatriceDesContraintes ) { + PNE_AugmenterLaTailleDeLaMatriceDesCoupes( Pne ); + Nuvar = Pne->Coupes.Nuvar; + A = Pne->Coupes.A; + } +} + +/* Second membre */ +Pne->Coupes.B[Pne->Coupes.NombreDeContraintes] = SecondMembre; +Pne->Coupes.TypeDeCoupe[Pne->Coupes.NombreDeContraintes] = TypeDeCoupe; + +/* Etat de saturation */ +if ( ContrainteSaturee == OUI_PNE ) Pne->Coupes.PositionDeLaVariableDEcart[Pne->Coupes.NombreDeContraintes] = HORS_BASE_SUR_BORNE_INF; +else Pne->Coupes.PositionDeLaVariableDEcart[Pne->Coupes.NombreDeContraintes] = EN_BASE; + +Pne->Coupes.NombreDeContraintes++; +if ( Pne->Coupes.NombreDeContraintes >= Pne->Coupes.NombreDeContraintesAllouees ) PNE_AugmenterLeNombreDeCoupes( Pne ); + +return; +} + + + diff --git a/src/ext/Sirius_Solver/pne/pne_knapsack_lift_variable_continue.c b/src/ext/Sirius_Solver/pne/pne_knapsack_lift_variable_continue.c new file mode 100644 index 0000000000..f027fdb877 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_knapsack_lift_variable_continue.c @@ -0,0 +1,343 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Apres constitution d'une coupe de knapsack sur la restriction + aux variables entieres d'une knapsack avec variable continue, + on lifte cette variable continue. + S'applique aux mixed knapsack avec une variable continue: + a^T y < b + s + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define Zero 1.e-9 + +double PNE_ProgrammationDynamiqueMaxKnapsack( int , double * , double * , double , char * ); + +/*------------------------------------------------------------------------*/ +/* Resolution du probleme Max c^T . y s.c a^T y >= b */ +/* y binaire, a entier > 0, b entier > 0, c reel */ +/* Methode: programmation dynamique */ + +double PNE_ProgrammationDynamiqueMaxKnapsack( int NombreDeVariables, double * C, double * A, double B0double, + /* En retour */ + char * Y + ) +{ +int Var; int i; double Z; int B1; int AdeVar; double CdeVar; double * Bellman; int B0; double Opt; double Sec; +int B0max; int E1; int E2; int B; char * Commande; int EtatOpt; char * Init; + +/* Ci-dessous un probleme pour tester la programmation dynamique */ +/* +if ( NombreDeVariables >= 6 ) { + B0double = 178; + C[0] = 1.; + C[1] = 1.; + C[2] = 1./4.; + C[3] = 1./2.; + C[4] = 0; + C[5] = 1.; + + A[0] = 45; + A[1] = 46; + A[2] = 79; + A[3] = 54; + A[4] = 53; + A[5] = 125; + + NombreDeVariables = 6; +} +*/ +EtatOpt = -1; + +B0 = (int) B0double; +/* Calcul de la valeur max du second membre */ +B0max = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + B0max += (int) A[Var]; + /*printf("C[%d] = %e A = %d (%e) B0 %d B0max %d\n",Var,C[Var],(int)A[Var],A[Var],B0,B0max);*/ +} +B1 = B0max + 1; + +i = (B0max + 1) * NombreDeVariables; +i++; +Bellman = (double *) malloc( i * sizeof( double ) ); +Init = (char *) malloc( i * sizeof( char ) ); +Commande = (char *) malloc( i * sizeof( char ) ); +for ( B = 0 ; B < i ; B++ ) Init[B] = NON_PNE; +Z = -LINFINI_PNE; + +E1 = 0; +/* Variable 0 */ +Var = 0; +AdeVar = (int) A[Var]; +CdeVar = C[Var]; +/* i est l'etat de depart, j est l'etat d'arrivee */ +for ( i = 0 ; i <= B0max ; i++ ) { + + if ( Init[E1] == OUI_PNE ) { + printf("Bug l'etat %d est deja initialise \n",E1); + exit(0); + } + + /* Variable a 1 => on change de niveau */ + /* B est le niveau atteint pour le second membre */ + B = i + AdeVar; + if ( B >= B0 && B <= B0max ) { + /* On atteint une solution realisable */ + Bellman[E1] = CdeVar; + Commande[E1] = 1; + Init[E1] = OUI_PNE; + } + /* Variable a 0 => on ne change pas de niveau */ + B = i; + if ( B >= B0 ) { + if ( Init[E1] == OUI_PNE ) { + if ( 0 > Bellman[E1] ) { + Bellman[E1] = 0; + Commande[E1] = 0; + } + } + else { + Bellman[E1] = 0; + Commande[E1] = 0; + Init[E1] = OUI_PNE; + } + } + E1++; +} +Var++; + +for ( ; Var < NombreDeVariables ; Var++ ) { + AdeVar = (int) A[Var]; + CdeVar = C[Var]; + /* i est l'etat de depart, j est l'etat d'arrivee */ + for ( i = 0 ; i <= B0max ; i++ ) { + /* normalement l'etat n'est pas initialise */ + if ( Init[E1] == OUI_PNE ) { + printf("Bug Variable %d etat %d est deja initialise \n",Var,E1); + exit(0); + } + /* Variable a 1 => on change de niveau */ + B = i + AdeVar; + if ( B <= B0max ) { + E2 = E1 - B1 + AdeVar; + if ( Init[E2] == OUI_PNE ) { + Bellman[E1] = CdeVar + Bellman[E2]; + Commande[E1] = 1; + Init[E1] = OUI_PNE; + /*printf("Bellman %e B %d Var %d\n",Bellman[E1],B,Var);*/ + } + } + /* Variable a 0 => on ne change pas de niveau */ + B = i; + E2 = E1 - B1; + if ( Init[E2] == OUI_PNE ) { + if ( Init[E1] == OUI_PNE ) { + if ( Bellman[E2] > Bellman[E1] ) { + Bellman[E1] = Bellman[E2]; + Commande[E1] = 0; + } + } + else { + Bellman[E1] = Bellman[E2]; + Commande[E1] = 0; + Init[E1] = OUI_PNE; + } + } + if ( Var == NombreDeVariables - 1 ) { + if ( i == 0 ) { + if ( Init[E1] == NON_PNE ) { + printf("Bug Variable %d etat non initialise \n",E1); + exit(0); + } + Z = Bellman[E1]; + EtatOpt = E1; + break; + } + } + E1++; + } +} + +if ( Y != NULL ) { + /* On rebalaie en avant pour avoir la solution optimale */ + Opt = 0; + Sec = 0; + E1 = EtatOpt; + Var = NombreDeVariables - 1; + i = 0; + Y[Var] = Commande[E1]; + Opt += C[Var] * Y[Var]; + Sec += A[Var] * Y[Var]; + while ( Var > 0 ) { + E2 = E1 - B1 + ( (int) A[Var] * (int) Commande[E1] ); + i += (int) A[Var] * (int) Commande[E1]; + Var--; + Y[Var] = Commande[E2]; + Opt += C[Var] * Y[Var]; + Sec += A[Var] * Y[Var]; + E1 = E2; + } + + i += (int) A[0] * (int) Y[0]; + /* + printf(" Z %e niveau atteint %d\n",Z,i); + printf(" Opt %e sec %e\n",Opt,Sec); + */ + + if ( Opt != Z ) { + printf("Ereur programmation dynamique !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); + exit(0); + } +} + +free( Bellman ); +free( Init ); +free( Commande ); + +printf(" Z %e \n",Z); + +return( Z ); +} + +/*----------------------------------------------------------------------------*/ + +void PNE_KnapsackLifterLaVariableContinue( /* Un vecteur de travail */ + double * C, + /* La knapsack */ + int NbTermesKnapsack, + double * aKnapsack, + double bKnapsack, + /* La coupe sur knapsack */ + int NbTermesCoupeKnapsack, + int * varCoupeKnapsack, + double * piCoupeKnapsack, + double pi0CoupeKnapsack, + /* La valeur prise par s pour le calcul de la coupe sur knapsack */ + double sBarre, + /* En retour le coeff de la variable continue liftee */ + double * Gamma + ) +{ +double GammaLB; double X; int i; double CoutConstant; double Xi; double sOpt; +char * Y; + +printf("Valeur de sBarre %e\n",sBarre); + +Y = (char *) malloc( NbTermesKnapsack * sizeof( char ) ); + +/* Calcul du produit scalaire a^T . Pi */ +memset( (char *) C, 0 , NbTermesKnapsack * sizeof( double ) ); +for ( i = 0 ; i < NbTermesKnapsack ; i++ ) C[i] = aKnapsack[i]; +X = 0.0; +for ( i = 0 ; i < NbTermesCoupeKnapsack ; i++ ) X += C[varCoupeKnapsack[i]] * piCoupeKnapsack[i]; + +X -= bKnapsack + sBarre; +if ( fabs( X ) < Zero ) X = 1.0; +GammaLB = ( piCoupeKnapsack[0] - pi0CoupeKnapsack ) / X; +if ( GammaLB < 0.0 ) GammaLB = 1.0; + +/* Resolution du probleme knapsack */ +ResolutionKnapsack: +/* Constitution du vecteur des couts des variables entieres */ +for ( i = 0 ; i < NbTermesKnapsack ; i++ ) C[i] = -GammaLB * aKnapsack[i]; +for ( i = 0 ; i < NbTermesCoupeKnapsack ; i++ ) C[varCoupeKnapsack[i]] += piCoupeKnapsack[i]; +/* Resolution du probleme knapsack : Max du critere sous contraint aKnapsack * Y > bKnapsack */ +CoutConstant = pi0CoupeKnapsack + GammaLB * bKnapsack; + +Xi = PNE_ProgrammationDynamiqueMaxKnapsack( NbTermesKnapsack, C, aKnapsack, bKnapsack, + /* En retour */ + Y ); +Xi -= CoutConstant; + +if ( Xi >= 0.0 ) { + /* La coupe n'est pas valide pour toutes les valeurs de s avec cette valeur de GammaLB, on l'augmente */ + X = 0.0; + for ( i = 0 ; i < NbTermesCoupeKnapsack ; i++ ) X += piCoupeKnapsack[i] * (double) Y[varCoupeKnapsack[i]]; + X -= pi0CoupeKnapsack; + sOpt = -bKnapsack; + for ( i = 0 ; i < NbTermesKnapsack ; i++ ) sOpt += aKnapsack[i] * (double) Y[i]; + if ( fabs( sOpt ) < Zero ) return; /* Prevoir qu'on arrete */ + GammaLB = X / ( sOpt - sBarre ); + goto ResolutionKnapsack; +} + +/* En mettant 0 on doit la detecter violee */ + +*Gamma = GammaLB; + +printf("Valeur de Gamma %e\n",GammaLB); + +free( Y ); + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Recherche d'un coupe de knapsack pour la partie binaire puis lifting de la + variable continue. + Appele par PNE_MIRMarchandWolsey */ + +void PNE_Knapsack_0_1_AvecVariableContinue( PROBLEME_PNE * Pne, + int NombreDeVariablesBinaires, + int * NumeroDeLaVariableBinaire, + double * CoeffDeLaVariableBinaire, + double b, + double ValeurDeLaVariableContinue, + int NombreDeVariablesSubstituees, + int * NumeroDesVariablesSubstituees, + char * TypeDeSubsitution, + double * CoefficientDeLaVariableSubstituee + ) +{ +char CouvertureTrouvee; double SecondMembre; double sBarre; +char RendreLesCoeffsEntiers; char Mixed_0_1_Knapsack; + +Mixed_0_1_Knapsack = OUI_PNE; + +RendreLesCoeffsEntiers = OUI_PNE; +sBarre = ValeurDeLaVariableContinue; +SecondMembre = b + sBarre; +CouvertureTrouvee = NON_PNE; + +/* Les variables binaires ne sont pas encore complementees. Elles le seront dans GreedyCoverKnapsack. + La variable continue a ete creee. */ +PNE_GreedyCoverKnapsack( Pne, 0, NombreDeVariablesBinaires, NumeroDeLaVariableBinaire, CoeffDeLaVariableBinaire, + SecondMembre, RendreLesCoeffsEntiers, &CouvertureTrouvee, + Mixed_0_1_Knapsack, + sBarre, + NombreDeVariablesSubstituees, NumeroDesVariablesSubstituees, + TypeDeSubsitution, CoefficientDeLaVariableSubstituee + ); + + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_knapsack_negligees.c b/src/ext/Sirius_Solver/pne/pne_knapsack_negligees.c new file mode 100644 index 0000000000..850eb91e66 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_knapsack_negligees.c @@ -0,0 +1,262 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Stockage des coupes de sac a dos negligees. + Remarque: on peut faire qq chose de commun avec les G. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 0 + +# define SIZE_ALLOC_COUPES 100 /* Nombre de coupes allouees */ +# define SIZE_ALLOC_TERMES_COUPES (SIZE_ALLOC_COUPES*25) + +void PNE_AllocCoupesKNegligees( PROBLEME_PNE * ); +void PNE_AugmenterNombreDeCoupesKNegligees( PROBLEME_PNE * ); +void PNE_AugmenterLaTailleDesCoupesKNegligees( PROBLEME_PNE * ); + +/*----------------------------------------------------------------------------*/ + +void PNE_AllocCoupesKNegligees( PROBLEME_PNE * Pne ) +{ +COUPES_K_NEGLIGEES * CoupesKNegligees; + +CoupesKNegligees = (COUPES_K_NEGLIGEES *) malloc( sizeof( COUPES_K_NEGLIGEES ) ); +if ( CoupesKNegligees == NULL ) return; + +CoupesKNegligees->SecondMembre = (double *) malloc( SIZE_ALLOC_COUPES * sizeof( double ) ); +if ( CoupesKNegligees->SecondMembre == NULL ) { + return; +} +CoupesKNegligees->LaCoupeEstDansLePool = (char *) malloc( SIZE_ALLOC_COUPES * sizeof( char ) ); +if ( CoupesKNegligees->LaCoupeEstDansLePool == NULL ) { + free( CoupesKNegligees->SecondMembre ); + return; +} +CoupesKNegligees->First = (int *) malloc( SIZE_ALLOC_COUPES * sizeof( int ) ); +if ( CoupesKNegligees->First == NULL ) { + free( CoupesKNegligees->SecondMembre ); + free( CoupesKNegligees->LaCoupeEstDansLePool ); + return; +} +CoupesKNegligees->NbElements = (int *) malloc( SIZE_ALLOC_COUPES * sizeof( int ) ); +if ( CoupesKNegligees->NbElements == NULL ) { + free( CoupesKNegligees->SecondMembre ); + free( CoupesKNegligees->LaCoupeEstDansLePool ); + free( CoupesKNegligees->First ); + return; +} +CoupesKNegligees->NombreDeCoupesAllouees = SIZE_ALLOC_COUPES; + +CoupesKNegligees->Colonne = (int *) malloc( SIZE_ALLOC_TERMES_COUPES * sizeof( int ) ); +if ( CoupesKNegligees->Colonne == NULL ) { + free( CoupesKNegligees->SecondMembre ); + free( CoupesKNegligees->LaCoupeEstDansLePool ); + free( CoupesKNegligees->First ); + free( CoupesKNegligees->NbElements ); + return; +} +CoupesKNegligees->Coefficient = (double *) malloc( SIZE_ALLOC_TERMES_COUPES * sizeof( double ) ); +if ( CoupesKNegligees->Coefficient == NULL ) { + free( CoupesKNegligees->SecondMembre ); + free( CoupesKNegligees->LaCoupeEstDansLePool ); + free( CoupesKNegligees->First ); + free( CoupesKNegligees->NbElements ); + free( CoupesKNegligees->Colonne ); + return; +} +CoupesKNegligees->TailleCoupesAllouee = SIZE_ALLOC_TERMES_COUPES; + +CoupesKNegligees->IndexLibre = 0; +CoupesKNegligees->NombreDeCoupes = 0; +CoupesKNegligees->Full = NON_PNE; +Pne->CoupesKNegligees = CoupesKNegligees; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AugmenterNombreDeCoupesKNegligees( PROBLEME_PNE * Pne ) +{ +COUPES_K_NEGLIGEES * CoupesKNegligees; int Size; double * SecondMembre; char * LaCoupeEstDansLePool; +int * First; int * NbElements; + +CoupesKNegligees = Pne->CoupesKNegligees; +Size = CoupesKNegligees->NombreDeCoupesAllouees + SIZE_ALLOC_COUPES; + +SecondMembre = (double *) realloc( CoupesKNegligees->SecondMembre, Size * sizeof( double ) ); +if ( SecondMembre == NULL ) { + CoupesKNegligees->Full = OUI_PNE; + return; +} +LaCoupeEstDansLePool = (char *) realloc( CoupesKNegligees->LaCoupeEstDansLePool, Size * sizeof( char ) ); +if ( LaCoupeEstDansLePool == NULL ) { + free( SecondMembre ); + CoupesKNegligees->Full = OUI_PNE; + return; +} +First = (int *) realloc( CoupesKNegligees->First, Size * sizeof( int ) ); +if ( First == NULL ) { + free( SecondMembre ); + free( LaCoupeEstDansLePool ); + CoupesKNegligees->Full = OUI_PNE; + return; +} +NbElements = (int *) realloc( CoupesKNegligees->NbElements, Size * sizeof( int ) ); +if ( NbElements == NULL ) { + free( SecondMembre ); + free( LaCoupeEstDansLePool ); + free( First ); + CoupesKNegligees->Full = OUI_PNE; + return; +} +CoupesKNegligees->NombreDeCoupesAllouees = Size; +CoupesKNegligees->SecondMembre = SecondMembre; +CoupesKNegligees->LaCoupeEstDansLePool = LaCoupeEstDansLePool; +CoupesKNegligees->First = First; +CoupesKNegligees->NbElements = NbElements; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AugmenterLaTailleDesCoupesKNegligees( PROBLEME_PNE * Pne ) +{ +COUPES_K_NEGLIGEES * CoupesKNegligees; int Size; int * Colonne; double * Coefficient; + +CoupesKNegligees = Pne->CoupesKNegligees; +Size = CoupesKNegligees->TailleCoupesAllouee + SIZE_ALLOC_TERMES_COUPES; + +Colonne = (int *) realloc( CoupesKNegligees->Colonne, Size * sizeof( int ) ); +if ( Colonne == NULL ) { + CoupesKNegligees->Full = OUI_PNE; + return; +} +Coefficient = (double *) realloc( CoupesKNegligees->Coefficient, Size * sizeof( double ) ); +if ( Coefficient == NULL ) { + free( Colonne ); + CoupesKNegligees->Full = OUI_PNE; + return; +} +CoupesKNegligees->TailleCoupesAllouee = Size; +CoupesKNegligees->Colonne = Colonne; +CoupesKNegligees->Coefficient = Coefficient; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CreerUneCoupeKNegligee( PROBLEME_PNE * Pne, int NumeroDeCoupe ) +{ +COUPES_K_NEGLIGEES * CoupesKNegligees; int il; int NombreDeCoupes; +int Nb; int * First; int * NbElements; int * Colonne; int * Mdeb; int * NbTerm; +int * Nuvar; double * Coefficient; double * A; int il1; int ilMax; + +return; + +Mdeb = Pne->Coupes.Mdeb; +NbTerm = Pne->Coupes.NbTerm; +Nuvar = Pne->Coupes.Nuvar; +A = Pne->Coupes.A; + +CoupesKNegligees = Pne->CoupesKNegligees; +if ( CoupesKNegligees == NULL ) { + PNE_AllocCoupesKNegligees( Pne ); + CoupesKNegligees = Pne->CoupesKNegligees; + if ( CoupesKNegligees == NULL ) return; /* Saturation memoire */ +} + +NombreDeCoupes = CoupesKNegligees->NombreDeCoupes; + +/* Place suffisante */ +if ( NombreDeCoupes >= CoupesKNegligees->NombreDeCoupesAllouees ) { + /* On augmente la taille */ + PNE_AugmenterNombreDeCoupesKNegligees( Pne ); + if ( Pne->CoupesKNegligees == NULL ) return; + if ( CoupesKNegligees->Full == OUI_PNE ) return; +} + +/* Place suffisante */ +il1 = CoupesKNegligees->IndexLibre; +while ( il1 + NbTerm[NumeroDeCoupe] + 1 >= CoupesKNegligees->TailleCoupesAllouee ) { + /* On augmente la taille */ + PNE_AugmenterLaTailleDesCoupesKNegligees( Pne ); + if ( Pne->CoupesKNegligees == NULL ) return; + if ( CoupesKNegligees->Full == OUI_PNE ) return; +} + +First = CoupesKNegligees->First; +NbElements = CoupesKNegligees->NbElements; +Coefficient = CoupesKNegligees->Coefficient; +Colonne = CoupesKNegligees->Colonne; + +First[NombreDeCoupes] = il1; +Nb = 0; +il = Mdeb[NumeroDeCoupe]; +ilMax = il + NbTerm[NumeroDeCoupe]; +while ( il < ilMax ) { + if ( A[il] != 0 ) { + Coefficient[il1] = A[il]; + Colonne[il1] = Nuvar[il]; + il1++; + Nb++; + } + il++; +} +NbElements[NombreDeCoupes] = Nb; + +CoupesKNegligees->SecondMembre[NombreDeCoupes] = Pne->Coupes.B[NumeroDeCoupe]; + +# if TRACES == 1 + printf("Coupe de K negligee: %d\n",NombreDeCoupes); + il = First[NombreDeCoupes]; + ilMax = il + NbElements[NombreDeCoupes]; + while ( il < ilMax ) { + if ( Pne->TypeDeVariableTrav[Colonne[il]] == ENTIER ) printf("%e (%d I) ",Coefficient[il],Colonne[il]); + else printf("%e (%d R) ",Coefficient[il],Colonne[il]); + il++; + } + printf(" SecondMembre %e\n",CoupesKNegligees->SecondMembre[NombreDeCoupes]); +# endif + +CoupesKNegligees->IndexLibre = il1; +CoupesKNegligees->LaCoupeEstDansLePool[NombreDeCoupes] = NON_PNE; +CoupesKNegligees->NombreDeCoupes++; + +return; +} + + diff --git a/src/ext/Sirius_Solver/pne/pne_knapsack_negligees_violees.c b/src/ext/Sirius_Solver/pne/pne_knapsack_negligees_violees.c new file mode 100644 index 0000000000..fc02112bae --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_knapsack_negligees_violees.c @@ -0,0 +1,131 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Detection des coupes de knapsack negliges violees. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define PROFONDEUR_LIMITE_COUPES_DE_K 10 + +/*----------------------------------------------------------------------------*/ + +void PNE_DetectionKnapsackNegligeesViolees( PROBLEME_PNE * Pne ) +{ +double S; int Cnt; double E; int * First; int * NbElements; int NbV; double NormeV; +int il; int ilMax; double * Coeff; int * Indice; double B; int NbT; double * X; +int * Colonne; char * LaCoupeEstDansLePool; double * SecondMembre; +double * Coefficient; COUPES_K_NEGLIGEES * CoupesKNegligees; double Marge; +int * TypeDeBorne; BB * Bb; + +Marge = 0.01; + +Bb = Pne->ProblemeBbDuSolveur; +if ( Bb->NoeudEnExamen->ProfondeurDuNoeud > PROFONDEUR_LIMITE_COUPES_DE_K ) return; + +if ( Pne->CoupesKNegligees == NULL ) return; +CoupesKNegligees = Pne->CoupesKNegligees; + +TypeDeBorne = Pne->TypeDeBorneTrav; +X = Pne->UTrav; +Coeff = Pne->Coefficient_CG; +Indice = Pne->IndiceDeLaVariable_CG; + +First = CoupesKNegligees->First; +LaCoupeEstDansLePool = CoupesKNegligees->LaCoupeEstDansLePool; +NbElements = CoupesKNegligees->NbElements; +SecondMembre = CoupesKNegligees->SecondMembre; +Colonne = CoupesKNegligees->Colonne; +Coefficient = CoupesKNegligees->Coefficient; + +NbV = 0; +NormeV = 0.0; +for ( Cnt = 0 ; Cnt < CoupesKNegligees->NombreDeCoupes ; Cnt++ ) { + if ( First[Cnt] < 0 ) continue; + if ( LaCoupeEstDansLePool[Cnt] == OUI_PNE ) continue; + il = First[Cnt]; + ilMax = il + NbElements[Cnt]; + S = 0; + NbT = 0; + B = CoupesKNegligees->SecondMembre[Cnt]; + while ( il < ilMax ) { + if ( TypeDeBorne[Colonne[il]] != VARIABLE_FIXE ) { + /* Car sinon il n'y a pas de variable correspondante dans le simplexe */ + S += Coefficient[il] * X[Colonne[il]]; + Coeff[NbT] = Coefficient[il]; + Indice[NbT] = Colonne[il]; + NbT++; + } + else { + B -= Coefficient[il] * X[Colonne[il]]; + } + il++; + } + if ( S > B + Marge && NbT > 0 ) { + /* + printf("NbT %d depassement %e\n",NbT,S-B); + for ( il = 0 ; il < NbT ; il++ ) { + printf(" %e (%d) ",Coeff[il],Indice[il]); + } + printf("< %e\n",B); + */ + E = S - B; + NormeV += E; + /* On Stocke la coupe */ + NbV++; + PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'K', NbT, B, E, Coeff, Indice ); + Pne->CoupesCalculees[Pne->NombreDeCoupesCalculees-1]->IndexDansKNegligees = Cnt; + } +} + +if ( Pne->AffichageDesTraces == OUI_PNE && NbV > 0 ) { + printf("Adding %d initially neglected Knapsack cuts violated by %e\n",NbV,NormeV); + fflush( stdout ); +} + +return; +} + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_knapsack_sur_coupe.c b/src/ext/Sirius_Solver/pne/pne_knapsack_sur_coupe.c new file mode 100644 index 0000000000..59f72607e4 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_knapsack_sur_coupe.c @@ -0,0 +1,254 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul d'une couope de knapsack sur une coupe de Gomory + ou sur une coupe d'intersection. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define RAPPORT_MAX 1.e+5 +# define ZERO_COEFFMN 1.e-4 + +# define MAX_TERMES_POUR_KNAPSACK_DANS_COUPE 100 + +/*----------------------------------------------------------------------------*/ + +void PNE_CalculerUneKnapsackSurGomoryOuIntersection( PROBLEME_PNE * Pne, + double * Coefficient_CG, + int * IndiceDeLaVariable_CG, + double SecondMembre, + int NombreDeTermes, + double PlusGrandCoeff ) +{ +int i; char Kpossible; int Var; char CouvertureTrouvee; int NbT; double CoeffMx; double CoeffMn; +double * Coeff; int * Variable; int * TypeDeBorneTrav; double * UminTrav; double Coefficient; +int * TypeDeVariableTrav; double * UmaxTrav; char Trouve; char RendreLesCoeffsEntiers; +char Mixed_0_1_Knapsack; + +int Cnt1; double bBorne; int VarBin; double u; double l; char Found; int i1; + +# if NORMALISER_LES_COUPES_SUR_LES_G_ET_I == OUI_PNE + double Normalisation; +# endif + +# if NORMALISER_LES_COUPES_SUR_LES_G_ET_I != OUI_PNE + PlusGrandCoeff = 1.; /* Pour ne pas avoir de warning a a compilation */ +# endif + +Mixed_0_1_Knapsack = NON_PNE; + +Kpossible = OUI_PNE; +NbT = 0; +Coeff = Pne->ValeurLocale; +Variable = Pne->IndiceLocal; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; + +/* Si les Gomory et les coupes d'intersection sont normalisees, on revient aux valeurs initiales */ +# if NORMALISER_LES_COUPES_SUR_LES_G_ET_I == OUI_PNE + Normalisation = PlusGrandCoeff; + SPX_ArrondiEnPuissanceDe2( &Normalisation ); + for ( i = 0 ; i < NombreDeTermes ; i++ ) Coefficient_CG[i] *= Normalisation; + SecondMembre *= Normalisation; +# endif + +CoeffMx = -LINFINI_PNE; +CoeffMn = LINFINI_PNE; + +for ( i = 0 ; i < NombreDeTermes ; i++ ) { + Var = IndiceDeLaVariable_CG[i]; + Coefficient = Coefficient_CG[i]; + if ( TypeDeVariableTrav[Var] == ENTIER ) { + + /* Attention a cause des bornes variables il faut verifier que la variable n'y est pas deja. Peut etre ameliore */ + Found = 0; + /* + for ( i1 = 0 ; i1 < NbT ; i1++ ) { + if ( Variable[i1] == Var ) { + Found = 1; + Coeff[i1] += Coefficient; + if ( fabs( Coeff[i1] ) > CoeffMx ) CoeffMx = fabs( Coeff[i1] ); + else if ( fabs( Coeff[i1] ) < CoeffMn ) CoeffMn = fabs( Coeff[i1] ); + break; + } + } + */ + /* Fin borne sup variable */ + + if ( Found == 0 ) { + Coeff[NbT] = Coefficient; + if ( fabs( Coefficient ) > CoeffMx ) CoeffMx = fabs( Coefficient ); + else if ( fabs( Coefficient ) < CoeffMn ) CoeffMn = fabs( Coefficient ); + Variable[NbT] = Var; + NbT++; + } + continue; + } + + if ( Coefficient < 0.0 ) { + /* Il faut monter la variable au max */ + + + + /* S'il y a une borne sup variable on remplace la variable par sa borne sup variable */ + if ( Pne->CntDeBorneSupVariable != NULL && 0 ) { + if ( Pne->CntDeBorneSupVariable[Var] >= 0 ) { + Cnt1 = Pne->CntDeBorneSupVariable[Var]; + i1 = Pne->MdebTrav[Cnt1]; + bBorne = Pne->BTrav[Cnt1]; + SecondMembre -= Coefficient * bBorne ; + VarBin = Pne->NuvarTrav[i1]; + + u = -Pne->ATrav[i1]; + /* Peut etre ameliore */ + Found = 0; + for ( i1 = 0 ; i1 < NbT ; i1++ ) { + if ( Variable[i1] == VarBin ) { + Found = 1; + Coeff[i1] += Coefficient * u; + if ( fabs( Coeff[i1] ) > CoeffMx ) CoeffMx = fabs( Coeff[i1] ); + else if ( fabs( Coeff[i1] ) < CoeffMn ) CoeffMn = fabs( Coeff[i1] ); + break; + } + } + if ( Found == 0 ) { + Coeff[NbT] = Coefficient * u; + Variable[NbT] = VarBin; + if ( fabs( Coeff[NbT] ) > CoeffMx ) CoeffMx = fabs( Coeff[NbT] ); + else if ( fabs( Coeff[NbT] ) < CoeffMn ) CoeffMn = fabs( Coeff[NbT] ); + NbT++; + } + /*printf("Variable bound ajoute\n");*/ + continue; + } + } + /* Fin borne sup variable */ + + if ( TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + SecondMembre -= Coefficient * UmaxTrav[Var]; + } + else { + Kpossible = NON_PNE; + break; + } + } + else { + /* Il faut baisser la variable au min */ + + + /* S'il y a une borne sup variable on remplace la variable par sa borne sup variable */ + if ( Pne->CntDeBorneInfVariable != NULL && 0 ) { + if ( Pne->CntDeBorneInfVariable[Var] >= 0 ) { + Cnt1 = Pne->CntDeBorneInfVariable[Var]; + i1 = Pne->MdebTrav[Cnt1]; + bBorne = -Pne->BTrav[Cnt1]; + SecondMembre -= Coefficient * bBorne ; + VarBin = Pne->NuvarTrav[i1]; + l = Pne->ATrav[i1]; + /* Peut etre ameliore */ + Found = 0; + for ( i1 = 0 ; i1 < NbT ; i1++ ) { + if ( Variable[i1] == VarBin ) { + Found = 1; + Coeff[i1] += Coefficient * l; + break; + } + } + if ( Found == 0 ) { + Coeff[NbT] = Coefficient * l; + Variable[NbT] = VarBin; + NbT++; + } + /*printf("Variable bound ajoute\n");*/ + continue; + } + } + /* Fin borne inf variable */ + + if ( TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + SecondMembre -= Coefficient * UminTrav[Var]; + } + else { + Kpossible = NON_PNE; + break; + } + } +} + +/* Si le second membre est positif et que tous les coeff sont negatifs alors la contrainte ne sera jamais + violee */ +if ( SecondMembre >= 0.0 ) { + Trouve = NON_PNE; + for ( i = 0 ; i < NbT ; i++ ) { + if ( Coeff[i] > 0.0 ) { + Trouve = OUI_PNE; + break; + } + } + if ( Trouve == NON_PNE ) Kpossible = NON_PNE; +} + +if ( Kpossible == OUI_PNE && NbT >= MIN_TERMES_POUR_KNAPSACK && NbT <= MAX_TERMES_POUR_KNAPSACK_DANS_COUPE ) { + /* + printf("On peut tenter une K sur la Gomory NbT %d \n",NbT); + for ( i = 0 ; i < NbT ; i++ ) { + printf(" %e (%d)",Coeff[i],Variable[i]); + } + printf(" < %e\n",SecondMembre); fflush(stdout); + */ + + if ( fabs( SecondMembre ) > CoeffMx ) CoeffMx = fabs( SecondMembre ); + else if ( fabs( SecondMembre ) < CoeffMn ) CoeffMn = fabs( SecondMembre ); + + RendreLesCoeffsEntiers = NON_PNE; + if ( CoeffMn > ZERO_COEFFMN ) { + if ( CoeffMx / CoeffMn < RAPPORT_MAX ) RendreLesCoeffsEntiers = OUI_PNE; + } + + CouvertureTrouvee = NON_PNE; + PNE_GreedyCoverKnapsack( Pne, 0, NbT, Variable, Coeff, SecondMembre, RendreLesCoeffsEntiers, &CouvertureTrouvee, + Mixed_0_1_Knapsack, 0.0, 0, NULL, NULL, NULL ); + /* + if ( CouvertureTrouvee == OUI_PNE ) { + printf(" K trouvee sur Gomory ou coupe d'intersection !!!!!!!!!!!!!!\n"); + } + */ +} + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_lire_jeu_de_donnees_mps.c b/src/ext/Sirius_Solver/pne/pne_lire_jeu_de_donnees_mps.c new file mode 100644 index 0000000000..971a6afd5e --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_lire_jeu_de_donnees_mps.c @@ -0,0 +1,1278 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Lecture du jeu de donnees au format MPS + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" +# include "pne_define.h" +# include "pne_fonctions.h" + +# include "mps_define.h" +# include "mps_global.h" + +int aHashCode = 31; +int kHashCode = 0; + +# define OFFSET_BASIS 0 /*2166136261*/ +# define FNV_PRIME 16777619 + +/*----------------------------------------------------------------------------*/ + +void PNE_LireJeuDeDonneesMPS() +{ +FILE * Flot; +int LgMax ; int Count; int PositionDansLeFichier; int i ; +int CntCourant; int Cnt ; int ilk ; int NbChamps ; +int ilMps ; int il ; int NbInit ; int CountVar ; +int CountTrm ; int VariablesBinairesEnCours ; +int VarCourant; int BaseVar ; int BaseCnt ; +int j; double SensOpt; + +double PlusLinfiniBis; double CoefficientMps; double CoefficientMpsB; + +double * A; int * Nuvar; int * Mdeb; int * NbTerm; + +char * LigneLue; +char TypeDeContrainte[2] ; char * LabelDeLaContrainteLue ; +char * LabelDeLaVariableLue ; char * LabelDeLaVariablePrecedente; +char * LabelDeLaContrainteLueB ; char * LabelDuSecondMembreLu ; +char * ValeurLue ; char * ValeurLueB ; +char * ValeurLueC ; char TypeDeBorne[3] ; +char * LabelDeLaBorneLue ; + +/* SensOpt = 1 si minimisation et SensOpt = -1. si maximisation */ +SensOpt = 1.; + +Mps.CoeffHaschCodeContraintes = 6; +Mps.SeuilHaschCodeContraintes = 8; + +Mps.CoeffHaschCodeVariables = 3; +Mps.SeuilHaschCodeVariables = 8; + +Flot = fopen( "A_JEU_DE_DONNEES", "r" ); +if( Flot == NULL ) { + printf("Erreur ouverture du fichier contenant le jeu de donnees \n"); + exit(0); +} + +LgMax = 1024; +LigneLue = (char *) malloc( LgMax ); +LabelDeLaContrainteLue = (char *) malloc( LgMax ); +LabelDeLaVariableLue = (char *) malloc( LgMax ); +LabelDeLaVariablePrecedente = (char *) malloc( LgMax ); +LabelDeLaContrainteLueB = (char *) malloc( LgMax ); +LabelDuSecondMembreLu = (char *) malloc( LgMax ); +LabelDeLaBorneLue = (char *) malloc( LgMax ); +ValeurLue = (char *) malloc( LgMax ); +ValeurLueB = (char *) malloc( LgMax ); +ValeurLueC = (char *) malloc( LgMax ); +if ( LigneLue == NULL || LabelDeLaContrainteLue == NULL || + LabelDeLaVariableLue == NULL || LabelDeLaVariablePrecedente == NULL || + LabelDeLaContrainteLueB == NULL || LabelDuSecondMembreLu == NULL || + LabelDeLaBorneLue == NULL || ValeurLue == NULL || + ValeurLueB == NULL || ValeurLueC == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_LireJeuDeDonneesMPS \n"); + exit(0); +} + +Mps.NbVar = -1; +Mps.NbCnt = -1; + +PlusLinfiniBis = 1.e+70 /*1.e+8*/; + +/* + Les champs du format MPS +Champ1 : 2- 3 +Champ2 : 5-12 +Champ3 : 15-22 +Champ4 : 25-36 +Champ5 : 40-47 +Champ6 : 50-61 +*/ + +/* Lecture des lignes */ +/* The section is preceded by a card with ROWS in columns 1-4 */ +while ( 1 ) { + fgets( LigneLue , LgMax , Flot ); + + if( strstr( LigneLue , "OBJSENSE" ) == LigneLue ) { + /* Dans ce cas on verifie s'il s'agit d'un maximisation ou d'une minimisation */ + /* On verifie s'il le maximize ou le minimize est sur la ligne sinon on le cherche dans les lignes suivantes */ + if( strstr( LigneLue , "MAXIMIZE" ) != NULL ) { + SensOpt = -1.; + } + else if( strstr( LigneLue , "MINIMIZE" ) != NULL ) { + SensOpt = 1.; + } + else { + fgets( LigneLue , LgMax , Flot ); + if( strstr( LigneLue , "MAXIMIZE" ) != NULL ) { + SensOpt = -1.; + } + else if( strstr( LigneLue , "MINIMIZE" ) != NULL ) { + SensOpt = 1.; + } + else { + printf("Sens de l'opimisation (MINIMIZE ou MAXIMIZE) pas trouve dans les donnees\n"); + exit(0); + } + } + } + + if( strstr( LigneLue , "ROWS" ) == LigneLue ) break; +} + +/* +In this section all the row labels are defined, as well as the row type. The row +type is entered in field 1 (in column 2 or 3) and the row label is entered in +field 2 (columns 5-12). Row type: +E : egalité +L : inferieur ou egal +G : superieur ou egal +N : objectif +N : free ?? +*/ +/*printf("Debut de la lecture des cartes ROWS \n ");*/ +PositionDansLeFichier = ftell( Flot ); /* Stockage du debut des informations sur ROWS */ + +Count = 0; +while ( 1 ) { /* Pour savoir combien de contraintes il faut allouer */ + fgets( LigneLue , LgMax , Flot ); + if( strstr( LigneLue , "COLUMNS" ) == LigneLue ) break; + Count++; +} +/* Allocations */ +Mps.Mdeb = (int *) malloc( Count * sizeof( int ) ); +Mps.Mder = (int *) malloc( Count * sizeof( int ) ); +Mps.NbTerm = (int *) malloc( Count * sizeof( int ) ); +Mps.B = (double *) malloc( Count * sizeof( double ) ); +Mps.SensDeLaContrainte = (char *) malloc( Count * sizeof( char ) ); +Mps.BRange = (double *) malloc( Count * sizeof( double ) ); +Mps.VariablesDualesDesContraintes = (double *) malloc( Count * sizeof( double ) ); +Mps.LabelDeLaContrainte = (char **) malloc( Count * sizeof( void * ) ); +Mps.LabelDuSecondMembre = (char **) malloc( Count * sizeof( void * ) ); +if ( Mps.Mdeb == NULL || Mps.Mder == NULL || + Mps.NbTerm == NULL || Mps.B == NULL || + Mps.SensDeLaContrainte == NULL || Mps.BRange == NULL || + Mps.VariablesDualesDesContraintes == NULL || + Mps.LabelDeLaContrainte == NULL || + Mps.LabelDuSecondMembre == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_LireJeuDeDonneesMPS \n"); + exit(0); +} + +Mps.NbCntRange = 0; +for ( i = 0; i < Count ; i++ ) { + Mps.B[i] = 0.0; + Mps.BRange[i] = 0.0; +} + +Mps.LabelDeLObjectif = NULL; + +fseek( Flot , PositionDansLeFichier , SEEK_SET ); /* Repositionnement dans le fichier */ +while ( 1 ) { + fgets( LigneLue , LgMax , Flot ); + + if( strstr( LigneLue , "COLUMNS" ) == LigneLue ) break; + + NbChamps = sscanf( LigneLue , "%s %s" , TypeDeContrainte, LabelDeLaContrainteLue); + if ( NbChamps <= 0 ) continue; + + if ( TypeDeContrainte[0] == 'N' ) { + if ( Mps.LabelDeLObjectif == NULL ) { + /* Objectif */ + Mps.LabelDeLObjectif = (char *) malloc( strlen( LabelDeLaContrainteLue ) + 1 ); + strcpy( Mps.LabelDeLObjectif , LabelDeLaContrainteLue ); + continue; + } + } + + Mps.NbCnt++; + Mps.LabelDeLaContrainte[Mps.NbCnt] = (char *) malloc( strlen( LabelDeLaContrainteLue ) + 1 ); + strcpy( Mps.LabelDeLaContrainte[Mps.NbCnt] , LabelDeLaContrainteLue ); + /*printf("Contrainte lue : %s\n",Mps.LabelDeLaContrainte[Mps.NbCnt]);*/ + Mps.B[Mps.NbCnt] = 0.; + if ( TypeDeContrainte[0] == 'E' ) { /* Egalite */ + Mps.SensDeLaContrainte[Mps.NbCnt] = '='; + continue; + } + if ( TypeDeContrainte[0] == 'L' ) { /* Inferieur ou egal */ + Mps.SensDeLaContrainte[Mps.NbCnt] = '<'; + continue; + } + if ( TypeDeContrainte[0] == 'G' ) { /* Superieur ou egal */ + Mps.SensDeLaContrainte[Mps.NbCnt] = '>'; + continue; + } + if ( TypeDeContrainte[0] == 'N' ) { /* Free */ + Mps.SensDeLaContrainte[Mps.NbCnt] = 'N'; + continue; + } + printf(" Type de contrainte non reconnu: %s \n",TypeDeContrainte); + exit(0); +} +Mps.NbCnt++; /* Important */ + +BaseCnt = 0; +PNE_CreerHashCodeContrainteMPS( /*&BaseCnt*/ ); + +/* Lecture des colonnes */ +/* +printf("Debut de la lecture des cartes COLUMNS \n"); fflush(stdout); +*/ +/* The section is preceded by a card with COLUMNS in columns 1-7 */ +PositionDansLeFichier = ftell( Flot ); /* Stockage du debut des informations sur ROWS */ + +memset( (char *) LabelDeLaVariablePrecedente , ' ' , LgMax * sizeof( char ) ); +CountVar = 0; +CountTrm = 0; +CoefficientMpsB = 0.0; /* Pour ne pas etre embete par les warning de compilation */ +while ( 1 ) { /* Pour savoir combien de variables il faut allouer */ + + memset( (char *) LabelDeLaContrainteLue , ' ' , LgMax * sizeof( char ) ); + memset( (char *) LabelDeLaContrainteLue , ' ' , LgMax * sizeof( char ) ); + memset( (char *) LabelDeLaContrainteLueB , ' ' , LgMax * sizeof( char ) ); + memset( (char *) LabelDeLaVariableLue , ' ' , LgMax * sizeof( char ) ); + + fgets( LigneLue , LgMax , Flot ); + + if( strstr( LigneLue , "RHS" ) == LigneLue ) break; + if( strstr( LigneLue , "ENDATA" ) == LigneLue ) goto FinLecture; + + NbChamps = sscanf( LigneLue , "%s %s %s %s %s" , + LabelDeLaVariableLue , LabelDeLaContrainteLue , ValeurLue , + LabelDeLaContrainteLueB , ValeurLueB ); + if ( NbChamps <= 0 ) continue; + + CoefficientMps = atof( ValeurLue ); + if ( NbChamps > 3 ) CoefficientMpsB = atof( ValeurLueB ); + + if ( strcmp( LabelDeLaVariableLue , LabelDeLaVariablePrecedente ) != 0 ) { /* Nouvelle variable */ + CountVar++; + } + strcpy( LabelDeLaVariablePrecedente , LabelDeLaVariableLue ); + CountTrm++; + if ( NbChamps > 3 ) CountTrm++; + +} + +/* Allocations des tableaux */ +Mps.LabelDeLaVariable = (char **) malloc( CountVar * sizeof( void * ) ); +Mps.TypeDeVariable = (int *) malloc( CountVar * sizeof( int ) ); +Mps.TypeDeBorneDeLaVariable = (int *) malloc( CountVar * sizeof( int ) ); +Mps.U = (double *) malloc( CountVar * sizeof( double ) ); +Mps.L = (double *) malloc( CountVar * sizeof( double ) ); +Mps.Umin = (double *) malloc( CountVar * sizeof( double ) ); +Mps.Umax = (double *) malloc( CountVar * sizeof( double ) ); + +Mps.A = (double *) malloc( CountTrm * sizeof( double ) ); +Mps.Nuvar = (int *) malloc( CountTrm * sizeof( int ) ); +Mps.Msui = (int * ) malloc( CountTrm * sizeof( int ) ); + +if ( Mps.LabelDeLaVariable == NULL || Mps.TypeDeVariable == NULL || Mps.TypeDeBorneDeLaVariable == NULL || + Mps.U == NULL || Mps.L == NULL || Mps.Umin == NULL || + Mps.Umax == NULL || Mps.A == NULL || Mps.Nuvar == NULL || + Mps.Msui == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_LireJeuDeDonneesMPS \n"); + exit(0); +} + +for ( i = 0 ; i < CountVar ; i++ ) Mps.L[i] = 0.0; + +/* Phase effective de lecture */ +memset( (char *) Mps.NbTerm , 0 , Mps.NbCnt * sizeof( int ) ); +for ( i = 0 ; i < Mps.NbCnt ; i++ ) { + Mps.Mdeb[i] = -1; + Mps.Mder[i] = -1; +} + +CntCourant = 0; +il = -1; +memset( (char *) LabelDeLaVariablePrecedente , ' ' , LgMax * sizeof( char ) ); + +VariablesBinairesEnCours = NON_MPS; + +fseek( Flot , PositionDansLeFichier , SEEK_SET ); /* Repositionnement dans le fichier */ +while ( 1 ) { + + fgets( LigneLue , LgMax , Flot ); + if( strstr( LigneLue , "RHS" ) == LigneLue ) break; + + memset( (char *) LabelDeLaContrainteLue , ' ' , LgMax * sizeof( char ) ); + memset( (char *) LabelDeLaContrainteLue , ' ' , LgMax * sizeof( char ) ); + memset( (char *) LabelDeLaContrainteLueB , ' ' , LgMax * sizeof( char ) ); + memset( (char *) LabelDeLaVariableLue , ' ' , LgMax * sizeof( char ) ); + + if ( strstr( LigneLue , "MARKER" ) != 0 && strstr( LigneLue , "INTORG" ) != 0 ) { + /* printf("Lecture de variables entieres \n"); */ + VariablesBinairesEnCours = OUI_MPS; + continue; + } + + if ( strstr( LigneLue , "MARKER" ) != 0 && strstr( LigneLue , "INTEND" ) != 0 ) { + /* printf("Fin lecture de variables entieres \n"); */ + if( VariablesBinairesEnCours == OUI_MPS ) VariablesBinairesEnCours = NON_MPS; + continue; + } + + NbChamps = sscanf( LigneLue , "%s %s %s %s %s" , + LabelDeLaVariableLue , LabelDeLaContrainteLue , ValeurLue , + LabelDeLaContrainteLueB , ValeurLueB ); + if ( NbChamps <= 0 ) continue; + + CoefficientMps = atof( ValeurLue ); + if ( NbChamps > 3 ) CoefficientMpsB = atof( ValeurLueB ); + + if ( strcmp( LabelDeLaVariableLue , LabelDeLaVariablePrecedente ) != 0 ) { /* Nouvelle variable */ + Mps.NbVar++; + Mps.LabelDeLaVariable[Mps.NbVar] = (char *) malloc( strlen( LabelDeLaVariableLue ) + 1 ); + strcpy( Mps.LabelDeLaVariable[Mps.NbVar] , LabelDeLaVariableLue ); + + Mps.L[Mps.NbVar] = 0.; + + Mps.Umin [Mps.NbVar] = 0.; + Mps.Umax [Mps.NbVar] = PlusLinfiniBis; + Mps.TypeDeVariable[Mps.NbVar] = REEL; + + Mps.TypeDeBorneDeLaVariable[Mps.NbVar] = VARIABLE_BORNEE_INFERIEUREMENT; + + if ( VariablesBinairesEnCours == OUI_MPS ) { + Mps.Umin [Mps.NbVar] = 0.; + Mps.Umax [Mps.NbVar] = 1.; + Mps.TypeDeVariable[Mps.NbVar] = ENTIER; + } + } + strcpy( LabelDeLaVariablePrecedente , LabelDeLaVariableLue ); + + if( Mps.LabelDeLObjectif != NULL ) { + if ( strcmp( LabelDeLaContrainteLue , Mps.LabelDeLObjectif ) == 0 ) { + Mps.L[Mps.NbVar] = CoefficientMps; + if ( NbChamps <= 3 ) continue; /* Vers la fin du while */ + else goto DeuxiemeSerie; + } + } + /* Recherche de la contrainte */ + PNE_RechercheDuNumeroDeContrainteMPS( /*CntCourant, BaseCnt,*/ &Cnt, LabelDeLaContrainteLue ); + + /* Contrainte trouvee */ + if ( Mps.Mdeb[Cnt] < 0 ) { + Mps.Mdeb[Cnt] = il + 1; + Mps.Msui[il + 1] = -1; + Mps.Mder[Cnt] = il + 1; + } + Mps.NbTerm[Cnt]++; + il++; + ilk = Mps.Mder[Cnt] ; + Mps.Msui [ilk] = il; + Mps.Msui [il] = -1; + Mps.Mder [Cnt] = il; + Mps.A [il] = CoefficientMps; + Mps.Nuvar[il] = Mps.NbVar; + + CntCourant = Cnt; + + /* Nouvelle lecture sur la meme ligne */ + DeuxiemeSerie: + + if ( NbChamps <= 3 ) continue; + + if( Mps.LabelDeLObjectif != NULL ) { + if ( strcmp( LabelDeLaContrainteLueB , Mps.LabelDeLObjectif ) == 0 ) { + if ( Mps.L[Mps.NbVar] != 0.0 ) { + if ( Mps.L[Mps.NbVar] != CoefficientMpsB ) { + printf("Erreur dans le fichier MPS: la variable %s est donnee avec plusieurs couts differents\n",LabelDeLaVariableLue); + printf(" seule la premiere valeur rencontree est utilisee\n"); + } + } + if ( Mps.L[Mps.NbVar] == 0.0 ) Mps.L[Mps.NbVar] = CoefficientMpsB; + continue; /* Vers la fin du while */ + } + } + + /* Recherche de la 2eme contrainte qui se trouve sur la meme ligne */ + PNE_RechercheDuNumeroDeContrainteMPS( /*CntCourant, BaseCnt,*/ &Cnt, LabelDeLaContrainteLueB ); + /* Contrainte trouvee */ + if ( Mps.Mdeb[Cnt] < 0 ) { + Mps.Mdeb[Cnt] = il + 1; + Mps.Msui[il + 1] = -1; + Mps.Mder[Cnt] = il + 1; + } + Mps.NbTerm[Cnt]++; + il++; + ilk = Mps.Mder[Cnt] ; + Mps.Msui [ilk] = il; + Mps.Msui [il] = -1; + Mps.Mder [Cnt] = il; + Mps.A [il] = CoefficientMpsB; + Mps.Nuvar[il] = Mps.NbVar; + + CntCourant = Cnt; + +} +Mps.NbVar++; /* Important */ + +BaseVar = 0; +PNE_CreerHashCodeVariableMPS( /*&BaseVar*/ ); +/* +printf("Fin de la lecture de COLUMNS, nombre de variables %d \n",Mps.NbVar); fflush(stdout); +*/ +/* Lecture des valeurs de second membre */ +/* The section is preceded by a card with RHS in columns 1-3 */ +NbInit = 0; +CntCourant = 0; + +while ( 1 ) { + fgets( LigneLue , LgMax , Flot ); + if( strstr( LigneLue , "RANGES" ) == LigneLue ) break; + if( strstr( LigneLue , "BOUNDS" ) == LigneLue ) goto BOUNDS; + if( strstr( LigneLue , "ENDATA" ) == LigneLue ) goto FinLecture; + + NbChamps = sscanf( LigneLue , "%s %s %s %s %s" , + LabelDuSecondMembreLu , LabelDeLaContrainteLue , ValeurLue , + LabelDeLaContrainteLueB , ValeurLueB ); + if ( NbChamps <= 0 ) continue; + + CoefficientMps = atof( ValeurLue ); + if ( NbChamps > 3 ) CoefficientMpsB = atof( ValeurLueB ); + + PNE_RechercheDuNumeroDeContrainteMPS( /*CntCourant, BaseCnt,*/ &Cnt, LabelDeLaContrainteLue ); + + /* Contrainte trouvee */ + NbInit++; + Mps.LabelDuSecondMembre[Cnt] = (char *) malloc( strlen( LabelDuSecondMembreLu ) + 1 ); + strcpy( Mps.LabelDuSecondMembre[Cnt] , LabelDuSecondMembreLu ); + Mps.B[Cnt] = CoefficientMps; + + CntCourant = Cnt; + + /* Nouvelle lecture sur la meme ligne */ + if ( NbChamps <= 3 ) continue; + + /* Recherche de la 2eme contrainte qui se trouve sur la meme ligne */ + + PNE_RechercheDuNumeroDeContrainteMPS( /*CntCourant, BaseCnt,*/ &Cnt, LabelDeLaContrainteLueB ); + + /* Contrainte trouvee */ + NbInit++; + Mps.LabelDuSecondMembre[Cnt] = (char *) malloc( strlen( LabelDuSecondMembreLu ) + 1 ); + strcpy( Mps.LabelDuSecondMembre[Cnt] , LabelDuSecondMembreLu ); /* A revoir a corriger car ca sert a rien */ + Mps.B[Cnt] = CoefficientMpsB; + + CntCourant = Cnt; + +} + +/* Presence eventuelle de contraintes Range */ + +CntCourant = 0; +while ( 1 ) { + fgets( LigneLue , LgMax , Flot ); + if( strstr( LigneLue , "BOUNDS" ) == LigneLue ) break; + if( strstr( LigneLue , "ENDATA" ) == LigneLue ) goto FinLecture; + + NbChamps = sscanf( LigneLue , "%s %s %s %s %s" , + LabelDuSecondMembreLu , LabelDeLaContrainteLue , ValeurLue , + LabelDeLaContrainteLueB , ValeurLueB ); + if ( NbChamps <= 0 ) continue; + + CoefficientMps = atof( ValeurLue ); + if ( NbChamps > 3 ) CoefficientMpsB = atof( ValeurLueB ); + + PNE_RechercheDuNumeroDeContrainteMPS( /*CntCourant, BaseCnt,*/ &Cnt, LabelDeLaContrainteLue ); + + /* Contrainte trouvee */ + Mps.NbCntRange+= 1; + Mps.BRange[Cnt] = CoefficientMps; + + CntCourant = Cnt; + + /* Nouvelle lecture sur la meme ligne */ + if ( NbChamps <= 3 ) continue; + + /* Recherche de la 2eme contrainte qui se trouve sur la meme ligne */ + + PNE_RechercheDuNumeroDeContrainteMPS( /*CntCourant, BaseCnt,*/ &Cnt, LabelDeLaContrainteLueB ); + + /* Contrainte trouvee */ + Mps.NbCntRange+= 1; + Mps.BRange[Cnt] = CoefficientMpsB; + + CntCourant = Cnt; + +} + +BOUNDS: + +/* + Lecture des bornes sur le variables + The section is preceded by a card with BOUNDS in columns 1-6. + The bounds are entered as a row, with a corresponding row label. + The nonzero entries in this row vector correspond to columns + in the matrix and must be in the same order in which the column + names appear in the COLUMNS section. + When bounds are not specified for a column (or the entire BOUNDS + section omitted) the usual bounds 0 + infini , are assumed. + More than one bound for a particular variable may be entered, i.e., + both a lower and an upper bound; when only one is specified the + other is assumed to be one of the default values of 0 or +infini + as shown in parentheses below. + + Field 1 (columns 2-3) specifies the type of bound: + LO lower bound + UP upper bound + LI lower bound integer variable + UI upper bound integer variable + BV binary variable + FX fixed variable + FR free + MI lower bound - infini + PL upper bound + infini */ + +VarCourant = 0; + +while ( 1 ) { + + fgets( LigneLue , LgMax , Flot ); + if( strstr( LigneLue , "ENDATA" ) == LigneLue ) goto FinLecture; + + NbChamps = sscanf( LigneLue , "%s %s %s %s" , + TypeDeBorne , LabelDeLaBorneLue , LabelDeLaVariableLue , ValeurLue ); + if ( NbChamps <= 0 ) continue; + + CoefficientMps = atof( ValeurLue ); + /*CoefficientMpsB = atof( ValeurLueB );*/ + + PNE_RechercheDuNumeroDeVariableMPS( /*VarCourant, BaseVar,*/ &i, LabelDeLaVariableLue ); + + if ( i < 0 ) { + /* Creation d'une variable avec un cout nul */ + i = Mps.NbVar; + printf("Creation de la variable num %d\n",i); + Mps.NbVar++; + Mps.LabelDeLaVariable = (char **) realloc( Mps.LabelDeLaVariable , Mps.NbVar * sizeof( void * ) ); + Mps.TypeDeVariable = (int *) realloc( Mps.TypeDeVariable , Mps.NbVar * sizeof( int ) ); + Mps.TypeDeBorneDeLaVariable = (int *) realloc( Mps.TypeDeBorneDeLaVariable, Mps.NbVar * sizeof( int ) ); + Mps.U = (double *) realloc( Mps.U , Mps.NbVar * sizeof( double ) ); + Mps.L = (double *) realloc( Mps.L , Mps.NbVar * sizeof( double ) ); + Mps.Umin = (double *) realloc( Mps.Umin , Mps.NbVar * sizeof( double ) ); + Mps.Umax = (double *) realloc( Mps.Umax , Mps.NbVar * sizeof( double ) ); + if ( Mps.LabelDeLaVariable == NULL || Mps.TypeDeVariable == NULL || Mps.TypeDeBorneDeLaVariable == NULL || + Mps.U == NULL || Mps.L == NULL || Mps.Umin == NULL || + Mps.Umax == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_LireJeuDeDonneesMPS \n"); + exit(0); + } + + Mps.LabelDeLaVariable[i] = (char *) malloc( strlen( LabelDeLaVariableLue ) + 1 ); + strcpy( Mps.LabelDeLaVariable[i] , LabelDeLaVariableLue ); + + Mps.L[i] = 0.; + /* Initialisations par defaut */ + Mps.Umin [i] = 0.; + Mps.Umax [i] = PlusLinfiniBis; + Mps.TypeDeVariable[i] = REEL; + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_INFERIEUREMENT; + /* Pas de hashcode pour la variable */ + + } + + if ( strcmp( TypeDeBorne , "LO" ) == 0 ) { + /* Borne inferieure */ + Mps.Umin[i] = CoefficientMps; + + if ( Mps.Umin[i] > Mps.Umax[i] ) { printf("Erreur de donnees \n"); exit(0); } + + if ( Mps.TypeDeVariable[i] != ENTIER ) { /* Si le type n'est pas deja defini par INTORG */ + Mps.TypeDeVariable[i] = REEL; + } + if ( Mps.TypeDeBorneDeLaVariable[i] == NON_DEFINI ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_NON_BORNEE ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + /* C'est une redefinition de la borne */ + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + /* C'est une redefinition de la borne */ + } + else { + printf("Lecture des donnees, impossible d'affecter un type de borne a la variable %d TypeDeBorne %s Type existant %d\n" + ,i,TypeDeBorne,Mps.TypeDeBorneDeLaVariable[i]); + exit(0); + } + continue; + } + if ( strcmp( TypeDeBorne , "UP" ) == 0 ) { + Mps.Umax[i] = CoefficientMps; + if ( Mps.TypeDeVariable[i] != ENTIER ) { /* Si le type n'est pas deja defini par INTORG */ + Mps.TypeDeVariable[i] = REEL; + } + if ( Mps.TypeDeBorneDeLaVariable[i] == NON_DEFINI ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_SUPERIEUREMENT; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_NON_BORNEE ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_SUPERIEUREMENT; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + /* C'est une redefinition de la borne */ + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + /* C'est une redefinition de la borne */ + } + else { + printf("Lecture des donnees, impossible d'affecter un type de borne a la variable %d TypeDeBorne %s TypeCourant %d\n", + i,TypeDeBorne,Mps.TypeDeBorneDeLaVariable[i]); + exit(0); + } + continue; + } + if ( strcmp( TypeDeBorne , "MI" ) == 0 ) { + if ( Mps.TypeDeVariable[i] != ENTIER ) { /* Si le type n'est pas deja defini par INTORG */ + Mps.Umin [i] = -PlusLinfiniBis; + Mps.Umax [i] = 0.; + Mps.U [i] = 0.; + Mps.TypeDeVariable [i] = REEL; + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_SUPERIEUREMENT; + continue; + } + else { + printf(" L'optimisation avec des variables entieres comprises entre 0 et - l'infini n'est pas implémentée\n"); + exit(0); + } + } + if ( strcmp( TypeDeBorne , "FR" ) == 0 ) { + Mps.Umin [i] = -PlusLinfiniBis; + Mps.Umax [i] = PlusLinfiniBis; + Mps.TypeDeVariable [i] = REEL; + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_NON_BORNEE; + continue; + } + if ( strcmp( TypeDeBorne , "LI" ) == 0 ) { + Mps.Umin [i] = CoefficientMps; + Mps.TypeDeVariable[i] = ENTIER; + if ( Mps.TypeDeBorneDeLaVariable[i] == NON_DEFINI ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_NON_BORNEE ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + /* C'est une redefinition de la borne */ + } + else { + printf("Lecture des donnees, impossible d'affecter un type de borne a la variable %d TypeDeBorne %s\n",i,TypeDeBorne); + exit(0); + } + continue; + } + if ( strcmp( TypeDeBorne , "UI" ) == 0 ) { + Mps.Umax [i] = CoefficientMps; + Mps.TypeDeVariable[i] = ENTIER; + if ( Mps.TypeDeBorneDeLaVariable[i] == NON_DEFINI ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_SUPERIEUREMENT; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_NON_BORNEE ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_SUPERIEUREMENT; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + /* C'est une redefinition de la borne */ + } + else { + printf("Lecture des donnees, impossible d'affecter un type de borne a la variable %d TypeDeBorne %s\n",i,TypeDeBorne); + exit(0); + } + continue; + } + if ( strcmp( TypeDeBorne , "BV" ) == 0 ) { + Mps.Umin [i] = 0.; + Mps.Umax [i] = 1.; + Mps.TypeDeVariable [i] = ENTIER; + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_DES_DEUX_COTES; + continue; + } + if ( strcmp( TypeDeBorne , "SC" ) == 0 ) { + Mps.Umin [i] = 0.; + Mps.Umax [i] = 1.; + Mps.TypeDeVariable [i] = ENTIER; + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_DES_DEUX_COTES; + continue; + } + if ( strcmp( TypeDeBorne , "FX" ) == 0 ) { + Mps.Umin [i] = CoefficientMps; + Mps.Umax [i] = CoefficientMps; + Mps.U [i] = CoefficientMps; + Mps.TypeDeVariable [i] = REEL; + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_FIXE; + continue; + } + if ( strcmp( TypeDeBorne , "PL" ) == 0 ) { + /* Borne sup infinie => rien a faire */ + continue; + } + printf(" Code borne inconnu %s\n",TypeDeBorne); exit(0); + +} + +/* +printf("Fin de lecture de BOUNDS \n"); fflush(stdout); +*/ + +FinLecture: + +for ( i = 0 ; i < Mps.NbVar ; i++ ) { + if ( Mps.TypeDeVariable[i] == ENTIER ) { + if ( fabs( Mps.Umax[i] - Mps.Umin[i] ) < PlusLinfiniBis ) { + Mps.TypeDeBorneDeLaVariable[i] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + } +} + +/* On enleve les contraintes de type Free */ +/* Algorithme naif ou l'on espere qu'il n'y a pas beaucoup de contraintes Free */ +for ( i = 0 ; i < Mps.NbCnt ; i++ ) { + if ( Mps.SensDeLaContrainte[i] == 'N' ) { + /* Contrainte libre: on peut suprimer */ + for ( j = i ; j < Mps.NbCnt-1 ; j++ ) { + Mps.Mdeb[j] = Mps.Mdeb[j+1]; + Mps.NbTerm[j] = Mps.NbTerm[j+1]; + Mps.SensDeLaContrainte[j] = Mps.SensDeLaContrainte[j+1]; + Mps.B[j] = Mps.B[j+1]; + Mps.BRange[j] = Mps.BRange[j+1]; + Mps.LabelDeLaContrainte[j] = Mps.LabelDeLaContrainte[j+1]; + } + Mps.NbCnt--; + i--; + } +} + +/* Classer les contraintes */ +/* printf("Classement des contraintes\n"); */ + +A = (double *) malloc( CountTrm * sizeof( double ) ); +Nuvar = (int *) malloc( CountTrm * sizeof( int ) ); +Mdeb = (int *) malloc( Mps.NbCnt * sizeof( int ) ); +NbTerm = (int *) malloc( Mps.NbCnt * sizeof( int ) ); +if ( A == NULL || Nuvar == NULL || Mdeb == NULL || NbTerm == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_LireJeuDeDonneesMPS \n"); + exit(0); +} + +il = -1; +for ( i = 0 ; i < Mps.NbCnt ; i++ ) { + Mdeb [i] = il + 1; + NbTerm[i] = Mps.NbTerm[i]; + ilMps = Mps.Mdeb[i]; + while ( ilMps >= 0 ) { + il++; + A [il] = Mps.A [ilMps]; + Nuvar[il] = Mps.Nuvar[ilMps]; + ilMps = Mps.Msui[ilMps]; + } +} + +memcpy( (char *) Mps.A , (char *) A , CountTrm * sizeof( double ) ); +memcpy( (char *) Mps.Nuvar , (char *) Nuvar , CountTrm * sizeof( int ) ); +memcpy( (char *) Mps.Mdeb , (char *) Mdeb , Mps.NbCnt * sizeof( int ) ); +memcpy( (char *) Mps.NbTerm , (char *) NbTerm , Mps.NbCnt * sizeof( int ) ); + +free( A ); free( Nuvar ) ; free( Mdeb ) ; free( NbTerm ); + +/* Classement des variables dans les contraintes */ +PNE_ClasserVariablesDansContraintesMPS(); + +/* Ajustement des couts pour tenir compte du sens de l'optimisation */ + +if ( SensOpt == 1.0 ) printf("Minimization\n"); +else if ( SensOpt == -1.0 ) printf("Maximization\n"); +else { + printf("Sens de l'optimisation Minimisation ou Maximisation non defini\n"); + exit(0); +} + +for ( i = 0 ; i < Mps.NbVar ; i++ ) { + Mps.L[i] *= SensOpt; +} + +printf("Reading MPS file -> rows: %d columns: %d \n",Mps.NbCnt,Mps.NbVar); + +free( LigneLue ); +free( LabelDeLaContrainteLue ); +free( LabelDeLaVariableLue ); +free( LabelDeLaContrainteLueB ); +free( LabelDuSecondMembreLu ); +free( LabelDeLaBorneLue ); +free( LabelDeLaVariablePrecedente ); +free( ValeurLue ); +free( ValeurLueB ); +free( ValeurLueC ); + +/* On libere le flot et le buffer */ +fclose( Flot ); + +free( Mps.FirstNomCnt ); +free( Mps.NomCntSuivant ); +free( Mps.FirstNomVar ); +free( Mps.NomVarSuivant ); + +if ( Mps.NbCntRange > 0 ) { + printf(" Nombre de Ranges %d !!!!!\n",Mps.NbCntRange); + PNE_PrendreEnCompteLesContraintesRangeMPS(); +} + +return; + +} + +/*----------------------------------------------------------------------------*/ +/* + Pour chaque contrainte, on classe les variables dans l'ordre croissant + de leur numero +*/ + +void PNE_ClasserVariablesDansContraintesMPS() +{ +int i ; int j; int iX; int Prem; int PremSv; int Lp; int Lz; + +double * TabSv; int * Suiv; + +/* Inutile car c'est fait dans PNE Solveur */ +return; + +TabSv = (double *) malloc( Mps.NbVar * sizeof( double ) ); +Suiv = (int *) malloc( Mps.NbVar * sizeof( int ) ); +if ( TabSv == NULL || Suiv == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_LireJeuDeDonneesMPS \n"); + exit(0); +} + +for ( j = 0 ; j < Mps.NbCnt ; j++ ) { + + Prem = -1; + for ( i = Mps.Mdeb[j] ; i <= Mps.Mdeb[j] + Mps.NbTerm[j] - 1 ; i++ ) { + iX = Mps.Nuvar[i]; + TabSv[iX] = Mps.A[i]; + Lp = -1; + Lz = Prem; + while ( 1 ) { + if ( Lz < 0 || iX < Lz ) { + if ( Lp < 0 ) { + /* Premier terme */ + PremSv = Prem; + Prem = iX; + Suiv[iX] = PremSv; + break; + } + /* Lp >= 0 */ + Suiv[Lp] = iX; + Suiv[iX] = Lz; + break; + } + Lp = Lz; + Lz = Suiv[Lz]; + } + } + + /* Reclassement dans l ordre */ + i = Mps.Mdeb[j]; + Lz = Prem; + while ( Lz >= 0 ) { + Mps.Nuvar[i] = Lz; + Mps.A [i] = TabSv[Lz]; + i++; + Lz = Suiv[Lz]; + } + +} + +free( TabSv ); +free( Suiv ); + +return; +} + +/*----------------------------------------------------------------------------------------*/ + +void PNE_RechercheDuNumeroDeContrainteMPS( /*int CntCourant,*/ + /*int BaseCnt,*/ + int * CntTrouv, + char * LabelDeLaContrainteLue ) +{ +int Cnt; char * pt1; int k; + +/* Recherche de la contrainte */ + +pt1 = LabelDeLaContrainteLue; + +/* Hashcode du Nom */ +k = PNE_HashCode( pt1 , Mps.NentreesCnt ); + +Cnt = Mps.FirstNomCnt[k]; +while ( Cnt >= 0 ) { + if ( strcmp( Mps.LabelDeLaContrainte[Cnt] , LabelDeLaContrainteLue ) == 0 ) { + *CntTrouv = Cnt; + return; + } + Cnt = Mps.NomCntSuivant[Cnt]; +} + +printf(" Contrainte inconnue -%s- HashCode %d \n",LabelDeLaContrainteLue,k); +exit(0); + +return; +} + +/*----------------------------------------------------------------------------------------*/ + +void PNE_RechercheDuNumeroDeVariableMPS( /*int VarCourant, + int BaseVar,*/ + int * VarTrouv, + char * LabelDeLaVariableLue ) +{ +int Var; char * pt1; int k; + +/* Recherche de la variable */ + +pt1 = LabelDeLaVariableLue; + +/* Hashcode du Nom */ +k = PNE_HashCode( pt1 , Mps.NentreesVar ); + +Var = Mps.FirstNomVar[k]; +while ( Var >= 0 ) { + if ( strcmp( Mps.LabelDeLaVariable[Var] , LabelDeLaVariableLue ) == 0 ) { + *VarTrouv = Var; + return; + } + Var = Mps.NomVarSuivant[Var]; +} + + printf(" Variable inconnue %s , on la cree avec un cout nul\n",LabelDeLaVariableLue); +*VarTrouv = -1; + +return; +} + +/*----------------------------------------------------------------------------------------*/ + +void PNE_CreerHashCodeContrainteMPS( /*int * BaseCnt*/ ) +{ +int Cnt; int Prem; char * pt1; int k; + +#if VERBOSE_PNE + printf("Debut creation haschcode cnt\n"); fflush(stdout); +#endif + +Mps.NentreesCnt = (int) pow( 2 , 20 ); + +Mps.FirstNomCnt = (int *) malloc( Mps.NentreesCnt * sizeof( int ) ); +Mps.NomCntSuivant = (int *) malloc( Mps.NbCnt * sizeof( int ) ); +if ( Mps.FirstNomCnt == NULL || Mps.NomCntSuivant == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_CreerHashCodeContrainteMPS \n"); + exit(0); +} + +for ( k = 0 ; k < Mps.NentreesCnt ; k++ ) Mps.FirstNomCnt[k] = -1; + +for ( Cnt = 0 ; Cnt < Mps.NbCnt ; Cnt++ ) { + pt1 = Mps.LabelDeLaContrainte[Cnt]; + /* Hashcode du Nom */ + k = PNE_HashCode( pt1 , Mps.NentreesCnt ); + + Prem = Mps.FirstNomCnt[k]; + Mps.FirstNomCnt [k] = Cnt; + Mps.NomCntSuivant[Cnt] = Prem; +} + +#if VERBOSE_PNE + printf("Fin creation haschcode cnt\n"); fflush(stdout); +#endif + +return; +} + +/*----------------------------------------------------------------------------------------*/ + +void PNE_CreerHashCodeVariableMPS( /*int * BaseVar*/ ) +{ +int Var; int Prem; char * pt1; int k; + +#if VERBOSE_PNE + printf("Debut creation haschcode var\n"); fflush(stdout); +#endif + +/* +Mps.NentreesVar = (int) ( 5 * Mps.NbVar ) + 1; +*/ +Mps.NentreesVar = (int) pow( 2 , 20 ); + +Mps.FirstNomVar = (int *) malloc( Mps.NentreesVar * sizeof( int ) ); +Mps.NomVarSuivant = (int *) malloc( Mps.NbVar * sizeof( int ) ); +if ( Mps.FirstNomVar == NULL || Mps.NomVarSuivant == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_CreerHashCodeVariableMPS \n"); + exit(0); +} + +for ( k = 0 ; k < Mps.NentreesVar ; k++ ) Mps.FirstNomVar[k] = -1; + +for ( Var = 0 ; Var < Mps.NbVar ; Var++ ) { + pt1 = Mps.LabelDeLaVariable[Var]; + /* Hashcode du Nom */ + k = PNE_HashCode( pt1 , Mps.NentreesVar ); + + Prem = Mps.FirstNomVar[k]; + Mps.FirstNomVar [k] = Var; + Mps.NomVarSuivant[Var] = Prem; +} + +#if VERBOSE_PNE + printf("Fin creation haschcode var\n"); fflush(stdout); +#endif + +return; +} + +/*----------------------------------------------------------------------------------------*/ + +int PNE_HashCode( char * pt1 , int Nentrees ) +{ +int Int; char Car; int k; + +/* Hashcode du Nom */ +k = kHashCode; +while ( sscanf( pt1 , "%c", &Car ) > 0 ) { + Int = (int) Car; + pt1++; + k = ( k * aHashCode + Int ) % Nentrees; +} +return( k ); + +} + +/***************************************************************************/ + +void PNE_PrendreEnCompteLesContraintesRangeMPS() +{ +int Cnt; int NewNbCnt; int NbTermesEnPlus; int NewNbTermes; int NbVarNew; +int CntCourant; int il; int ilMax; int ilCourant; double Uinf; double Usup; +int * Mdeb_New; int * NbTerm_New; int * Nuvar_New; double * A_New; +char MethodeAvecVariableSupplementaire; + +MethodeAvecVariableSupplementaire = OUI_MPS; + +if ( MethodeAvecVariableSupplementaire == OUI_MPS ) goto METHODE_AVEC_VARIABLE_SUPPLEMENTAIRE; + +NewNbCnt = Mps.NbCnt + Mps.NbCntRange; + +/* On compte le nombre de termes supplementaires a mettre dans la matrice des contraintes */ +NbTermesEnPlus = 0; +for ( Cnt = 0 ; Cnt < Mps.NbCnt ; Cnt++ ) { + if ( Mps.BRange[Cnt] != 0.0 ) NbTermesEnPlus+= Mps.NbTerm[Cnt]; +} + +NewNbTermes = Mps.Mdeb[Mps.NbCnt - 1] + Mps.NbTerm[Mps.NbCnt - 1] + NbTermesEnPlus; + +/* Reallocations */ +Mps.Mdeb = (int *) realloc( Mps.Mdeb, NewNbCnt * sizeof( int ) ); +Mps.NbTerm = (int *) realloc( Mps.NbTerm, NewNbCnt * sizeof( int ) ); +Mps.B = (double *) realloc( Mps.B , NewNbCnt * sizeof( double ) ); +Mps.SensDeLaContrainte = (char *) realloc( Mps.SensDeLaContrainte, NewNbCnt * sizeof( char ) ); + +Mps.VariablesDualesDesContraintes = (double *) realloc( Mps.VariablesDualesDesContraintes, NewNbCnt * sizeof( double ) ); +Mps.LabelDeLaContrainte = (char **) realloc( Mps.LabelDeLaContrainte , NewNbCnt * sizeof( void * ) ); + +if ( Mps.Mdeb == NULL || Mps.NbTerm == NULL || + Mps.B == NULL || Mps.SensDeLaContrainte == NULL || + Mps.VariablesDualesDesContraintes == NULL || Mps.LabelDeLaContrainte == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_PrendreEnCompteLesContraintesRangeMPS \n"); + exit(0); +} + +Mps.A = (double *) realloc( Mps.A , NewNbTermes * sizeof( double ) ); +Mps.Nuvar = (int *) realloc( Mps.Nuvar, NewNbTermes * sizeof( int ) ); + +CntCourant = Mps.NbCnt; +ilCourant = Mps.Mdeb[Mps.NbCnt - 1] + Mps.NbTerm[Mps.NbCnt - 1]; +for ( Cnt = 0 ; Cnt < Mps.NbCnt ; Cnt++ ) { + if ( Mps.BRange[Cnt] == 0.0 ) continue; + il = Mps.Mdeb[Cnt]; + ilMax = il + Mps.NbTerm[Cnt]; + Mps.Mdeb[CntCourant] = ilCourant; + while ( il < ilMax ) { + Mps.A[ilCourant] = Mps.A[il]; + Mps.Nuvar[ilCourant] = Mps.Nuvar[il]; + ilCourant++; + il++; + } + Mps.NbTerm[CntCourant] = ilCourant - Mps.Mdeb[CntCourant]; + if ( Mps.SensDeLaContrainte[Cnt] == '<' ) { + Mps.B[CntCourant] = Mps.B[Cnt] - fabs( Mps.BRange[Cnt] ); + Mps.SensDeLaContrainte[CntCourant] = '>'; + } + else if ( Mps.SensDeLaContrainte[Cnt] == '>' ) { + Mps.B[CntCourant] = Mps.B[Cnt] + fabs( Mps.BRange[Cnt] ); + Mps.SensDeLaContrainte[CntCourant] = '<'; + } + else { + if ( Mps.BRange[Cnt] > 0.0 ) { + Mps.SensDeLaContrainte[Cnt] = '>'; + Mps.B[CntCourant] = Mps.B[Cnt] + fabs( Mps.BRange[Cnt] ); + Mps.SensDeLaContrainte[CntCourant] = '<'; + } + else { + Mps.SensDeLaContrainte[Cnt] = '<'; + Mps.B[CntCourant] = Mps.B[Cnt] - fabs( Mps.BRange[Cnt] ); + Mps.SensDeLaContrainte[CntCourant] = '>'; + } + } + CntCourant++; +} + +Mps.NbCnt = NewNbCnt; + +free( Mps.BRange ); + +return; + +METHODE_AVEC_VARIABLE_SUPPLEMENTAIRE: + +/* Methode 2 on cree une contrainte d'egalite avec une variable bornee */ + +NbVarNew = Mps.NbVar + Mps.NbCntRange; + +Mps.LabelDeLaVariable = (char **) realloc( Mps.LabelDeLaVariable , NbVarNew * sizeof( void * ) ); +Mps.TypeDeVariable = (int *) realloc( Mps.TypeDeVariable , NbVarNew * sizeof( int ) ); +Mps.TypeDeBorneDeLaVariable = (int *) realloc( Mps.TypeDeBorneDeLaVariable, NbVarNew * sizeof( int ) ); +Mps.U = (double *) realloc( Mps.U , NbVarNew * sizeof( double ) ); +Mps.L = (double *) realloc( Mps.L , NbVarNew * sizeof( double ) ); +Mps.Umin = (double *) realloc( Mps.Umin , NbVarNew * sizeof( double ) ); +Mps.Umax = (double *) realloc( Mps.Umax , NbVarNew * sizeof( double ) ); +if ( Mps.LabelDeLaVariable == NULL || Mps.TypeDeVariable == NULL || Mps.TypeDeBorneDeLaVariable == NULL || + Mps.U == NULL || Mps.L == NULL || Mps.Umin == NULL || + Mps.Umax == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_PrendreEnCompteLesContraintesRangeMPS \n"); + exit(0); +} + +Mdeb_New = (int *) malloc( Mps.NbCnt * sizeof( int ) ); +NbTerm_New = (int *) malloc( Mps.NbCnt * sizeof( int ) ); +if ( Mdeb_New == NULL || NbTerm_New == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_PrendreEnCompteLesContraintesRangeMPS \n"); + exit(0); +} + +NbTermesEnPlus = Mps.NbCntRange; +NewNbTermes = Mps.Mdeb[Mps.NbCnt - 1] + Mps.NbTerm[Mps.NbCnt - 1] + NbTermesEnPlus; +A_New = (double *) malloc( NewNbTermes * sizeof( double ) ); +Nuvar_New = (int *) malloc( NewNbTermes * sizeof( int ) ); +if ( A_New == NULL || Nuvar_New == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_PrendreEnCompteLesContraintesRangeMPS \n"); + exit(0); +} + +ilCourant = 0; +for ( Cnt = 0 ; Cnt < Mps.NbCnt ; Cnt++ ) { + /* On recopie la contrainte */ + il = Mps.Mdeb[Cnt]; + ilMax = il + Mps.NbTerm[Cnt]; + Mdeb_New[Cnt] = ilCourant; + NbTerm_New[Cnt] = Mps.NbTerm[Cnt]; + while ( il < ilMax ) { + A_New[ilCourant] = Mps.A[il]; + Nuvar_New[ilCourant] = Mps.Nuvar[il]; + ilCourant++; + il++; + } + if ( Mps.BRange[Cnt] == 0.0 ) continue; + /* On ajoute un terme a la contrainte */ + A_New[ilCourant] = -1.0; + Nuvar_New[ilCourant] = Mps.NbVar; + ilCourant++; + NbTerm_New[Cnt]++; + /* On transforme la contrainte en contrainte d'egalite */ + if ( Mps.SensDeLaContrainte[Cnt] == '<' ) { + Usup = Mps.B[Cnt]; + Uinf = Usup - fabs( Mps.BRange[Cnt] ); + } + else if ( Mps.SensDeLaContrainte[Cnt] == '>' ) { + Uinf = Mps.B[Cnt]; + Usup = Uinf + fabs( Mps.BRange[Cnt] ); + } + else { + if ( Mps.BRange[Cnt] > 0.0 ) { + Uinf = Mps.B[Cnt]; + Usup = Uinf + fabs( Mps.BRange[Cnt] ); + } + else { + Usup = Mps.B[Cnt]; + Uinf = Usup - fabs( Mps.BRange[Cnt] ); + } + } + Mps.B[Cnt] = 0.0; + Mps.SensDeLaContrainte[Cnt] = '='; + /* On cree la variable */ + Mps.TypeDeVariable [Mps.NbVar] = REEL; + Mps.TypeDeBorneDeLaVariable[Mps.NbVar] = VARIABLE_BORNEE_DES_DEUX_COTES; + Mps.U [Mps.NbVar] = Uinf; + Mps.L [Mps.NbVar] = 0.0; + Mps.Umin[Mps.NbVar] = Uinf; + Mps.Umax[Mps.NbVar] = Usup; + if ( Mps.NbVar > 1000000000 ) { + printf("Trop de variable a optimiser, limite 1000000000\n"); + exit(0); + } + Mps.LabelDeLaVariable[Mps.NbVar] = (char *) malloc( 12 ); + if ( Mps.LabelDeLaVariable[Mps.NbVar] == NULL ) { + printf("PNE memoire insuffisante dans le sous programme PNE_PrendreEnCompteLesContraintesRangeMPS \n"); + exit(0); + } + sprintf( Mps.LabelDeLaVariable[Mps.NbVar], "%d", Mps.NbVar); + Mps.NbVar++; +} + +free( Mps.Mdeb ); +free( Mps.NbTerm ); +free( Mps.A ); +free( Mps.Nuvar ); + +Mps.Mdeb = Mdeb_New; +Mps.NbTerm = NbTerm_New ; +Mps.A = A_New ; +Mps.Nuvar = Nuvar_New; + +free( Mps.BRange ); + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_mac.c b/src/ext/Sirius_Solver/pne/pne_mac.c new file mode 100644 index 0000000000..dba8ad1706 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_mac.c @@ -0,0 +1,133 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +#include /* Standard I/O */ +#include /* Standard Library */ +#include /* Error number and related */ + +# if defined(__linux) || defined(linux) || defined(__linux__) + +/* On ne controle que dans le cas de linux */ + +#define ENUMS +#include +#include +#include +#include /* for the glibc version number */ +#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1 +#include +#include /* the L2 protocols */ +#else +#include +#include +#include /* The L2 protocols */ +#endif +#include +#include +#include +#include +#include + +# include "pne_fonctions.h" + +# define AUCUN_CONTROLE 0 +# define RECUPERATION_ADRESSE_MAC 1 +# define CONTROLE_ADRESSE_MAC 2 + +# define MODE AUCUN_CONTROLE + +/*----------------------------------------------------------------------------*/ + +void PNE_ControleMacAdresse( void ) +{ +int i, j, nb; int sck; char * pt; +struct ifconf ifc; struct ifreq *ifr; +char buffer[1024]; char buff[256]; char AdresseMac[] = "00:25:90:E4:5A:08"; + +# if MODE == AUCUN_CONTROLE + return; +# endif + +/* On commence par enumerer les interfaces */ +sck = socket(AF_INET, SOCK_STREAM, 0); +if ( sck < 0 ) { + /* Unable to create socket */ + printf("Unable to detect authorized computer (step 1)\n"); + return; +} + +ifc.ifc_len = sizeof(buffer); +ifc.ifc_buf = buffer; +if ( ioctl(sck, SIOCGIFCONF, &ifc) < 0 ) { + /* Erreur sur ioctl(SIOCGIFCONF) */ + printf("Unable to detect authorized computer (step 2)\n"); +} + +ifr = ifc.ifc_req; +nb = ifc.ifc_len / sizeof(struct ifreq); +for ( i = 0 ; i < nb ; i++ ) { + if ( ioctl(sck, SIOCGIFHWADDR, &ifr[i]) < 0 ) { + /* ioctl(SIOCGIFHWADDR) */ + printf("Unable to detect authorized computer (step 3)\n"); + return; + } + + # if MODE == RECUPERATION_ADRESSE_MAC + printf("Adresse mac de %s: ", ifr[i].ifr_name); + # endif + pt = buff; + for ( j = 0 ; j < IFHWADDRLEN ; j++ ) { + /* printf("%02X", (unsigned int) (unsigned char) (ifr[i].ifr_hwaddr.sa_data[j])); */ + sprintf(pt,"%02X", (unsigned int) (unsigned char) (ifr[i].ifr_hwaddr.sa_data[j])); + pt += 2; + if (j != IFHWADDRLEN-1) { + /*putchar(':');*/ + *pt = ':'; + pt++; + } + } + # if MODE == RECUPERATION_ADRESSE_MAC + putchar('\n'); + printf("%s\n",buff); + # endif + # if MODE == CONTROLE_ADRESSE_MAC + if ( strcmp( AdresseMac , buff ) == 0 ) { + /*printf("Utilisation du solveur permise\n");*/ + return; + } + # endif +} +# if MODE == RECUPERATION_ADRESSE_MAC + exit(0); +# endif + +# if MODE == CONTROLE_ADRESSE_MAC + /* On n'a pas trouve l'adresse mac recherchee */ + printf("Please, contact RTE to use this solver for your own purpose\n"); + exit(0); +# endif + +return; +} + +# else + +void PNE_ControleMacAdresse( void ) +{ +return; +} + +# endif diff --git a/src/ext/Sirius_Solver/pne/pne_majorant_knapsack.c b/src/ext/Sirius_Solver/pne/pne_majorant_knapsack.c new file mode 100644 index 0000000000..7a34fbaf3b --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_majorant_knapsack.c @@ -0,0 +1,353 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul d'une borne sur le sac a dos + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_definition_arguments.h" +# include "pne_fonctions.h" +# include "pne_constantes_externes.h" +# include "pne_define.h" + +int PNE_KnapsackProgrammationDynamique( int , int * , double * , double ); + +/*------------------------------------------------------------------------*/ +/* Resolution du probleme de separation pour les couvertures de sac a dos. + On calcul le min du critere, la contrainte a respecter est du type >. + Min Sigma cj.xj s.c.: Sigma aj.xj > B0 (inegalite stricte) et xj binaire */ + +double PNE_ProgrammationDynamiqueKnapsackSeparation( int NombreDeVariables, double * C, double * A, double B0double ) +{ +int Var; int i; double Z; int B1; int AdeVar; double CdeVar; double * Bellman; int B0; +int B0max; int E1; int E2; int B; char * Commande; int EtatOpt; char * Init; + +/* Ci-dessous un probleme pour tester la programmation dynamique */ +/* +if ( NombreDeVariables >= 6 ) { + B0double = 178; + C[0] = 1.; + C[1] = 1.; + C[2] = 1./4.; + C[3] = 1./2.; + C[4] = 0; + C[5] = 1.; + + A[0] = 45; + A[1] = 46; + A[2] = 79; + A[3] = 54; + A[4] = 53; + A[5] = 125; + + NombreDeVariables = 6; +} +*/ + +EtatOpt = -1; + +B0 = (int) B0double; +/* Calcul de la valeur max du second membre */ +B0max = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + B0max += (int) A[Var]; + /*printf("C[%d] = %e A = %d (%e) B0 %d B0max %d\n",Var,C[Var],(int)A[Var],A[Var],B0,B0max);*/ +} +B1 = B0max + 1; + +i = (B0max + 1) * NombreDeVariables; +i++; +Bellman = (double *) malloc( i * sizeof( double ) ); +Init = (char *) malloc( i * sizeof( char ) ); +Commande = (char *) malloc( i * sizeof( char ) ); +for ( B = 0 ; B < i ; B++ ) Init[B] = NON_PNE; +Z = -LINFINI_PNE; + +E1 = 0; +/* Variable 0 */ +Var = 0; +AdeVar = (int) A[Var]; +CdeVar = C[Var]; +/* i est l'etat de depart, j est l'etat d'arrivee */ +for ( i = 0 ; i <= B0max ; i++ ) { + /* Variable a 1 => on change de niveau */ + /* B est le niveau atteint pour le second membre */ + B = i + AdeVar; + if ( B >= B0 && B <= B0max ) { + /* On atteint une solution realisable */ + Bellman[E1] = CdeVar; + Commande[E1] = 1; + Init[E1] = OUI_PNE; + } + /* Variable a 0 => on ne change pas de niveau */ + B = i; + if ( B >= B0 ) { + if ( Init[E1] == OUI_PNE ) { + if ( 0 < Bellman[E1] ) { + Bellman[E1] = 0; + Commande[E1] = 0; + } + } + else { + Bellman[E1] = 0; + Commande[E1] = 0; + Init[E1] = OUI_PNE; + } + } + E1++; +} +Var++; + +for ( ; Var < NombreDeVariables ; Var++ ) { + AdeVar = (int) A[Var]; + CdeVar = C[Var]; + /* i est l'etat de depart, j est l'etat d'arrivee */ + for ( i = 0 ; i <= B0max ; i++ ) { + /* normalement l'etat E1 n'est pas initialise */ + /* Variable a 1 => on change de niveau */ + B = i + AdeVar; + if ( B <= B0max ) { + E2 = E1 - B1 + AdeVar; + if ( Init[E2] == OUI_PNE ) { + Bellman[E1] = CdeVar + Bellman[E2]; + Commande[E1] = 1; + Init[E1] = OUI_PNE; + /*printf("Bellman %e B %d Var %d\n",Bellman[E1],B,Var);*/ + } + } + /* Variable a 0 => on ne change pas de niveau */ + B = i; + E2 = E1 - B1; + if ( Init[E2] == OUI_PNE ) { + if ( Init[E1] == OUI_PNE ) { + if ( Bellman[E2] < Bellman[E1] ) { + Bellman[E1] = Bellman[E2]; + Commande[E1] = 0; + } + } + else { + Bellman[E1] = Bellman[E2]; + Commande[E1] = 0; + Init[E1] = OUI_PNE; + } + } + if ( Var == NombreDeVariables - 1 ) { + if ( i == 0 ) { + if ( Init[E1] == NON_PNE ) { + printf("Bug Variable %d etat non initialise \n",E1); + exit(0); + } + Z = Bellman[E1]; + EtatOpt = E1; + break; + } + } + E1++; + } +} + +free( Bellman ); +free( Init ); +free( Commande ); + +printf(" Z %e \n",Z); + +return( Z ); +} + +/*-----------------------------------------------------------------------*/ +/* Resolution du knapsack par programmation dynamique. Remplace le calcul + des majorants employes dans le up et down lifting */ +/* Max cx s.c. ax <= b */ +int PNE_KnapsackProgrammationDynamique( int NombreDeVariables, int * C, double * A, double B0 ) +{ +int Var; int i; int Z; int B1; int AdeVar; int CdeVar; int * Bellman_T1; int * Bellman_T2; + +B1 = (int) B0 + 1; + +Bellman_T1 = (int *) malloc( B1 * sizeof( int ) ); +Bellman_T2 = (int *) malloc( B1 * sizeof( int ) ); + +memset( (char *) Bellman_T2, 0, B1 * sizeof( int ) ); +memset( (char *) Bellman_T1, 0, B1 * sizeof( int ) ); + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + AdeVar = (int) A[Var]; + CdeVar = (int) C[Var]; + for ( i = 0 ; i < B1 ; i++ ) { + /* variable a 0 */ + if ( Bellman_T2[i] > Bellman_T1[i] ) Bellman_T1[i] = Bellman_T2[i]; + /* variable a 1 */ + if ( i+AdeVar < B1 ) { + if ( CdeVar + Bellman_T2[i+AdeVar] > Bellman_T1[i] ) Bellman_T1[i] = CdeVar + Bellman_T2[i+AdeVar]; + } + } + memcpy( (char *) Bellman_T2, (char *) Bellman_T1, B1 * sizeof( int ) ); +} +Z = Bellman_T2[0]; + +free( Bellman_T1 ); +free( Bellman_T2 ); + +return( Z ); +} + +/*-----------------------------------------------------------------------*/ + +int PNE_MajorantKnapsack( int NombreDeVariables, int * C, double * A, double B0, + char LesCoeffSontEntiers ) +{ +int Var; double X; int Z; int U_Dantzig; int U0; int U1; char U0_Valide; char U1_Valide; +char SolEntiere; int sigma0_s; int sigma1_s; double Marge; double B; int s; +int U; char U_Valide; int Zdyn; +# if UTILISER_AUSSI_LA_PROGRAMMATION_DYNAMIQUE == OUI_PNE + char ProgDyn; +# endif + +Zdyn = -1; +# if UTILISER_AUSSI_LA_PROGRAMMATION_DYNAMIQUE == OUI_PNE + if ( B0 <= SEUIL_POUR_PROGRAMMATION_DYNAMIQUE ) { + ProgDyn = OUI_PNE; + if ( LesCoeffSontEntiers != OUI_PNE ) ProgDyn = NON_PNE; + if ( ProgDyn == OUI_PNE ) { + /*printf("Programmation dynamique B0 %e\n",B0);*/ + Z = PNE_KnapsackProgrammationDynamique( NombreDeVariables, C, A, B0 ); + Zdyn = Z; + /*return( Z);*/ + } + } +# endif + +Marge = 1.e-8; +SolEntiere = NON_PNE; +/* Pour eviter les warning de compilation */ +LesCoeffSontEntiers = NON_PNE; + +/* Recherche de l'element critique s */ +B = B0; +Z = 0; +X = 0.0; +s = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + B -= A[Var]; + Z += C[Var]; + if ( B < 0.0 ) { + /* On a empile la variable en trop */ + /* L'item critique est Var */ + s = Var; + B += A[s]; + Z -= C[s]; + X = B / A[s]; + if ( fabs(X) < Marge ) { + SolEntiere = OUI_PNE; + } + else if ( fabs( 1. - X ) < Marge ) { + Z += C[s]; + SolEntiere = OUI_PNE; + } + } +} +if ( SolEntiere == OUI_PNE ) { + if ( Zdyn >= 0 && /*Zdyn < Z*/ Zdyn != Z ) { + printf("SolEntiere prog dyn Zdyn %d Z %d\n",Zdyn,Z); + } + return( Z ); +} + +/* Borne de Dantzig */ +U_Dantzig = Z + (int) floor( (double) C[Var] * X ); +U0 = U_Dantzig; +U1 = U_Dantzig; +U = U_Dantzig; + +/* A ce stade, Z est la valeur de la fonction cout apres avoir empile les item jusqu'a s-1 compris */ +/* sigma0_s est l'item critique lorsqu'on fait Xs = 0 */ +U0_Valide = NON_PNE; +for ( Var = s + 1 ; Var < NombreDeVariables ; Var++ ) { + B -= A[Var]; + Z += C[Var]; + if ( B < 0.0 ) { + /* L'item critique est Var */ + sigma0_s = Var; + B += A[sigma0_s]; + Z -= C[sigma0_s]; + X = B / A[sigma0_s]; + /* Borne de Fayard et Plateau */ + U0_Valide = OUI_PNE; + if ( fabs(X) < Marge ) U0 = Z; + else if ( fabs( 1. - X ) < Marge ) U0 = Z + C[sigma0_s]; + else U0 = Z + (int) floor( C[sigma0_s] * X ); + } +} + +/* sigma1_s est l'item critique lorsqu'on fait Xs = 1 sigma0_s est forcement toujours avant s */ +B = B0 - A[s]; +Z = C[s]; +U1_Valide = NON_PNE; +if ( B > 0.0 ) { + for ( Var = 0 ; Var < s ; Var++ ) { + B -= A[Var]; + Z += C[Var]; + if ( B < 0.0 ) { + /* L'item critique est Var */ + sigma1_s = Var; + B += A[sigma1_s]; + Z -= C[sigma1_s]; + X = B / A[sigma1_s]; + /* Borne de Hudson */ + U1_Valide = OUI_PNE; + if ( fabs(X) < Marge ) U1 = Z; + else if ( fabs( 1. - X ) < Marge ) U1 = Z + C[sigma1_s]; + else U1 = Z + (int) floor( C[sigma1_s] * X ); + } + } +} + +U_Valide = NON_PNE; +if ( U0_Valide == OUI_PNE && U1_Valide == OUI_PNE ) { + U_Valide = OUI_PNE; + U = U0; + if ( U < U1 ) U = U1; +} + +Z = U_Dantzig ; +if ( U_Valide == OUI_PNE ) { + if ( U <= Z ) { + /*printf("Borne de Dantzig rejetee U %d U_Dantzig %d\n",U,U_Dantzig);*/ + Z = U; + } + /* + else { + if ( U_Valide == OUI_PNE ) printf("Borne de Dantzig pas rejetee U %d U_Dantzig %d U0_Valide %d U1_Valide %d s %d\n",U,U_Dantzig,U0_Valide,U1_Valide,s); + } + */ +} + +/* +if ( Zdyn >= 0 && Zdyn != Z ) { + printf(" prog dyn Zdyn %d Z %d\n",Zdyn,Z); +} +*/ + +return( Z ); + +} diff --git a/src/ext/Sirius_Solver/pne/pne_memoire.h b/src/ext/Sirius_Solver/pne/pne_memoire.h new file mode 100644 index 0000000000..bfd47be2da --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_memoire.h @@ -0,0 +1,34 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef PNE_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# include "mem_fonctions.h" +/***************************************************************** + + + Macros pour redefinir les primitives de gestion memoire lorsqu'on + ne veut pas utiliser celles de lib de l'OS + + +*****************************************************************/ + +# define malloc(Taille) MEM_Malloc(Pne->Tas,Taille) +# define free(Pointeur) MEM_Free(Pointeur) +# define realloc(Pointeur,Taille) MEM_Realloc(Pne->Tas,Pointeur,Taille) + +/*****************************************************************/ +# define PNE_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# endif diff --git a/src/ext/Sirius_Solver/pne/pne_mise_a_jour_seuil_coupes.c b/src/ext/Sirius_Solver/pne/pne_mise_a_jour_seuil_coupes.c new file mode 100644 index 0000000000..a6fa6dc0ff --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_mise_a_jour_seuil_coupes.c @@ -0,0 +1,159 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Mise a jour du seuil utilise pour les coupes. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_MiseAJourSeuilCoupes( PROBLEME_PNE * Pne, char TypeDeCoupe, double * Seuil ) +{ +BB * Bb; char ProblemeUniquementEnVariablesEntieres; + +Bb = (BB *) Pne->ProblemeBbDuSolveur; +ProblemeUniquementEnVariablesEntieres = NON_PNE; +if ( Pne->NombreDeVariablesEntieresTrav == Pne->NombreDeVariablesNonFixes ) ProblemeUniquementEnVariablesEntieres = OUI_PNE; + +if ( TypeDeCoupe == COUPE_KNAPSACK ) { + if ( ProblemeUniquementEnVariablesEntieres == OUI_PNE ) *Seuil = 0.1 * SEUIL_VIOLATION_KNAPSACK; + else { + /* Si pb mixte */ + if ( Bb->AverageK == NON_INITIALISE ) *Seuil = SEUIL_VIOLATION_KNAPSACK; + else { + if ( Bb->AverageK > 0.25 * Bb->AverageG && Bb->NoeudEnExamen != Bb->NoeudRacine ) *Seuil = Pne->SeuilDeViolationK; + else *Seuil = SEUIL_VIOLATION_KNAPSACK; + } + } +} +else if ( TypeDeCoupe == COUPE_MIR_MARCHAND_WOLSEY ) { + if ( Bb->AverageK == NON_INITIALISE ) *Seuil = SEUIL_VIOLATION_MIR_MARCHAND_WOLSEY; + else { + if ( Bb->AverageK > 0.25 * Bb->AverageG ) *Seuil = Pne->SeuilDeViolationMIR_MARCHAND_WOLSEY; + else *Seuil = SEUIL_VIOLATION_MIR_MARCHAND_WOLSEY; + } +} +else if ( TypeDeCoupe == COUPE_CLIQUE ) { + if ( ProblemeUniquementEnVariablesEntieres == OUI_PNE ) *Seuil = 0.1 * SEUIL_VIOLATION_CLIQUES; + else { + /* Si pb mixte */ + if ( Bb->AverageK == NON_INITIALISE ) *Seuil = SEUIL_VIOLATION_CLIQUES; + else { + if ( Bb->AverageK > 0.25 * Bb->AverageG && Bb->NoeudEnExamen != Bb->NoeudRacine ) *Seuil = Pne->SeuilDeViolationCliques; + else *Seuil = SEUIL_VIOLATION_CLIQUES; + } + } +} +else if ( TypeDeCoupe == COUPE_IMPLICATION ) { + if ( ProblemeUniquementEnVariablesEntieres == OUI_PNE ) *Seuil = 0.1 * SEUIL_VIOLATION_IMPLICATIONS; + else { + /* Si pb mixte */ + if ( Bb->AverageK == NON_INITIALISE ) *Seuil = SEUIL_VIOLATION_IMPLICATIONS; + else { + if ( Bb->AverageK > 0.25 * Bb->AverageG && Bb->NoeudEnExamen != Bb->NoeudRacine ) *Seuil = Pne->SeuilDeViolationImplications; + else *Seuil = SEUIL_VIOLATION_IMPLICATIONS; + } + } +} +else if ( TypeDeCoupe == COUPE_DE_BORNE_VARIABLE ) { + if ( ProblemeUniquementEnVariablesEntieres == OUI_PNE ) *Seuil = 0.1 * SEUIL_VIOLATION_BORNES_VARIABLES; + else { + /* Si pb mixte */ + if ( Bb->AverageK == NON_INITIALISE ) *Seuil = SEUIL_VIOLATION_BORNES_VARIABLES; + else { + if ( Bb->AverageK > 0.25 * Bb->AverageG && Bb->NoeudEnExamen != Bb->NoeudRacine ) *Seuil = Pne->SeuilDeViolationBornesVariables; + else *Seuil = SEUIL_VIOLATION_BORNES_VARIABLES; + } + } +} +else { + printf("PNE_MiseAJourSeuilCoupes bug: TypeDeCoupe %d inconnu\n",TypeDeCoupe); + exit(0); +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_MiseAJourDesSeuilDeSelectionDesCoupes( PROBLEME_PNE * Pne ) +{ +BB * Bb; char ProblemeUniquementEnVariablesEntieres; double CoeffMin; double CoeffMax; + +/* Seuil pour les Knapsack afin d'eviter d'en avoir trop */ +Bb = Pne->ProblemeBbDuSolveur; +ProblemeUniquementEnVariablesEntieres = NON_PNE; +if ( Pne->NombreDeVariablesEntieresTrav == Pne->NombreDeVariablesNonFixes ) ProblemeUniquementEnVariablesEntieres = OUI_PNE; + +if ( Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes > 0 ) { + Bb->AverageG = (int) ceil(Bb->NombreTotalDeGDuPoolUtilisees/Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes); + Bb->AverageK = (int) ceil(Bb->NombreTotalDeKDuPoolUtilisees/Bb->NombreDeProblemesResolusDepuisLaRAZDesCoupes); +} + +if ( Bb->AverageK != NON_INITIALISE ) { + if ( Bb->AverageK > 0.25 * Bb->AverageG ) { + if ( Pne->NombreDeK > 0 ) Pne->SeuilDeViolationK = Pne->SommeViolationsK / Pne->NombreDeK; + if ( Pne->NombreDeMIR_MARCHAND_WOLSEY > 0 ) Pne->SeuilDeViolationMIR_MARCHAND_WOLSEY = Pne->SommeViolationsMIR_MARCHAND_WOLSEY / Pne->NombreDeMIR_MARCHAND_WOLSEY; + if ( Pne->NombreDeCliques > 0 ) Pne->SeuilDeViolationCliques = Pne->SommeViolationsCliques / Pne->NombreDeCliques; + if ( Pne->NombreDImplications > 0 ) Pne->SeuilDeViolationImplications = Pne->SommeViolationsImplications / Pne->NombreDImplications; + if ( Pne->NombreDeBornesVariables > 0 ) Pne->SeuilDeViolationBornesVariables = Pne->SommeViolationsBornesVariables / Pne->NombreDeBornesVariables; + } +} + +CoeffMin = 1.e-2; +CoeffMax = 1.e+2; +if ( Pne->SeuilDeViolationK > CoeffMax * SEUIL_VIOLATION_KNAPSACK ) Pne->SeuilDeViolationK = CoeffMax * SEUIL_VIOLATION_KNAPSACK; +else if( Pne->SeuilDeViolationK < CoeffMin * SEUIL_VIOLATION_KNAPSACK ) Pne->SeuilDeViolationK = CoeffMin * SEUIL_VIOLATION_KNAPSACK; + +if ( Pne->SeuilDeViolationMIR_MARCHAND_WOLSEY > CoeffMax * SEUIL_VIOLATION_MIR_MARCHAND_WOLSEY ) Pne->SeuilDeViolationMIR_MARCHAND_WOLSEY = CoeffMax * SEUIL_VIOLATION_MIR_MARCHAND_WOLSEY; +else if ( Pne->SeuilDeViolationMIR_MARCHAND_WOLSEY < CoeffMin * SEUIL_VIOLATION_MIR_MARCHAND_WOLSEY ) Pne->SeuilDeViolationMIR_MARCHAND_WOLSEY = CoeffMin * SEUIL_VIOLATION_MIR_MARCHAND_WOLSEY; + +if ( Pne->SeuilDeViolationCliques > CoeffMax * SEUIL_VIOLATION_CLIQUES ) Pne->SeuilDeViolationCliques = CoeffMax * SEUIL_VIOLATION_CLIQUES; +else if ( Pne->SeuilDeViolationCliques < CoeffMin * SEUIL_VIOLATION_CLIQUES ) Pne->SeuilDeViolationCliques = CoeffMin * SEUIL_VIOLATION_CLIQUES; + +if ( Pne->SeuilDeViolationImplications > CoeffMax * SEUIL_VIOLATION_IMPLICATIONS ) Pne->SeuilDeViolationImplications = CoeffMax * SEUIL_VIOLATION_IMPLICATIONS; +else if ( Pne->SeuilDeViolationImplications < CoeffMin * SEUIL_VIOLATION_IMPLICATIONS ) Pne->SeuilDeViolationImplications = CoeffMin * SEUIL_VIOLATION_IMPLICATIONS; + +if ( Pne->SeuilDeViolationBornesVariables > CoeffMax * SEUIL_VIOLATION_BORNES_VARIABLES ) Pne->SeuilDeViolationBornesVariables = CoeffMax * SEUIL_VIOLATION_BORNES_VARIABLES; +else if ( Pne->SeuilDeViolationBornesVariables < CoeffMin * SEUIL_VIOLATION_BORNES_VARIABLES ) Pne->SeuilDeViolationBornesVariables = CoeffMin * SEUIL_VIOLATION_BORNES_VARIABLES; + +/* +printf("SeuilDeViolationK %e SeuilDeViolationMIR_MARCHAND_WOLSEY %e SeuilDeViolationCliques %e SeuilDeViolationImplications %e SeuilDeViolationBornesVariables %e\n", + Pne->SeuilDeViolationK,Pne->SeuilDeViolationMIR_MARCHAND_WOLSEY,Pne->SeuilDeViolationCliques, + Pne->SeuilDeViolationImplications,Pne->SeuilDeViolationBornesVariables); +*/ + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_node_dm_A.c b/src/ext/Sirius_Solver/pne/pne_node_dm_A.c new file mode 100644 index 0000000000..6a690eb5d3 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_node_dm_A.c @@ -0,0 +1,510 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Mise sous forme coarse (Dumalge Mendelson) de la matrice + des contraintes + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if DUMALGE_MENDELSON_PNE == OUI_PNE + +# include "btf.h" +# include "btf_internal.h" + +# include "cs.h" + + +# define UMIN_EGAL_UMAX 10 +# define PROFONDEUR_MIN_POUR_NODE_PRESOLVE 10 +# define CYCLE_NODE_PRESOLVE 1 +# define MX_CYCLES 5 +# define MARGE 1.e-6 +# define MARGE_POUR_ARRONDI 1.e-4 +# define MARGE_POUR_VARIABLE_CONTINUE 1.e-2 +# define ZERO 1.e-7 + + +# define LIGNE 1 +# define COLONNE 2 + +/*----------------------------------------------------------------------------*/ + +void PNE_NodeDumalgeMendelsonMatriceDesContraintes( PROBLEME_PNE * Pne, + double * ValeurDeBorneInf, + double * ValeurDeBorneSup, + char * BorneInfConnue, + char * BorneSupConnue, + char * UneVariableAEteFixee, + int * Faisabilite ) +{ +int Var; int il; int ilMax; int ilAi; int ic; int i; int j; char Flag; char Resolu; +int * VarOldVarNew; int * VarNewVarOld; +int NbIneg; +int Cb; int C1; int C2; int C3; int IndexRR; int IndexCC; +int R1; int R2; int R3; int Rb; +int * Ligne; int * Colonne; int NbCntDuProblemeReduit; int NbVarDuProblemeReduit; +int ContrainteDepart; int ContrainteMx; + +int NbCntSupprimees; int NombreDeContraintesTrav; int NombreDeVariablesTrav; +char * CntSupprimee; +int * LigneIndeterminee; int NombreDeLignesIndeterminees; + +MATRICE * MatriceFactorisee; int NbVar0; int ccDeb; int ccFin; int rrDeb; int rrFin; +void * MatriceAFactoriser; +int NbCnt; int NbVar; int Cnt; double * B; int Cnt1; +int il1; int il1Max; char * LaContrainteEstBornante; +cs * A; double * Scatter; double Norme; double Norme1; double Pscal; double Cos; + +int * MdebTrav; int * NbTermTrav; int * NuvarTrav; double * ATrav; char * SensContrainteTrav; int * CdebTrav; int * CsuiTrav; int * NumContrainteTrav; +int * CntOldCntNew; char * ContrainteInactive; int * TypeDeBorneTrav; +int * CntNewCntOld; csd * Csd; csi seed; double S; char CodeRet; char FactorisationOK; char MatriceSinguliere; char Choix; + +printf("PNE_NodeDumalgeMendelsonMatriceDesContraintes \n"); + +NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; +NombreDeContraintesTrav = Pne->NombreDeContraintesTrav; + +TypeDeBorneTrav = Pne->TypeDeBorneTrav; + +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; +ATrav = Pne->ATrav; +CdebTrav = Pne->CdebTrav; +CsuiTrav = Pne->CsuiTrav; +NumContrainteTrav = Pne->NumContrainteTrav; +SensContrainteTrav = Pne->SensContrainteTrav; + +CntSupprimee = (char *) malloc( NombreDeContraintesTrav * sizeof( char ) ); +memset( (char *) CntSupprimee, 0, NombreDeContraintesTrav * sizeof( char ) ); + +i = Pne->NombreDeContraintesTrav; + +B = (double *) malloc( i * sizeof( double ) ); +A = (cs *) malloc( sizeof( cs ) ); + +/* Decompte du nombre de variables: on enleve les colonnes sans terme */ + +CntOldCntNew = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); +CntNewCntOld = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); + +Debut: + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) CntOldCntNew[Cnt] = -1; + +/* Decompte du nombre max de termes de la matrice */ +A->nzmax = 0; +NbCnt = 0; +NbIneg = 0; + +ContrainteDepart = 0; +if ( ContrainteDepart >= Pne->NombreDeContraintesTrav ) ContrainteDepart = 0; +ContrainteMx = Pne->NombreDeContraintesTrav; + +for ( Cnt = 0 ; Cnt < ContrainteMx ; Cnt++ ) { + + S = Pne->BTrav[Cnt]; + B[Cnt] = S; + Flag = 0; + if ( CntSupprimee[Cnt] == 1 ) goto DECOMPTE_CNT; + + /* Toutes les contraintes d'inegalite ont ete mises sous forme < */ + if ( SensContrainteTrav[Cnt] == '<' ) NbIneg++; + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + if ( ATrav[il] != 0.0 ) { + Var = NuvarTrav[il]; + if ( BorneInfConnue[Var] != UMIN_EGAL_UMAX ) { + A->nzmax++; + Flag = 1; + } + else { + S -= ATrav[il] * Pne->UTrav[Var]; + } + } + il++; + } + DECOMPTE_CNT: + if ( Flag == 1 ) { + CntOldCntNew[Cnt] = NbCnt; + CntNewCntOld[NbCnt] = Cnt; + B[Cnt] = S; + NbCnt++; + } +} + +printf("NbCnt %d sur %d\n",NbCnt,Pne->NombreDeContraintesTrav); + +A->nzmax += NbIneg; + +NbVar = NbIneg; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( BorneInfConnue[Var] != UMIN_EGAL_UMAX ) NbVar++; +} + +VarOldVarNew = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +VarNewVarOld = (int *) malloc( NbVar * sizeof( int ) ); +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) VarOldVarNew[Var] = -1; + +printf("A->nzmax %d\n",(int) A->nzmax); + +A->p = (csi *) malloc( ( NbVar + 1 ) * sizeof( csi ) ); +A->i = (csi *) malloc( A->nzmax * sizeof( csi ) ); +A->x = (double *) malloc( A->nzmax * sizeof( double ) ); +A->nz = -1; /* compressed-col */ + +/* Il faut recompter les variables et les contraintes */ +NbVar = 0; +ilAi = 0; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( BorneInfConnue[Var] == UMIN_EGAL_UMAX ) continue; + Flag = 0; + A->p[NbVar] = ilAi; + ic = CdebTrav[Var]; + while ( ic >= 0 ) { + i = CntOldCntNew[NumContrainteTrav[ic]]; + if ( ATrav[ic] != 0.0 && i >= 0 ) { + A->i[ilAi] = i; + A->x[ilAi] = ATrav[ic]; + ilAi++; + Flag = 1; + } + ic = CsuiTrav[ic]; + } + if ( Flag == 1 ) { + VarOldVarNew[Var] = NbVar; + VarNewVarOld[NbVar] = Var; + NbVar++; + } +} + +for ( Cnt = ContrainteDepart ; Cnt < ContrainteMx ; Cnt++ ) { + if ( SensContrainteTrav[Cnt] != '<' ) continue; + i = CntOldCntNew[Cnt]; + if ( i >= 0 ) { + A->p[NbVar] = ilAi; + A->i[ilAi] = i; + A->x[ilAi] = 1.0; + VarNewVarOld[NbVar] = Pne->NombreDeVariablesTrav + Cnt; + ilAi++; + NbVar++; + } +} + +printf("NbVar %d\n",NbVar); + + +NbVar0 = NbVar; +A->p[NbVar] = ilAi; +A->n = NbVar; +A->m = NbCnt; +A->p[NbVar] = ilAi; + +printf("NbCnt = %d\n",NbCnt); + + +A->nz = -1; +A->nzmax = ilAi; + + +seed = 0; +Csd = cs_dmperm( A, seed ); + +/* A faire: verifier que toutes les colonnes de Rb sont dans C3 */ + +printf("\nPrimal\n"); +Cb = Csd->cc[1]; +printf("Nombre d'elements de CBarre : %d\n",Cb); +C1 = Csd->cc[2]-Csd->cc[1]; +printf("Nombre d'elements de C1 : %d\n",C1); +C2 = Csd->cc[3]-Csd->cc[2]; +printf("Nombre d'elements de C2 : %d\n",C2); +C3 = Csd->cc[4]-Csd->cc[3]; +printf("Nombre d'elements de C3 : %d\n",C3); + +printf("\n"); +R1 = Csd->rr[1]; +printf("Nombre d'elements de R1 : %d\n",R1); +R2 = Csd->rr[2]-Csd->rr[1]; +printf("Nombre d'elements de R2 : %d\n",R2); +R3 = Csd->rr[3]-Csd->rr[2]; +printf("Nombre d'elements de R3 : %d\n",R3); +Rb = Csd->rr[4]-Csd->rr[3]; +printf("Nombre d'elements de RBarre : %d\n",Rb); + +Ligne = (int *) malloc( NbCnt * sizeof( int ) ); +Colonne = (int *) malloc( NbVar * sizeof( int ) ); + + +FactorisationOK = 0; +MatriceSinguliere = 1; + + +if ( Rb != 0 ) { + /* Il faut verifier que toutes les colonnes de R3 font partie de C3 */ + +} + +Resolu = OUI_PNE; +if ( C3 != 0 ) { + + printf("C3 %d R3 %d\n",C3,R3); + NbVarDuProblemeReduit = C3; + NbCntDuProblemeReduit = C3; + IndexCC = 3; + IndexRR = 2; + + for ( i = 0 ; i < NbCnt ; i++ ) Ligne[i] = -1; + for ( i = 0 ; i < NbVar ; i++ ) Colonne[i] = -1; + + ccDeb = (int) Csd->cc[IndexCC]; + ccFin = (int) Csd->cc[IndexCC+1]; + rrDeb = (int) Csd->rr[IndexRR]; + rrFin = (int) Csd->rr[IndexRR+1]; + + Resolu = NON_PNE; + MatriceFactorisee = (MATRICE * ) PNE_DumalgeFactoriserMatrice( Pne, &MatriceAFactoriser, + NbVarDuProblemeReduit, + NbCntDuProblemeReduit, + ccDeb, + ccFin, + rrDeb, + rrFin, + (void *) Csd, + (void *) A, + Ligne, + Colonne, + &CodeRet, FactorisationOK, MatriceSinguliere ); + + if ( CodeRet != MatriceSinguliere ) { + /* On essaie de resoudre C3 */ + + PNE_DumalgeResoudrePrimal( Pne, (void *) MatriceFactorisee, (void *) MatriceAFactoriser, + NbVarDuProblemeReduit, NbCntDuProblemeReduit, + + ccDeb, + ccFin, + rrDeb, + rrFin, + + (void *) Csd, + (void *) A, + + VarNewVarOld, + CntNewCntOld, + B, + &CodeRet, + FactorisationOK, + + + ValeurDeBorneInf, + ValeurDeBorneSup, + BorneInfConnue, + BorneSupConnue, + UneVariableAEteFixee + + ); + Resolu = OUI_PNE; + if ( CodeRet != FactorisationOK ) { + *Faisabilite = NON_PNE; + goto FIN; + } + + } + else { + + } + + +} + + + +if ( C2 != 0 && Resolu ) { + printf("C2 %d R2 %d\n",C2,R2); + NbVarDuProblemeReduit = C2; + NbCntDuProblemeReduit = C2; + IndexCC = 2; + IndexRR = 1; + + for ( i = 0 ; i < NbCnt ; i++ ) Ligne[i] = -1; + for ( i = 0 ; i < NbVar ; i++ ) Colonne[i] = -1; + + ccDeb = (int) Csd->cc[IndexCC]; + ccFin = (int) Csd->cc[IndexCC+1]; + rrDeb = (int) Csd->rr[IndexRR]; + rrFin = (int) Csd->rr[IndexRR+1]; + + Resolu = NON_PNE; + MatriceFactorisee = (MATRICE * ) PNE_DumalgeFactoriserMatrice( Pne, &MatriceAFactoriser, + NbVarDuProblemeReduit, + NbCntDuProblemeReduit, + ccDeb, + ccFin, + rrDeb, + rrFin, + (void *) Csd, + (void *) A, + Ligne, + Colonne, + &CodeRet, FactorisationOK, MatriceSinguliere ); + + if ( CodeRet != MatriceSinguliere ) { + + PNE_DumalgeResoudrePrimal( Pne, (void *) MatriceFactorisee, (void *) MatriceAFactoriser, + NbVarDuProblemeReduit, NbCntDuProblemeReduit, + + ccDeb, + ccFin, + rrDeb, + rrFin, + + (void *) Csd, + (void *) A, + + VarNewVarOld, + CntNewCntOld, + B, + &CodeRet, + FactorisationOK, + + + + ValeurDeBorneInf, + ValeurDeBorneSup, + BorneInfConnue, + BorneSupConnue, + UneVariableAEteFixee + + ); + + + Resolu = OUI_PNE; + if ( CodeRet != FactorisationOK ) { + *Faisabilite = NON_PNE; + goto FIN; + } + + + + + } + else { + /* + if ( C3 == 0 ) { + Choix = LIGNE; + LigneIndeterminee = LU_Indeterminees( MatriceFactorisee, &NombreDeLignesIndeterminees, Choix, LIGNE, COLONNE ); + printf("NombreDeLignesIndeterminees %d\n",NombreDeLignesIndeterminees); + int i; int r; + NbCntSupprimees = 0; + for ( i = 0; i < NombreDeLignesIndeterminees ; i++ , j++ ) { + j = LigneIndeterminee[i]; + r = Csd->p[rrDeb+j]; + Cnt = CntNewCntOld[r]; + if ( Presolve->LaContrainteEstBornante[Cnt] != OUI_PNE ) { + CntSupprimee[Cnt] = 1; + ContrainteInactive[Cnt] = OUI_PNE; + NbCntSupprimees++; + } + } + printf("NbCntSupprimees %d\n",NbCntSupprimees); + if ( NbCntSupprimees > 0 ) goto Debut; + + } + */ + } +} +if ( C1 != 0 && C2 == 0 && 0 ) { + NbVarDuProblemeReduit = C1; + NbCntDuProblemeReduit = C1; + IndexCC = 1; + IndexRR = 0; + for ( i = 0 ; i < NbCnt ; i++ ) Ligne[i] = -1; + for ( i = 0 ; i < NbVar ; i++ ) Colonne[i] = -1; + + if ( IndexCC == 0 ) ccDeb = 0; + else ccDeb = (int) Csd->cc[IndexCC]; + ccFin = (int) Csd->cc[IndexCC+1]; + if ( IndexRR == 0 ) rrDeb = 0; + else rrDeb = (int) Csd->rr[IndexRR]; + rrFin = (int) Csd->rr[IndexRR+1]; + + printf("resolution de la partie C1/R1 C1 %d R1 %d\n",C1,R1); + printf("ccDeb %d ccFin %d rrDeb %d rrFin %d \n",ccDeb,ccFin,rrDeb,rrFin); + MatriceFactorisee = (MATRICE * ) PNE_DumalgeFactoriserMatrice( Pne, &MatriceAFactoriser, + NbVarDuProblemeReduit, + NbCntDuProblemeReduit, + ccDeb, + ccFin, + rrDeb, + rrFin, + (void *) Csd, + (void *) A, + Ligne, + Colonne, + &CodeRet, FactorisationOK, MatriceSinguliere ); + + if ( CodeRet == MatriceSinguliere ) { + + } + + exit(0); +} + +FIN: + +free( VarOldVarNew ); +free( VarNewVarOld ); + +free( CntOldCntNew ); +free( CntNewCntOld ); +free( Ligne ); +free( Colonne ); +free ( A->p ); +free ( A->i ); +free( A->x ); +free( A ); +free( B ); + +cs_dfree( Csd ); + +return; +} + +# endif + + diff --git a/src/ext/Sirius_Solver/pne/pne_node_dm_factoriser_matrice.c b/src/ext/Sirius_Solver/pne/pne_node_dm_factoriser_matrice.c new file mode 100644 index 0000000000..af9a11a563 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_node_dm_factoriser_matrice.c @@ -0,0 +1,164 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution d'un sous systeme issu de la decomposition + Dumalge-Mendelson + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if DUMALGE_MENDELSON_PNE == OUI_PNE + +# include "btf.h" +# include "btf_internal.h" + +# include "cs.h" + +/*----------------------------------------------------------------------------*/ + +void * PNE_DumalgeFactoriserMatrice( PROBLEME_PNE * Pne, + void ** MatriceAFactoriser, + int NbVarDuProblemeReduit, + int NbCntDuProblemeReduit, + int IndexCCdeb, + int IndexCCfin, + int IndexRRdeb, + int IndexRRfin, + void * Csd_in, + void * A_in, + int * Ligne, + int * Colonne, + char * CodeRet, + char FactorisationOK, + char MatriceSinguliere + ) +{ +int ic; int icMax; int icNew; csi ccDeb; csi ccFin; csi rrDeb; csi rrFin; +int i; int j; int l; csd * Csd; cs * A; int c; +MATRICE_A_FACTORISER * Matrice; MATRICE * MatriceFactorisee; + +*CodeRet = FactorisationOK; + +Csd = (csd *) Csd_in; +A = (cs *) A_in; + +ccDeb = (csi) IndexCCdeb; +ccFin = (csi) IndexCCfin; +rrDeb = (csi) IndexRRdeb; +rrFin = (csi) IndexRRfin; + +for ( j = 0 , i = ccDeb ; i < ccFin ; i++ ) { + /* Csd->q[i]: dans la numerotation du probleme soumis a dmperm */ + l = Csd->q[i]; + Colonne[l] = j; + j++; +} + +for ( j = 0 , i = rrDeb ; i < rrFin ; i++ ) { + /* Csd->p[i]: dans la numerotation du probleme soumis a dmperm */ + l = Csd->p[i]; + Ligne[l] = j; + j++; +} + +Matrice = (MATRICE_A_FACTORISER *) malloc( sizeof( MATRICE_A_FACTORISER ) ); +Matrice->NombreDeColonnes = NbVarDuProblemeReduit; +Matrice->IndexDebutDesColonnes = (int *) malloc( NbVarDuProblemeReduit * sizeof( int ) ); +Matrice->NbTermesDesColonnes = (int *) malloc( NbVarDuProblemeReduit * sizeof( int ) ); +Matrice->ValeurDesTermesDeLaMatrice = (double *) malloc( A->nzmax * sizeof( double ) ); +Matrice->IndicesDeLigne = (int *) malloc( A->nzmax * sizeof( int ) ); + +*MatriceAFactoriser = (void *) Matrice; + +icNew = 0; +for ( j = 0 , i = ccDeb ; i < ccFin ; i++ ) { + Matrice->IndexDebutDesColonnes[j] = icNew; + Matrice->NbTermesDesColonnes [j] = 0; + c = Csd->q[i]; + ic = A->p[c]; + icMax = A->p[c+1]; + /*printf("\nMatrice: c %d j %d i %d\n",c,j,i);*/ + while ( ic < icMax ) { + if ( Ligne[A->i[ic]] >= 0 ) { + Matrice->ValeurDesTermesDeLaMatrice[icNew] = A->x[ic]; + Matrice->IndicesDeLigne[icNew] = Ligne[A->i[ic]]; + Matrice->NbTermesDesColonnes[j]++; + /* + printf("ValeurDesTermesDeLaMatrice %e IndicesDeLigne %d A->i %d\n", + Matrice->ValeurDesTermesDeLaMatrice[icNew],Matrice->IndicesDeLigne[icNew],A->i[ic]); + */ + icNew++; + } + ic++; + } + j++; +} + +printf("DEBUT DE FACTORISATION\n"); +Matrice->ContexteDeLaFactorisation = LU_GENERAL; +Matrice->UtiliserLesSuperLignes = NON_LU; +Matrice->FaireScalingDeLaMatrice = OUI_LU; + +Matrice->UtiliserLesValeursDePivotNulParDefaut = NON_LU; +Matrice->ValeurDuPivotMin = 1.e-10; +Matrice->ValeurDuPivotMinExtreme = 1.e-10; + +Matrice->SeuilPivotMarkowitzParDefaut = OUI_LU; +Matrice->FaireDuPivotageDiagonal = NON_LU; +Matrice->LaMatriceEstSymetriqueEnStructure = NON_LU; +Matrice->LaMatriceEstSymetrique = NON_LU; + +MatriceFactorisee = LU_Factorisation( Matrice ); + +printf("FIN DE FACTORISATION \n"); + +if ( MatriceFactorisee == NULL ) { + printf("PB factorisation \n"); + return( NULL ); +} + +if ( Matrice->ProblemeDeFactorisation == MATRICE_SINGULIERE ) { + printf("Matrice singuliere \n"); + *CodeRet = MatriceSinguliere; + return( (void *) MatriceFactorisee ); +} + +return( (void *) MatriceFactorisee ); + +} + +# endif + + diff --git a/src/ext/Sirius_Solver/pne/pne_node_dm_resoudre_primal.c b/src/ext/Sirius_Solver/pne/pne_node_dm_resoudre_primal.c new file mode 100644 index 0000000000..d3a0b21a26 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_node_dm_resoudre_primal.c @@ -0,0 +1,231 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution d'un sous systeme issu de la decomposition + Dumalge-Mendelson + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if DUMALGE_MENDELSON_PNE == OUI_PNE + +# include "btf.h" +# include "btf_internal.h" + +# include "cs.h" + +# define UMIN_EGAL_UMAX 10 + +/*----------------------------------------------------------------------------*/ + +void PNE_DumalgeResoudrePrimal( PROBLEME_PNE * Pne, + void * MatriceFact, + void * MatriceAFactoriser, + int NbVarDuProblemeReduit, + int NbCntDuProblemeReduit, + int IndexCCdeb, + int IndexCCfin, + int IndexRRdeb, + int IndexRRfin, + void * Csd_in, + void * A_in, + int * VarNewVarOld, + int * CntNewCntOld, + double * B, + char * CodeRet, + char FactorisationOK, + + double * ValeurDeBorneInf, + double * ValeurDeBorneSup, + char * BorneInfConnue, + char * BorneSupConnue, + + char * UneVariableAEteFixee + + + ) +{ +int Var; int YaErreur; int NbVarFix; +int ic; int icMax; double X; csi ccDeb; csi ccFin; csi rrDeb; csi rrFin; +int i; int j; int l; csd * Csd; cs * A; + +MATRICE_A_FACTORISER * Matrice; MATRICE * MatriceFactorisee; + +int Cnt; + +double * SecondMembreEtSolution; int CodeRetour; int NombreMaxIterationsDeRaffinement; double ValeurMaxDesResidus; +double * Verif; + + +*CodeRet = FactorisationOK; + +Matrice = (MATRICE_A_FACTORISER *) MatriceAFactoriser; +MatriceFactorisee = (MATRICE *) MatriceFact; + +Csd = (csd *) Csd_in; +A = (cs *) A_in; + +ccDeb = (csi) IndexCCdeb; +ccFin = (csi) IndexCCfin; +rrDeb = (csi) IndexRRdeb; +rrFin = (csi) IndexRRfin; + +SecondMembreEtSolution = (double *) malloc( NbCntDuProblemeReduit * sizeof( double ) ); +Verif = (double *) malloc( NbCntDuProblemeReduit * sizeof( double ) ); + +for ( j = 0 , i = rrDeb ; i < rrFin ; i++ ) { + /* Csd->p[i]: dans la numerotation du probleme soumis a dmperm */ + l = Csd->p[i]; + Cnt = CntNewCntOld[l]; + if ( Cnt < 0 || Cnt >= Pne->NombreDeContraintesTrav ) { + printf("Bug Resolution DM Cnt = %d\n",Cnt); + exit(0); + } + SecondMembreEtSolution[j] = B[Cnt]; + + /*if ( B[Cnt] != 0.0 ) printf("B[%d] = %e\n",Cnt,B[Cnt]);*/ + + j++; +} + +for ( l = 0 ; l < NbCntDuProblemeReduit ; l++ ) { + Verif[l] = SecondMembreEtSolution[l]; +} + +NombreMaxIterationsDeRaffinement = 0; +ValeurMaxDesResidus = 1.e-9; + +MatriceFactorisee->SauvegardeDuResultatIntermediaire = 0; +MatriceFactorisee->SecondMembreCreux = 0; + +LU_LuSolv( MatriceFactorisee, + SecondMembreEtSolution, /* Le vecteur du second membre et la solution */ + &CodeRetour, /* Le code retour ( 0 si tout s'est bien passe ) */ + Matrice, /* Peut etre NULL, dans ce cas on ne fait pas de raffinement */ + NombreMaxIterationsDeRaffinement, + ValeurMaxDesResidus /* En norme L infini i.e. le plus grand */ + ); + +printf("Fin de resolution CodeRetour %d\n",CodeRetour); + +for ( j = 0 ; j < NbVarDuProblemeReduit ; j++ ) { + ic = Matrice->IndexDebutDesColonnes[j]; + icMax = ic + Matrice->NbTermesDesColonnes[j]; + while ( ic < icMax ) { + i = Matrice->IndicesDeLigne[ic]; + Verif[i] -= Matrice->ValeurDesTermesDeLaMatrice[ic] * SecondMembreEtSolution[j]; + ic++; + } +} + +YaErreur = 0; +for ( i = 0 ; i < NbCntDuProblemeReduit ; i++ ) { + if ( fabs(Verif[i]) > 1.e-8 ) { + YaErreur = 1; + printf("Erreur[%d] = %e\n",i,Verif[i]); + } +} +if ( YaErreur == 0 ) printf("Pas d'erreur de resolution\n"); + +YaErreur = 0; +NbVarFix = 0; +for ( j = 0 , i = ccDeb ; i < ccFin ; i++ , j++) { + X = SecondMembreEtSolution[j]; + l = Csd->q[i]; + Var = VarNewVarOld[l]; + if ( Var < Pne->NombreDeVariablesTrav ) { + if ( X < Pne->UminTrav[Var] || X > Pne->UmaxTrav[Var] ) { + printf("Erreur Variable %d = %e Xmin %e Xmax %e\n",Var,X,Pne->UminTrav[Var],Pne->UmaxTrav[Var]); + YaErreur = 1; + *CodeRet = 10; + continue; + } + + Pne->UTrav[Var] = X; + Pne->UminTrav[Var] = X; + Pne->UmaxTrav[Var] = X; + + ValeurDeBorneInf[Var] = X; + ValeurDeBorneSup[Var] = X; + BorneInfConnue[Var] = UMIN_EGAL_UMAX; + BorneSupConnue[Var] = UMIN_EGAL_UMAX; + + *UneVariableAEteFixee = OUI_PNE; + + /* + Pne->TypeDeBorneTrav[Var] = VARIABLE_FIXE; + Pne->TypeDeVariableTrav[Var] = REEL; + */ + NbVarFix++; + + /* Passer la colonne l dans le second membre */ + ic = A->p[l]; + icMax = A->p[l+1]; + while ( ic < icMax ) { + B[CntNewCntOld[A->i[ic]]] -= A->x[ic] * X; + ic++; + } + + } + else { + Cnt = Var - Pne->NombreDeVariablesTrav; + if ( X < 0.0 ) { + printf("Erreur Variable d'ecart contrainte %d %e \n",Cnt,SecondMembreEtSolution[j]); + YaErreur = 1; + } + /*Pne->SensContrainteTrav[Cnt] = '=';*/ + } +} +/*if ( YaErreur == 1 ) exit(0);*/ + +LU_LibererMemoireLU( (MATRICE *) MatriceFactorisee ); + +free( Matrice->IndexDebutDesColonnes ); +free( Matrice->NbTermesDesColonnes ); +free( Matrice->ValeurDesTermesDeLaMatrice ); +free( Matrice->IndicesDeLigne ); +free( Matrice ); + +free( SecondMembreEtSolution ); +free( Verif ); + +printf("Nombre de variables fixees par le primal %d\n",NbVarFix); + +return; +} + +# endif + + diff --git a/src/ext/Sirius_Solver/pne/pne_node_presolve.c b/src/ext/Sirius_Solver/pne/pne_node_presolve.c new file mode 100644 index 0000000000..3495a6ebc4 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_node_presolve.c @@ -0,0 +1,254 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On etudie les domaines de variation des variables entieres + dans le but d'en fixer. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PNE_NodePresolve( PROBLEME_PNE * Pne, int * Faisabilite ) +{ +int Var; double * Umin; double * Umax; int NombreDeVariables; double Ai; +int il; double * U; int NombreDeContraintes; double * UminSv; double * UmaxSv; +char * BorneInfConnue; double * ValeurDeBorneInf; double * Bmin; double * Bmax; +int * NumeroDesVariablesFixees; int i; char CodeRet; BB * Bb; NOEUD * Noeud; +char * T; int NombreDeBornesModifiees; int * NumeroDeLaVariableModifiee; char Mode; +char * TypeDeBorneModifiee; double * NouvelleValeurDeBorne; CONFLICT_GRAPH * ConflictGraph; +PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; char * ContrainteActivable; + +Bb = Pne->ProblemeBbDuSolveur; +Noeud = Bb->NoeudEnExamen; + +if ( Noeud->ProfondeurDuNoeud < PROFONDEUR_MIN_POUR_NODE_PRESOLVE && Noeud->ProfondeurDuNoeud > 1 ) return; + +if ( Noeud->ProfondeurDuNoeud % CYCLE_NODE_PRESOLVE != 0 ) return; + +/*printf("PNE_NodePresolve \n");*/ + +/* Dans la suite: node presolve simplifie */ + +ConflictGraph = Pne->ConflictGraph; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +NombreDeVariables = Pne->NombreDeVariablesTrav; +Umin = Pne->UminTrav; +Umax = Pne->UmaxTrav; +U = Pne->UTrav; + +Mode = PRESOLVE_SIMPLIFIE_POUR_NODE_PRESOLVE; + +if ( Pne->ProbingOuNodePresolve == NULL ) { + PNE_ProbingNodePresolveAlloc( Pne, &CodeRet ); + if ( CodeRet == NON_PNE ) return; +} + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; + +ProbingOuNodePresolve->Faisabilite = OUI_PNE; +ProbingOuNodePresolve->VariableInstanciee = -1; +ProbingOuNodePresolve->NbVariablesModifiees = 0; +ProbingOuNodePresolve->NbContraintesModifiees = 0; + +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; + +Bmin = ProbingOuNodePresolve->Bmin; +Bmax = ProbingOuNodePresolve->Bmax; + +NumeroDesVariablesFixees = ProbingOuNodePresolve->NumeroDesVariablesFixees; +ProbingOuNodePresolve->NombreDeVariablesFixees = 0; + +T = NULL; +ContrainteActivable = NULL; + +ContrainteActivable = (char *) malloc( NombreDeContraintes * sizeof( char ) ); +if ( ContrainteActivable == NULL ) return; +memcpy( (char *) ContrainteActivable, (char *) Pne->ContrainteActivable, NombreDeContraintes * sizeof( char ) ); + +PNE_InitBorneInfBorneSupDesVariables( Pne ); + +/* Calcul min et max des contraintes */ +/* Au noeud racine on part "from scratch" et on archive le resultat, il faut le faire a chaque passage car on a pu fixer des bornes */ +if ( Bb->NoeudEnExamen == Bb->NoeudRacine ) { + PNE_CalculMinEtMaxDesContraintes( Pne, Faisabilite ); + if ( *Faisabilite == NON_PNE ) { + # if TRACES == 1 + printf("Pas de solution dans le presolve apres CalculMinEtMaxDesContraintes\n"); + # endif + goto Fin; + } + /* Et on sauvegarde le resultat comme point de depart pour les noeuds suivants */ + memcpy( (char *) ProbingOuNodePresolve->BminSv, (char *) ProbingOuNodePresolve->Bmin, NombreDeContraintes * sizeof( double ) ); + memcpy( (char *) ProbingOuNodePresolve->BmaxSv, (char *) ProbingOuNodePresolve->Bmax, NombreDeContraintes * sizeof( double ) ); +} +else { + /* Aux autres noeuds, on part des valeurs au noeud racine et on tient compte des instanciations + et des nouvelles bornes */ + PNE_NodePresolveInitBornesDesContraintes( Pne, Faisabilite ); + if ( *Faisabilite == NON_PNE ) { + # if TRACES == 1 + printf("Pas de solution dans le presolve apres NodePresolveInitBornesDesContraintes\n"); + # endif + goto Fin; + } +} + +PNE_PresolveSimplifie( Pne, ContrainteActivable, Mode, Faisabilite ); + +Fin: + +if ( *Faisabilite == NON_PNE ) { + # if TRACES == 1 + printf("Pas de solution dans le node presolve\n"); + # endif + goto FreeMemoire; +} +if ( ProbingOuNodePresolve->NombreDeVariablesFixees <= 0 ) goto FreeMemoire; + +if ( Bb->NoeudEnExamen == Bb->NoeudRacine ) goto ModifsBornesAuNoeudRacine; + +T = (char *) malloc( ( Bb->NombreDeVariablesDuProbleme ) * sizeof(char) ); +if ( T == NULL ) goto FreeMemoire; +memset( (char *) T, 0, Bb->NombreDeVariablesDuProbleme * sizeof( char ) ); +NombreDeBornesModifiees = Noeud->NombreDeBornesModifiees; +NumeroDeLaVariableModifiee = Noeud->NumeroDeLaVariableModifiee; +for( i = 0 ; i < NombreDeBornesModifiees ; i++ ) T[NumeroDeLaVariableModifiee[i]] = 1; + +il = NombreDeBornesModifiees + ProbingOuNodePresolve->NombreDeVariablesFixees; +Noeud->NumeroDeLaVariableModifiee = (int *) realloc( Noeud->NumeroDeLaVariableModifiee, il * sizeof( int ) ); +if ( Noeud->NumeroDeLaVariableModifiee == NULL ) { + free( Noeud->TypeDeBorneModifiee ); + free( Noeud->NouvelleValeurDeBorne ); + Noeud->TypeDeBorneModifiee = NULL; + Noeud->NouvelleValeurDeBorne = NULL; + Noeud->NombreDeBornesModifiees = 0; + goto FreeMemoire; +} +Noeud->TypeDeBorneModifiee = (char *) realloc( Noeud->TypeDeBorneModifiee, il * sizeof( char ) ); +if ( Noeud->TypeDeBorneModifiee == NULL ) { + free( Noeud->NumeroDeLaVariableModifiee ); + free( Noeud->NouvelleValeurDeBorne ); + Noeud->NumeroDeLaVariableModifiee = NULL; + Noeud->NouvelleValeurDeBorne = NULL; + Noeud->NombreDeBornesModifiees = 0; + goto FreeMemoire; +} +Noeud->NouvelleValeurDeBorne = (double *) realloc( Noeud->NouvelleValeurDeBorne, il * sizeof( double ) ); +if ( Noeud->NouvelleValeurDeBorne == NULL ) { + free( Noeud->NumeroDeLaVariableModifiee ); + free( Noeud->TypeDeBorneModifiee ); + Noeud->NumeroDeLaVariableModifiee = NULL; + Noeud->TypeDeBorneModifiee = NULL; + Noeud->NombreDeBornesModifiees = 0; + goto FreeMemoire; +} + +NumeroDeLaVariableModifiee = Noeud->NumeroDeLaVariableModifiee; +TypeDeBorneModifiee = Noeud->TypeDeBorneModifiee; +NouvelleValeurDeBorne = Noeud->NouvelleValeurDeBorne; + +/* De plus on initialise les bornes pour le simplexe qui va suivre. Mais on ne le fait que pour les + variables entieres */ + +for ( i = 0 ; i < ProbingOuNodePresolve->NombreDeVariablesFixees ; i++ ) { + Var = NumeroDesVariablesFixees[i]; + Ai = ValeurDeBorneInf[Var]; + U[Var] = Ai; + Umin[Var] = Ai; + Umax[Var] = Ai; + if ( BorneInfConnue[Var] == FIXATION_SUR_BORNE_SUP ) { + NumeroDeLaVariableModifiee[NombreDeBornesModifiees] = Var; + TypeDeBorneModifiee[NombreDeBornesModifiees] = BORNE_INF; + NouvelleValeurDeBorne[NombreDeBornesModifiees] = Umin[Var]; + NombreDeBornesModifiees++; + T[Var] = 2; + } + else if ( BorneInfConnue[Var] == FIXATION_SUR_BORNE_INF ) { + NumeroDeLaVariableModifiee[NombreDeBornesModifiees] = Var; + TypeDeBorneModifiee[NombreDeBornesModifiees] = BORNE_SUP; + NouvelleValeurDeBorne[NombreDeBornesModifiees] = Umax[Var]; + NombreDeBornesModifiees++; + T[Var] = 2; + } + else { + printf("BUG dans le node presolve: code BorneInfConnue = %d incorrect\n",BorneInfConnue[Var]); + exit(0); + } +} +Noeud->NombreDeBornesModifiees = NombreDeBornesModifiees; + +FreeMemoire: + +free( T ); +free( ContrainteActivable ); + +return; + +ModifsBornesAuNoeudRacine: + +UminSv = Pne->UminTravSv; +UmaxSv = Pne->UmaxTravSv; + +for ( i = 0 ; i < ProbingOuNodePresolve->NombreDeVariablesFixees ; i++ ) { + Var = NumeroDesVariablesFixees[i]; + Ai = ValeurDeBorneInf[Var]; + U[Var] = Ai; + Umin[Var] = Ai; + Umax[Var] = Ai; + UminSv[Var] = Ai; + UmaxSv[Var] = Ai; +} + +/* Attention: il faut recalculer les Min et Max des contraintes si des bornes sont modifiees */ +if ( ProbingOuNodePresolve->NombreDeVariablesFixees > 0 ) { + PNE_InitBorneInfBorneSupDesVariables( Pne ); + PNE_CalculMinEtMaxDesContraintes( Pne, Faisabilite ); + if ( *Faisabilite == NON_PNE ) { + # if TRACES == 1 + printf("Pas de solution apres le presolve du noeud racine\n"); + # endif + goto Fin; + } + /* Et on sauvegarde le resultat comme point de depart pour les noeuds suivants */ + memcpy( (char *) ProbingOuNodePresolve->BminSv, (char *) ProbingOuNodePresolve->Bmin, NombreDeContraintes * sizeof( double ) ); + memcpy( (char *) ProbingOuNodePresolve->BmaxSv, (char *) ProbingOuNodePresolve->Bmax, NombreDeContraintes * sizeof( double ) ); +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/pne/pne_node_presolve_calculer_bornes_des_contraintes.c b/src/ext/Sirius_Solver/pne/pne_node_presolve_calculer_bornes_des_contraintes.c new file mode 100644 index 0000000000..f280b6fec5 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_node_presolve_calculer_bornes_des_contraintes.c @@ -0,0 +1,546 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Appele par le node presolve, on y calcule les min et max + des contraintes au noeud de l'arbre. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define ZERO 1.e-10 + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PNE_NodePresolveInitBornesDesContraintes( PROBLEME_PNE * Pne, int * Faisabilite ) +{ +double * Bmin; double * Bmax; char * BminValide; char * BmaxValide; int NombreDeContraintes; +NOEUD * Noeud; BB * Bb; int i; double * UminSv; double * UmaxSv; +int * NumeroDeLaVariableModifiee; char * TypeDeBorneModifiee; double * NouvelleValeurDeBorne; +int Var; double ValeurDeVar; int * Cdeb; int * Csui; double * A; int * NumContrainte; +char BorneMiseAJour; int Cnt; char * SensContrainte; double * B; int Nb; int il; +int ilMax; int * Nuvar; int * Mdeb; int * NbTerm; int * TypeDeBorne; +int NombreDeVariablesInstanciees; int * IndicesDesVariablesInstanciees; +char * VariableAZeroOuAUn; int Var1; double * Umin; double * Umax; +char * BorneInfConnue; char * BorneSupConnue; char UneVariableAEteFixee; + +Bb = Pne->ProblemeBbDuSolveur; +Noeud = Bb->NoeudEnExamen; + +NombreDeVariablesInstanciees = Noeud->NombreDeVariablesEntieresInstanciees, +IndicesDesVariablesInstanciees = Noeud->IndicesDesVariablesEntieresInstanciees, +VariableAZeroOuAUn = Noeud->ValeursDesVariablesEntieresInstanciees, + +NombreDeContraintes = Pne->NombreDeContraintesTrav; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; + +Bmin = Pne->ProbingOuNodePresolve->Bmin; +Bmax = Pne->ProbingOuNodePresolve->Bmax; +/* On recupere les bornes des contraintes au noeud racine */ +memcpy( (char *) Bmin, (char *) Pne->ProbingOuNodePresolve->BminSv, NombreDeContraintes * sizeof( double ) ); +memcpy( (char *) Bmax, (char *) Pne->ProbingOuNodePresolve->BmaxSv, NombreDeContraintes * sizeof( double ) ); +BminValide = Pne->ProbingOuNodePresolve->BminValide; +BmaxValide = Pne->ProbingOuNodePresolve->BmaxValide; + +/* On applique d'abord les restrictions de bornes connues au noeud */ +UminSv = Pne->UminTravSv; +UmaxSv = Pne->UmaxTravSv; + +Umin = Pne->UminTrav; +Umax = Pne->UmaxTrav; + +NumeroDeLaVariableModifiee = Noeud->NumeroDeLaVariableModifiee; +TypeDeBorneModifiee = Noeud->TypeDeBorneModifiee; +NouvelleValeurDeBorne = Noeud->NouvelleValeurDeBorne; + +for( i = 0 ; i < Noeud->NombreDeBornesModifiees ; i++ ) { + Var = NumeroDeLaVariableModifiee[i]; + if ( TypeDeBorneModifiee[i] == BORNE_INF ) { + ValeurDeVar = NouvelleValeurDeBorne[i]; + BorneMiseAJour = MODIF_BORNE_INF; + } + else if ( TypeDeBorneModifiee[i] == BORNE_SUP ) { + ValeurDeVar = NouvelleValeurDeBorne[i]; + BorneMiseAJour = MODIF_BORNE_SUP; + } + else continue; + /* On met a jour les contraintes dans lesquelles la variable intervient */ + PNE_NodePresolveMajBminBmax( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, UminSv, UmaxSv, + Var, ValeurDeVar, BorneMiseAJour ); +} + +/* On applique les instanciations */ +for ( i = 0 ; i < NombreDeVariablesInstanciees ; i++ ) { + Var = IndicesDesVariablesInstanciees[i]; + if ( VariableAZeroOuAUn[i] == '0' ) { + ValeurDeVar = 0; + BorneMiseAJour = MODIF_BORNE_SUP; + } + else if ( VariableAZeroOuAUn[i] == '1' ) { + ValeurDeVar = 1; + BorneMiseAJour = MODIF_BORNE_INF; + } + else continue; + /* On met a jour les contraintes dans lesquelles la variable intervient */ + PNE_NodePresolveMajBminBmax( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, UminSv, UmaxSv, + Var, ValeurDeVar, BorneMiseAJour ); +} + +/* Pour toutes les instanciations on applique le graphe de conflits */ +for ( i = 0 ; i < NombreDeVariablesInstanciees ; i++ ) { + Var = IndicesDesVariablesInstanciees[i]; + if ( VariableAZeroOuAUn[i] == '0' ) ValeurDeVar = 0; + else if ( VariableAZeroOuAUn[i] == '1' ) ValeurDeVar = 1; + else continue; + PNE_NodePresolveGrapheDeConflit( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, UminSv, + UmaxSv, Umin, Umax, Var, ValeurDeVar, Faisabilite ); + if ( *Faisabilite == NON_PNE ) { + # if TRACES == 1 + printf("NodePresolveInitBornesDesContraintes pas de solution apres NodePresolveGrapheDeConflit\n"); + # endif + return; + } +} + +/* On applique les contraintes de borne variable du variable probing */ + +# if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + PNE_NodePresolveAppliquerContraintesDeBornesVariables( Pne , Faisabilite ); + if ( *Faisabilite == NON_PNE ) { + # if TRACES == 1 + printf("NodePresolveInitBornesDesContraintes pas de solution apres application des contraintes de borne variable\n"); + # endif + return; + } +# endif + +/* Boucle sur toutes les contraintes pour mettre a jour les indicateurs d'activite de depart */ +BorneInfConnue = Pne->ProbingOuNodePresolve->BorneInfConnue; +BorneSupConnue = Pne->ProbingOuNodePresolve->BorneSupConnue; +UneVariableAEteFixee = NON_PNE; +BorneMiseAJour = NON_PNE; + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( BminValide[Cnt] == NON_PNE && BmaxValide[Cnt] == NON_PNE ) continue; + Nb = 0; + Var1 = -1; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Nuvar[il]; + if ( A[il] == 0.0 ) goto NextElement; + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) goto NextElement; + if ( Umin[Var] == Umax[Var] ) goto NextElement; + Nb++; + Var1 = Var; + if ( Nb > 1 ) break; + NextElement: + il++; + } + + if ( Nb == 0 ) { + /* Tous les termes de la contrainte sont fixes */ + if ( SensContrainte[Cnt] == '<' ) { + if ( Bmin[Cnt] > B[Cnt] + SEUIL_DADMISSIBILITE && BminValide[Cnt] == OUI_PNE ) { + # if TRACES == 1 + printf("Contrainte d'inegalite NodePresolveInitBornesDesContraintes Nb = 0 pas de solution Bmin[%d] = %e B = %e\n",Cnt,Bmin[Cnt],B[Cnt]); + # endif + *Faisabilite = NON_PNE; + return; + } + } + else { + /* Contrainte d'egalite */ + if ( ( fabs( Bmax[Cnt] - Bmin[Cnt] ) > SEUIL_DADMISSIBILITE && BmaxValide[Cnt] == OUI_PNE && BminValide[Cnt] == OUI_PNE ) || + ( fabs( Bmax[Cnt] - B[Cnt] ) > SEUIL_DADMISSIBILITE && BmaxValide[Cnt] == OUI_PNE ) ) { + # if TRACES == 1 + printf("Contrainte d'egalite NodePresolveInitBornesDesContraintes Nb = 0 pas de solution Bmin[%d] = %e Bmax[%d] = %e B = %e\n",Cnt,Bmin[Cnt],Cnt,Bmax[Cnt],B[Cnt]); + # endif + *Faisabilite = NON_PNE; + return; + } + } + } + else { + if ( SensContrainte[Cnt] == '<' ) { + if ( BminValide[Cnt] == OUI_PNE && Bmin[Cnt] > B[Cnt] + SEUIL_DADMISSIBILITE ) { + # if TRACES == 1 + printf("NodePresolveInitBornesDesContraintes pas de solution Bmin[%d] = %e %c B = %e BminSv %e\n", + Cnt,Bmin[Cnt],SensContrainte[Cnt],B[Cnt],Pne->ProbingOuNodePresolve->BminSv[Cnt]); + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Nuvar[il]; + printf(" Var = %d Umin %e Umax %e A %e UminSv %e UmaxSv %e\n",Var,Umin[Var],Umax[Var],A[il],UminSv[Var],UmaxSv[Var]); + il++; + } + # endif + *Faisabilite = NON_PNE; + return; + } + } + else { + /* Contrainte d'egalite */ + if ( BmaxValide[Cnt] == OUI_PNE && Bmax[Cnt] < B[Cnt] - SEUIL_DADMISSIBILITE ) { + # if TRACES == 1 + printf("NodePresolveInitBornesDesContraintes pas de solution Bmax[%d] = %e B = %e\n",Cnt,Bmax[Cnt],B[Cnt]); + # endif + *Faisabilite = NON_PNE; + return; + } + if ( BminValide[Cnt] == OUI_PNE && Bmin[Cnt] > B[Cnt] + SEUIL_DADMISSIBILITE ) { + # if TRACES == 1 + printf("NodePresolveInitBornesDesContraintes pas de solution Bmin[%d] = %e B = %e\n",Cnt,Bmin[Cnt],B[Cnt]); + # endif + *Faisabilite = NON_PNE; + return; + } + } + } + +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_NodePresolveMajBminBmax( PROBLEME_PNE * Pne, + int * Cdeb, int * Csui, int * NumContrainte, + double * A, double * Bmin, double * Bmax, + double * UminSv, double * UmaxSv, + int Var, double ValeurDeVar, char BorneMiseAJour ) +{ +int ic; int Cnt; double Ai; char * SensContrainte; char * BmaxValide; double * B; + +SensContrainte = Pne->SensContrainteTrav; +BmaxValide = Pne->ProbingOuNodePresolve->BmaxValide; +B = Pne->BTrav; + +ic = Cdeb[Var]; +while ( ic >= 0 ) { + Ai = A[ic]; + Cnt = NumContrainte[ic]; + if ( BorneMiseAJour == MODIF_BORNE_INF ) { + /* C'est une modification de borne inf */ + if ( Ai > 0 ) { Bmin[Cnt] -= Ai * UminSv[Var]; Bmin[Cnt] += Ai * ValeurDeVar; } + else { + Bmax[Cnt] -= Ai * UminSv[Var]; + Bmax[Cnt] += Ai * ValeurDeVar; + } + } + else { + /* C'est une modification de borne sup */ + if ( Ai < 0 ) { Bmin[Cnt] -= Ai * UmaxSv[Var]; Bmin[Cnt] += Ai * ValeurDeVar; } + else { + Bmax[Cnt] -= Ai * UmaxSv[Var]; + Bmax[Cnt] += Ai * ValeurDeVar; + } + } + ic = Csui[ic]; +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_NodePresolveGrapheDeConflit( PROBLEME_PNE * Pne, + int * Cdeb, int * Csui, int * NumContrainte, + double * A, double * Bmin, double * Bmax, + double * UminSv, double * UmaxSv, + double * Umin, double * Umax, + int Var, double ValeurDeVar, + int * Faisabilite ) +{ +int Edge; int Noeud; int Complement; int Nv; int Pivot; int * First; int * Adjacent; int * Next; +char BorneMiseAJour; + +if ( Pne->ConflictGraph == NULL ) return; + +if ( *Faisabilite == NON_PNE ) return; + +Pivot = Pne->ConflictGraph->Pivot; +First = Pne->ConflictGraph->First; +Adjacent = Pne->ConflictGraph->Adjacent; +Next = Pne->ConflictGraph->Next; + +if ( ValeurDeVar == 1.0 ) { Noeud = Var; Complement = Pivot + Var; } +else { Noeud = Pivot + Var; Complement = Var; } + +Edge = First[Noeud]; +while ( Edge >= 0 ) { + Nv = Adjacent[Edge]; + /* Attention a ne pas prendre le complement */ + if ( Nv == Complement ) goto NextEdge; + if ( Nv < Pivot ) { + Var = Nv; + /* On ne doit pas avoir X[Var] = 1.0 */ + if ( Umin[Var] > 0.0001 ) { + /*printf("Node probing Instanciation infaisable\n");*/ + *Faisabilite = NON_PNE; + return; + } + if ( Umin[Var] == Umax[Var] ) goto NextEdge; + ValeurDeVar = 0.0; + BorneMiseAJour = MODIF_BORNE_SUP; + /* + printf("Node probing Variable %d fixee a %e Umin %e Umax %e\n",Var,ValeurDeVar,Umin[Var],Umax[Var]); + */ + /* On met a jour Bmin et Bmax */ + PNE_NodePresolveMajBminBmax( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, UminSv, UmaxSv, + Var, ValeurDeVar, BorneMiseAJour ); + /* On initialise les bornes */ + + Umin[Var] = ValeurDeVar; + Umax[Var] = ValeurDeVar; + + Pne->ProbingOuNodePresolve->BorneInfConnue[Var] = FIXATION_SUR_BORNE_INF; + Pne->ProbingOuNodePresolve->BorneSupConnue[Var] = FIXATION_SUR_BORNE_INF; + Pne->ProbingOuNodePresolve->ValeurDeBorneInf[Var] = ValeurDeVar; + Pne->ProbingOuNodePresolve->ValeurDeBorneSup[Var] = ValeurDeVar; + + Pne->ProbingOuNodePresolve->NumeroDesVariablesFixees[Pne->ProbingOuNodePresolve->NombreDeVariablesFixees] = Var; + Pne->ProbingOuNodePresolve->NombreDeVariablesFixees += 1; + + /* On continue le graphe a partir de Var */ + PNE_NodePresolveGrapheDeConflit( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, + UminSv, UmaxSv, Umin, Umax, + Var, ValeurDeVar, Faisabilite ); + if ( *Faisabilite == NON_PNE ) return; + } + else { + /* La valeur borne inf est interdite pour la variable */ + /* On doit donc fixer la variable a Umax et fixer les voisins de ce noeud */ + Var = Nv - Pivot; + /* On ne doit pas avoir X[Var] = 0.0 */ + if ( Umax[Var] < 0.9999 ) { + /*printf("Node probing Instanciation infaisable\n");*/ + *Faisabilite = NON_PNE; + return; + } + if ( Umin[Var] == Umax[Var] ) goto NextEdge; + ValeurDeVar = 1.0; + BorneMiseAJour = MODIF_BORNE_INF; + /* + printf("Node probing Variable %d fixee a %e Umin %e Umax %e\n",Var,ValeurDeVar,Umin[Var],Umax[Var]); + */ + /* On met a jour Bmin et Bmax */ + PNE_NodePresolveMajBminBmax( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, UminSv, UmaxSv, + Var, ValeurDeVar, BorneMiseAJour ); + /* On initialise les bornes */ + Umin[Var] = ValeurDeVar; + Umax[Var] = ValeurDeVar; + + Pne->ProbingOuNodePresolve->BorneInfConnue[Var] = FIXATION_SUR_BORNE_SUP; + Pne->ProbingOuNodePresolve->BorneSupConnue[Var] = FIXATION_SUR_BORNE_SUP; + Pne->ProbingOuNodePresolve->ValeurDeBorneInf[Var] = ValeurDeVar; + Pne->ProbingOuNodePresolve->ValeurDeBorneSup[Var] = ValeurDeVar; + + Pne->ProbingOuNodePresolve->NumeroDesVariablesFixees[Pne->ProbingOuNodePresolve->NombreDeVariablesFixees] = Var; + Pne->ProbingOuNodePresolve->NombreDeVariablesFixees += 1; + + /* On continue le graphe a partir de Var */ + PNE_NodePresolveGrapheDeConflit( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, + UminSv, UmaxSv, Umin, Umax, + Var, ValeurDeVar, Faisabilite ); + if ( *Faisabilite == NON_PNE ) return; + } + NextEdge: + Edge = Next[Edge]; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +# if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + +void PNE_NodePresolveAppliquerContraintesDeBornesVariables( PROBLEME_PNE * Pne, + int * Faisabilite ) +{ +int Cnt; int * First; int il; double B; int * Colonne; double * SecondMembre; +double * Coefficient; double Xmin; double Xmax; double * Bmin; double * Bmax; +CONTRAITES_DE_BORNE_VARIABLE * ContraintesDeBorneVariable; int NombreDeContraintesDeBorne; +char * BorneInfConnue; char * BorneSupConnue; double * ValeurDeBorneInf; +double * ValeurDeBorneSup; char BrnInfConnue; int VarBin; int VarCont; double A1; +int * Cdeb; int * Csui; int * NumContrainte; double * A; char BorneMiseAJour; +double Marge; char * LaContrainteDeBorneVariableEstDansLePool; double A2; +char Bvalide; double NouvelleValeur; char UneVariableAEteFixee; + +return; /* Experimentalement on constate que ca consomme du temps et que ca n'apporte pas grand chose + en terme de noeuds qui seront explores dans la recherche arborescente */ + +if ( Pne->ContraintesDeBorneVariable == NULL ) return; + +Marge = 1.e-6; + +Bmin = Pne->ProbingOuNodePresolve->Bmin; +Bmax = Pne->ProbingOuNodePresolve->Bmax; + +BorneInfConnue = Pne->ProbingOuNodePresolve->BorneInfConnue; +BorneSupConnue = Pne->ProbingOuNodePresolve->BorneSupConnue; +ValeurDeBorneInf = Pne->ProbingOuNodePresolve->ValeurDeBorneInf; +ValeurDeBorneSup = Pne->ProbingOuNodePresolve->ValeurDeBorneSup; + +ContraintesDeBorneVariable = Pne->ContraintesDeBorneVariable; + +NombreDeContraintesDeBorne = ContraintesDeBorneVariable->NombreDeContraintesDeBorne; +First = ContraintesDeBorneVariable->First; +LaContrainteDeBorneVariableEstDansLePool = ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool; +SecondMembre = ContraintesDeBorneVariable->SecondMembre; +Colonne = ContraintesDeBorneVariable->Colonne; +Coefficient = ContraintesDeBorneVariable->Coefficient; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; + +/* Parcours des contraintes de bornes variable: la variable entiere est toujours classee en second */ + +for ( Cnt = 0 ; Cnt < NombreDeContraintesDeBorne ; Cnt++ ) { + if ( LaContrainteDeBorneVariableEstDansLePool[Cnt] == OUI_PNE ) continue; + if ( First[Cnt] < 0 ) continue; + il = First[Cnt]; + /* Variable continue */ + VarCont = Colonne[il]; + if ( ValeurDeBorneInf[VarCont] == ValeurDeBorneSup[VarCont] ) continue; + A1 = Coefficient[il]; + + /* Variable entiere */ + il++; + VarBin = Colonne[il]; + BrnInfConnue = BorneInfConnue[VarBin]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || BrnInfConnue == FIXATION_SUR_BORNE_SUP ) { + B = SecondMembre[Cnt] - ( Coefficient[il] * ValeurDeBorneInf[VarBin] ); + if ( A1 > 0 ) { + /* On peut etablir une borne sup */ + Xmax = B / A1; + if ( Xmax < ValeurDeBorneSup[VarCont] ) { + if ( Xmax < ValeurDeBorneInf[VarCont] - Marge ) { *Faisabilite = NON_PNE; goto FinBornesVariable; } + /* + printf("Nouvelle valeur de borne sup pour la variable %d: %e -> %e\n",VarCont,ValeurDeBorneSup[VarCont],Xmax); + */ + /* On met a jour Bmin et Bmax */ + BorneMiseAJour = MODIF_BORNE_SUP; + PNE_NodePresolveMajBminBmax( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, ValeurDeBorneInf, ValeurDeBorneSup, + VarCont, Xmax, BorneMiseAJour ); + + ValeurDeBorneSup[VarCont] = Xmax; + BorneSupConnue[VarCont] = OUI_PNE; + + } + } + else { + /* On peut etablir une borne inf */ + Xmin = B / A1; + if ( Xmin > ValeurDeBorneInf[VarCont] ) { + if ( Xmin > ValeurDeBorneSup[VarCont] + Marge ) { *Faisabilite = NON_PNE; goto FinBornesVariable; } + /* + printf("Nouvelle valeur de borne inf pour la variable %d: %e -> %e\n",VarCont,ValeurDeBorneInf[VarCont],Xmin); + */ + /* On met a jour Bmin et Bmax */ + BorneMiseAJour = MODIF_BORNE_INF; + PNE_NodePresolveMajBminBmax( Pne, Cdeb, Csui, NumContrainte, A, Bmin, Bmax, ValeurDeBorneInf, ValeurDeBorneSup, + VarCont, Xmin, BorneMiseAJour ); + + ValeurDeBorneInf[VarCont] = Xmin; + BorneInfConnue[VarCont] = OUI_PNE; + + } + } + } + else { + /* A l'inverse on regarde si une modification de borne de la variable continue permet de fixer la variable entiere */ + A2 = Coefficient[il]; + Bvalide = NON_PNE; + BorneMiseAJour = NON_PNE; + UneVariableAEteFixee = NON_PNE; + NouvelleValeur = -1; + if ( A1 > 0 ) { + if ( BorneInfConnue[VarCont] == OUI_PNE ) { + B = SecondMembre[Cnt] - ( A1 * ValeurDeBorneInf[VarCont] ); + Bvalide = OUI_PNE; + } + } + else if ( BorneSupConnue[VarCont] == OUI_PNE ) { + B = SecondMembre[Cnt] - ( A1 * ValeurDeBorneSup[VarCont] ); + Bvalide = OUI_PNE; + } + if ( Bvalide == OUI_PNE ){ + if ( A2 > 0.0 ) { + /* On peut calculer une borne sup de la variable entiere */ + Xmax = B / A2; + if ( Xmax < 1 - 1.e-6 ){ + + printf("fixation %d a 0 car %e\n",VarBin,Xmax); fflush( stdout ); + + NouvelleValeur = ValeurDeBorneInf[VarBin]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, VarBin, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + } + } + else { + /* On peut calculer une borne inf de la variable entiere */ + Xmin = -B / fabs( A2 ); + if ( Xmin > 0 + 1.e-6 ) { + + printf("fixation %d a 1 car %e\n",VarBin,Xmin); fflush( stdout ); + + NouvelleValeur = ValeurDeBorneSup[VarBin]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, VarBin, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + } + } + } + } +} +FinBornesVariable: + +return; +} + +# endif + +/*----------------------------------------------------------------------------*/ diff --git a/src/ext/Sirius_Solver/pne/pne_normaliser_une_coupe.c b/src/ext/Sirius_Solver/pne/pne_normaliser_une_coupe.c new file mode 100644 index 0000000000..a3481e2e40 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_normaliser_une_coupe.c @@ -0,0 +1,62 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Normalisation d'une coupe + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_NormaliserUnCoupe( double * Coefficient, double * SecondMembre, int NombreDeTermes, double PlusGrandCoeff ) +{ +int i; double Normalisation; double Sec; + +# if NORMALISER_LES_COUPES_SUR_LES_G_ET_I != OUI_PNE + return; +# endif + +if ( PlusGrandCoeff < SEUIL_POUR_NORMALISER_LES_COUPES_SUR_LES_G_ET_I ) return; + +Normalisation = 1.0 / PlusGrandCoeff; +SPX_ArrondiEnPuissanceDe2( &Normalisation ); + +for ( i = 0 ; i < NombreDeTermes ; i++ ) Coefficient[i] *= Normalisation; +Sec = *SecondMembre; +Sec*= Normalisation; +*SecondMembre = Sec; + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_post_probing.c b/src/ext/Sirius_Solver/pne/pne_post_probing.c new file mode 100644 index 0000000000..49c668e684 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_post_probing.c @@ -0,0 +1,606 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: En fin de probing, si des variables binaires ont ete fixees + on regarde si des contraintes sont de venue des contraintes + de type "forcing constraints". + Plus tard on regardera si des contraintes ne sont pas devenues + redondantes afin de les eliminer. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# include "prs_define.h" +# include "prs_fonctions.h" + +# define TRACES 0 + +# define EPSILON_FORCING_CONSTRAINT 1.e-8 /*1.e-7*/ +# define FORCING_BMIN 1 +# define FORCING_BMAX 2 +# define PAS_DE_FORCING 128 + +# define MARGE_DINFAISABILITE 1.e-7 + +# define TEST_DES_CONTRAINTES_A_UNE_VARIABLE OUI_PNE /*OUI_PNE*/ +# define EPS 1.e-3 /*1.e-3*/ + +# define REBOUCLAGE OUI_PNE /*OUI_PNE*/ + +/*----------------------------------------------------------------------------*/ + +void PNE_PostProbing( PROBLEME_PNE * Pne ) +{ +int Cnt; int NombreDeContraintes; int il; int ilMax; int Var; char SminValide; +char SmaxValide; int * TypeDeVariable; int Nb; double Smin; double Smax; double a; +double b; double NouvelleValeur; int * TypeDeBorne; int * Mdeb; int * NbTerm; +int * Nuvar; double * X; double * Xmin; double * Xmax; double * B; double * A; +char * SensContrainte; char SensCnt; char TypeDeForcing; char TypeBorne; +int DerniereContrainte; int * CorrespondanceCntPneCntEntree; double Ai; int NbCntElim; +int NbVarFixees; int TypeBrn; double * CoutLineaire; char Signe; int NombreDeVariables; +char SuppressionPossible; char DernierSigneTrouve; char SupprimerLaVariable; +int * Cdeb; int * Csui; int * NumContrainte; char SupprimerLaContrainte; +int Var1; double S; double Xi; double Xs; int NbIt; char Reboucler; + +if ( Pne->FaireDuPresolve == NON_PNE ) return; + +if ( Pne->ChainageTransposeeExploitable == NON_PNE ) PNE_ConstruireLeChainageDeLaTransposee( Pne ); + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +X = Pne->UTrav; +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +A = Pne->ATrav; +Nuvar = Pne->NuvarTrav; +CorrespondanceCntPneCntEntree = Pne->CorrespondanceCntPneCntEntree; + +NbCntElim = 0; +NbVarFixees = 0; +NbIt = 0; + +Debut: + +NbIt++; +Reboucler = NON_PNE; + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + SminValide = OUI_PNE; + SmaxValide = OUI_PNE; + Smin = 0.; + Smax = 0.; + SensCnt = SensContrainte[Cnt]; + b = B[Cnt]; + TypeDeForcing = PAS_DE_FORCING; + Nb = 0; + SupprimerLaContrainte = NON_PNE; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Nuvar[il]; + TypeBorne = TypeDeBorne[Var]; + if ( TypeBorne == VARIABLE_NON_BORNEE ) { + SminValide = NON_PNE; + SmaxValide = NON_PNE; + goto FinAnalyseContrainte; + } + a = A[il]; + + if ( TypeBorne == VARIABLE_FIXE ) { + Smin += a * X[Var]; + Smax += a * X[Var]; + } + else { + Nb++; + if ( a > 0.0 ) { + /* Calcul de min */ + if ( SminValide == OUI_PNE ) { + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) { + Smin += a * Xmin[Var]; + } + else { + SminValide = NON_PNE; + if ( SmaxValide == NON_PNE ) break; + } + } + /* Calcul de max */ + if ( SmaxValide == OUI_PNE ) { + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Smax += a * Xmax[Var]; + } + else { + SmaxValide = NON_PNE; + if ( SminValide == NON_PNE ) break; + } + } + } + else { + /* Calcul de min */ + if ( SminValide == OUI_PNE ) { + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Smin += a * Xmax[Var]; + } + else { + SminValide = NON_PNE; + if ( SmaxValide == NON_PNE ) break; + } + } + /* Calcul de max */ + if ( SmaxValide == OUI_PNE ) { + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) { + Smax += a * Xmin[Var]; + } + else { + SmaxValide = NON_PNE; + if ( SminValide == NON_PNE ) break; + } + } + } + } + il++; + } + if ( Nb == 0 ) { + SupprimerLaContrainte = OUI_PNE; + goto FinAnalyseContrainte; + } + + if ( SensCnt == '<' ) { + if ( SmaxValide == OUI_PNE ) { + if ( Smax <= b + MARGE_DINFAISABILITE ) { + # if TRACES == 1 + printf("Contrainte %d redondante Smx = %e < %e Smin %e SminValide %d\n",Cnt,Smax,b,Smin,SminValide); + # endif + SupprimerLaContrainte = OUI_PNE; + } + } + } + if ( SminValide == OUI_PNE ) { + if ( fabs( Smin - b ) < EPSILON_FORCING_CONSTRAINT ) { + # if TRACES == 1 + if ( SensCnt == '<' ) printf("Forcing constraint pendant le variable probing sur contrainte d'inegalite %d\n",Cnt); + else printf("Forcing constraint pendant le variable probing sur contrainte d'egalite %d\n",Cnt); + printf("Bmin %e B %e sens %c\n",Smin,b,SensCnt); + # endif + TypeDeForcing = FORCING_BMIN; + SupprimerLaContrainte = OUI_PNE; + } + } + else if ( SmaxValide == OUI_PNE ) { + if ( SensCnt == '=' ) { + if ( fabs( Smax - b ) < EPSILON_FORCING_CONSTRAINT ) { + # if TRACES == 1 + printf("Forcing constraint pendant le variable probing sur contrainte d'egalite %d\n",Cnt); + printf("Bmax %e B %e sens %c\n",Smax,b,SensCnt); + # endif + TypeDeForcing = FORCING_BMAX; + SupprimerLaContrainte = OUI_PNE; + } + } + } + if ( TypeDeForcing != FORCING_BMIN && TypeDeForcing != FORCING_BMAX ) goto FinAnalyseContrainte; + + # if TRACES == 1 + if ( TypeDeForcing == FORCING_BMIN ) printf("Contraintes %d FORCING_BMIN\n",Cnt); + if ( TypeDeForcing == FORCING_BMAX ) printf("Contraintes %d FORCING_BMAX\n",Cnt); + # endif + + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Nuvar[il]; + TypeBorne = TypeDeBorne[Var]; + if ( TypeBorne == VARIABLE_FIXE ) goto NextIlDoForcing; + a = A[il]; + if ( a == 0.0 ) goto NextIlDoForcing; + if ( TypeDeForcing == FORCING_BMIN ) { + if ( a > 0.0 ) { + # if TRACES == 1 + printf("Forcing constraint contrainte %d variables %d a fixer au min %e\n",Cnt,Var,Xmin[Var]); + # endif + NouvelleValeur = Xmin[Var]; + } + else { + # if TRACES == 1 + printf("Forcing constraint contrainte %d variables %d a fixer au max %e\n",Cnt,Var,Xmax[Var]); + # endif + NouvelleValeur = Xmax[Var]; + } + } + else { /* TypeForcing = FORCING_BMAX */ + if ( a > 0.0 ) { + # if TRACES == 1 + printf("Forcing constraint contrainte %d variables %d a fixer au max %e\n",Cnt,Var,Xmax[Var]); + # endif + NouvelleValeur = Xmax[Var]; + } + else { + # if TRACES == 1 + printf("Forcing constraint contrainte %d variables %d a fixer au min %e\n",Cnt,Var,Xmin[Var]); + # endif + NouvelleValeur = Xmin[Var]; + } + } + /* Si la variable a ete fixee on met a jour la liste des contraintes a examiner au prochain coup */ + X[Var] = NouvelleValeur; + Xmin[Var] = NouvelleValeur; + Xmax[Var] = NouvelleValeur; + TypeDeBorne[Var] = VARIABLE_FIXE; + TypeDeVariable[Var] = REEL; + NbVarFixees++; + NextIlDoForcing: + il++; + } + + FinAnalyseContrainte: + + if ( SupprimerLaContrainte == OUI_PNE ) { + + /* On inverse avec la derniere contrainte */ + + Pne->NumeroDesContraintesInactives[Pne->NombreDeContraintesInactives] = CorrespondanceCntPneCntEntree[Cnt]; + Pne->NombreDeContraintesInactives++; + + DerniereContrainte = NombreDeContraintes - 1; + Mdeb[Cnt] = Mdeb[DerniereContrainte]; + NbTerm[Cnt] = NbTerm [DerniereContrainte]; + B[Cnt] = B[DerniereContrainte]; + SensContrainte[Cnt] = SensContrainte[DerniereContrainte]; + CorrespondanceCntPneCntEntree[Cnt] = CorrespondanceCntPneCntEntree[DerniereContrainte]; + Pne->ChainageTransposeeExploitable = NON_PNE; + Cnt--; + NombreDeContraintes--; + Pne->NombreDeContraintesTrav = NombreDeContraintes; + NbCntElim++; + } + +} + +# if TEST_DES_CONTRAINTES_A_UNE_VARIABLE == OUI_PNE +/* Contraintes a une variable */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + S = 0.; + Nb = 0; + SupprimerLaContrainte = NON_PNE; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + Ai = 1.; + Var1 = -1; + while ( il < ilMax ) { + Var = Nuvar[il]; + TypeBorne = TypeDeBorne[Var]; + a = A[il]; + if ( TypeBorne == VARIABLE_FIXE ) { S += a * X[Var]; goto NextElement; } + else if ( Xmin[Var] == Xmax[Var] ) { S += a * Xmin[Var]; goto NextElement; } + else { + Nb++; + if ( Nb > 1 ) goto Synthese; + Var1 = Var; + Ai = A[il]; + } + NextElement: + il++; + } + Synthese: + if ( Var1 < 0 ) continue; + if ( Nb == 0 ) { + # if TRACES == 1 + printf("Contrainte %d sans variable \n",Cnt); + # endif + SupprimerLaContrainte = OUI_PNE; + } + if ( Nb == 1 ) { + Var = Var1; + TypeBorne = TypeDeBorne[Var]; + S = B[Cnt] - S; + if ( SensContrainte[Cnt] == '=' ) { + NouvelleValeur = S / Ai; + if ( TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT || TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( NouvelleValeur < Xmin[Var] - SEUIL_DADMISSIBILITE ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; return; + } + } + else if ( TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT || TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( NouvelleValeur > Xmax[Var] + SEUIL_DADMISSIBILITE ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; return; + } + } + if ( TypeDeVariable[Var] == ENTIER ) { + if ( fabs( NouvelleValeur ) > MARGE_DINFAISABILITE && fabs( 1 - NouvelleValeur ) > MARGE_DINFAISABILITE ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; return; + } + } + /* On fixe la variable */ + + # if TRACES == 1 + if ( TypeDeVariable[Var] == ENTIER ) { + printf("Post probing contrainte d'egalite a une seule variable: on fixe la variable entiere %d a %e (Xmin = %e Xmax = %e)\n",Var,NouvelleValeur,Xmin[Var],Xmax[Var]); + } + else { + printf("Post probing contrainte d'egalite a une seule variable: on fixe la variable %d a %e (Xmin = %e Xmax = %e)\n",Var,NouvelleValeur,Xmin[Var],Xmax[Var]); + } + # endif + + X[Var] = NouvelleValeur; + Xmin[Var] = NouvelleValeur; + Xmax[Var] = NouvelleValeur; + TypeDeBorne[Var] = VARIABLE_FIXE; + TypeDeVariable[Var] = REEL; + NbVarFixees++; + SupprimerLaContrainte = OUI_PNE; + Reboucler = OUI_PNE; + } + else { + /* La contrainte est de sens < */ + /* Attention, on peut fixer la variable si elle est entiere */ + if ( Ai > 0 ) { + Xs = S / Ai; + /* Eventuellement on change la borne sup */ + if ( Xs < Xmax[Var] - EPS ) { + + # if TRACES == 1 + printf("Post probing contrainte d'inegalite a une seule variable: Xmax[%d] = %e devient %e (Xmin = %e)\n",Var,Xmax[Var],Xs,Xmin[Var]); + # endif + + Xmax[Var] = Xs; + SupprimerLaContrainte = OUI_PNE; + Reboucler = OUI_PNE; + if ( TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) TypeBorne = VARIABLE_BORNEE_DES_DEUX_COTES; + else if ( TypeBorne == VARIABLE_NON_BORNEE ) TypeBorne = VARIABLE_BORNEE_SUPERIEUREMENT; + + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( TypeDeVariable[Var] == ENTIER ) { + /* On fixe la variable a Xmin */ + X[Var] = Xmin[Var]; + Xmax[Var] = Xmin[Var]; + TypeBorne = VARIABLE_FIXE; + TypeDeVariable[Var] = REEL; + NbVarFixees++; + } + else if ( fabs( Xmax[Var] - Xmin[Var] ) < ZERO_VARFIXE ) { + /* On fixe la variable */ + X[Var] = Xs; + Xmin[Var] = Xs; + TypeBorne = VARIABLE_FIXE; + TypeDeVariable[Var] = REEL; + NbVarFixees++; + } + } + TypeDeBorne[Var] = TypeBorne; + } + } + else { + Xi = -S / fabs( Ai ); + /* Eventuellement on change la borne inf */ + if ( Xi > Xmin[Var] + EPS ) { + + # if TRACES == 1 + printf("Post probing contrainte d'inegalite a une seule variable: Xmin[%d] = %e devient %e (Xmax = %e)\n",Var,Xmin[Var],Xi,Xmax[Var]); + # endif + + Xmin[Var] = Xi; + SupprimerLaContrainte = OUI_PNE; + Reboucler = OUI_PNE; + if ( TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) TypeBorne = VARIABLE_BORNEE_DES_DEUX_COTES; + else if ( TypeBorne == VARIABLE_NON_BORNEE ) TypeBorne = VARIABLE_BORNEE_INFERIEUREMENT; + + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( TypeDeVariable[Var] == ENTIER ) { + /* On fixe la variable a Xmax */ + X[Var] = Xmax[Var]; + Xmin[Var] = Xmax[Var]; + TypeBorne = VARIABLE_FIXE; + TypeDeVariable[Var] = REEL; + NbVarFixees++; + } + else if ( fabs( Xmax[Var] - Xmin[Var] ) < ZERO_VARFIXE ) { + /* On fixe la variable */ + X[Var] = Xi; + Xmax[Var] = Xi; + TypeBorne = VARIABLE_FIXE; + TypeDeVariable[Var] = REEL; + NbVarFixees++; + } + } + TypeDeBorne[Var] = TypeBorne; + + } + } + } + } + if ( SupprimerLaContrainte == OUI_PNE ) { + + /* On inverse avec la derniere contrainte */ + + Pne->NumeroDesContraintesInactives[Pne->NombreDeContraintesInactives] = CorrespondanceCntPneCntEntree[Cnt]; + Pne->NombreDeContraintesInactives++; + + DerniereContrainte = NombreDeContraintes - 1; + Mdeb[Cnt] = Mdeb[DerniereContrainte]; + NbTerm[Cnt] = NbTerm [DerniereContrainte]; + B[Cnt] = B[DerniereContrainte]; + SensContrainte[Cnt] = SensContrainte[DerniereContrainte]; + CorrespondanceCntPneCntEntree[Cnt] = CorrespondanceCntPneCntEntree[DerniereContrainte]; + Pne->ChainageTransposeeExploitable = NON_PNE; + Cnt--; + NombreDeContraintes--; + Pne->NombreDeContraintesTrav = NombreDeContraintes; + NbCntElim++; + } +} +# endif + +if ( Pne->ChainageTransposeeExploitable == NON_PNE ) PNE_ConstruireLeChainageDeLaTransposee( Pne ); + +if ( NbCntElim == 0 ) goto Fin; + +CoutLineaire = Pne->LTrav; +NombreDeVariables = Pne->NombreDeVariablesTrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + + TypeBrn = TypeDeBorne[Var]; + if ( TypeBrn == VARIABLE_FIXE ) continue; + + if ( CoutLineaire[Var] > 0.0 ) Signe = '+'; + else if ( CoutLineaire[Var] < 0.0 ) Signe = '-'; + else Signe = '|'; + + SuppressionPossible = OUI_PNE; + DernierSigneTrouve = '|'; + + il = Cdeb[Var]; + while ( il >= 0 ) { + Ai = A[il]; + if ( Ai == 0.0 ) goto ContrainteSuivante; + Cnt = NumContrainte[il]; + if ( SensContrainte[Cnt] == '=' ) { + SuppressionPossible = NON_PNE; + break; + } + if ( Signe == '+' ) { + if ( Ai < 0.0 ) { + SuppressionPossible = NON_PNE; + break; + } + } + else if ( Signe == '-' ) { + if ( Ai > 0.0 ) { + SuppressionPossible = NON_PNE; + break; + } + } + else { /* Alors Signe = '|' ) */ + if ( Ai > 0.0 ) { + if ( DernierSigneTrouve == '-' ) { + SuppressionPossible = NON_PNE; + break; + } + else DernierSigneTrouve = '+'; + } + else if ( Ai < 0.0 ) { + if ( DernierSigneTrouve == '+' ) { + SuppressionPossible = NON_PNE; + break; + } + else DernierSigneTrouve = '-'; + } + } + ContrainteSuivante: + il = Csui[il]; + } + SupprimerLaVariable = NON_PNE; + if ( SuppressionPossible == OUI_PNE ) { + if ( Signe == '+' ) { + if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + # if TRACES == 1 + printf("Variable %d cout %e fixee a sa borne inf: %e \n",Var,CoutLineaire[Var],Xmin[Var]); + # endif + SupprimerLaVariable = OUI_PNE; + NouvelleValeur = Xmin[Var]; + } + } + else if ( Signe == '-' ) { + if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + # if TRACES == 1 + printf("Variable %d cout %e fixee a sa borne sup: %e \n",Var,CoutLineaire[Var],Xmax[Var]); + # endif + SupprimerLaVariable = OUI_PNE; + NouvelleValeur = Xmax[Var]; + } + } + else { /* Alors Signe = '|' ) */ + if ( DernierSigneTrouve == '+' ) { + /* La variable n'intervient que dans des contraintes d'inegalite, avec un coefficient positif et + de plus elle n'a pas de cout => on la fixe a Xmin */ + if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + # if TRACES == 1 + printf("Variable %d cout %e fixee a sa borne inf: %e \n",Var,CoutLineaire[Var],Xmin[Var]); + # endif + SupprimerLaVariable = OUI_PNE; + NouvelleValeur = Xmin[Var]; + } + } + else if ( DernierSigneTrouve == '-' ) { + if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + # if TRACES == 1 + printf("Variable %d cout %e fixee a sa borne sup: %e \n",Var,CoutLineaire[Var],Xmax[Var]); + # endif + SupprimerLaVariable = OUI_PNE; + NouvelleValeur = Xmax[Var]; + } + } + else { + /* DernierSigneTrouve = '|' : la variable n'intervient pas dans les contraintes et son cout est nul */ + # if TRACES == 1 + printf("Variable %d a cout nul et n'intervenant dans aucune contrainte\n",Var); + # endif + } + } + if ( SupprimerLaVariable == OUI_PNE ) { + # if TRACES == 1 + printf("Suppression de la variable %d\n",Var); + # endif + X[Var] = NouvelleValeur; + Xmin[Var] = NouvelleValeur; + Xmax[Var] = NouvelleValeur; + TypeDeBorne[Var] = VARIABLE_FIXE; + TypeDeVariable[Var] = REEL; + NbVarFixees++; + } + } +} + +Fin: + +if ( Reboucler == OUI_PNE ) { + NbIt++; + if ( NbIt < 5 && REBOUCLAGE == OUI_PNE ) { + goto Debut; + } +} + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + if ( NbCntElim != 0 || NbVarFixees != 0 ) { + printf("Post probing: %d constraint(s) removed - %d variable(s) fixed\n",NbCntElim,NbVarFixees); + } +} + +# if PRISE_EN_COMPTE_DES_GROUPES_DE_VARIABLES_EQUIVALENTS == OUI_PNE + PNE_ColonnesColineaires( Pne ); +# endif + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_postsolve.c b/src/ext/Sirius_Solver/pne/pne_postsolve.c new file mode 100644 index 0000000000..786ad63da2 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_postsolve.c @@ -0,0 +1,591 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Postsolve (apres le presolve) + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "prs_define.h" + +/* Pour le chainage de la transposee de la matrice d'entree */ +typedef struct{ +int * Cdeb; +int * Csui; +int * NumContrainte; +} TRANSPOSEE; + +void PNE_PostSolveChainageTransposee( PROBLEME_PNE * , PROBLEME_A_RESOUDRE * , TRANSPOSEE * ); +double PNE_PostSolveProduitScalaireVarDualeParColonneOptimisee( PROBLEME_PNE * , int ); +double PNE_PostSolveProduitScalaireVarDualeParColonne( PROBLEME_A_RESOUDRE * , TRANSPOSEE * , int , int ); + +/*----------------------------------------------------------------------------*/ + +void PNE_PostSolve( PROBLEME_PNE * Pne, PROBLEME_A_RESOUDRE * Probleme ) +{ +int i; int j; TRANSPOSEE * TransposeeEntree; double * VariablesDualesDesContraintesE; +char * TypeDOperationDePresolve;int * IndexDansLeTypeDOperationDePresolve; + +VariablesDualesDesContraintesE = Probleme->VariablesDualesDesContraintes; + +TransposeeEntree = (TRANSPOSEE *) malloc( sizeof( TRANSPOSEE ) ); +if ( TransposeeEntree == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_PostSolve\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} +PNE_PostSolveChainageTransposee( Pne, Probleme, TransposeeEntree ); + +TypeDOperationDePresolve = Pne->TypeDOperationDePresolve; +IndexDansLeTypeDOperationDePresolve = Pne->IndexDansLeTypeDOperationDePresolve; + +for ( j = Pne->NombreDOperationsDePresolve - 1 ; j >= 0 ; j-- ) { + i = IndexDansLeTypeDOperationDePresolve[j]; + if ( TypeDOperationDePresolve[j] == SUPPRESSION_VARIABLE_NON_BORNEE ) { + PNE_PostSolveVariablesSubstituees( Pne, Probleme, i, TypeDOperationDePresolve[j] ); + } + else if ( TypeDOperationDePresolve[j] == SUBSITUTION_DE_VARIABLE ) { + PNE_PostSolveVariablesSubstituees( Pne, Probleme, i, TypeDOperationDePresolve[j] ); + } + else if ( TypeDOperationDePresolve[j] == SUPPRESSION_COLONNE_COLINEAIRE ) { + PNE_PostSolveVariablesColineaires( Pne, i ); + } + else if ( TypeDOperationDePresolve[j] == SUPPRESSION_LIGNE_SINGLETON ) { + PNE_PostSolveContraintesSingleton( Pne, i, VariablesDualesDesContraintesE ); + } + else if ( TypeDOperationDePresolve[j] == SUPPRESSION_FORCING_CONSTRAINT ) { + PNE_PostSolveForcingConstraints( Pne, Probleme, (void *) TransposeeEntree, i ); + } + else if ( TypeDOperationDePresolve[j] == SUPPRESSION_CONTRAINTE_COLINEAIRE ) { + PNE_PostSolveContraintesColineaires( Pne, Probleme, i ); + } +} + +free( TransposeeEntree->Cdeb ); +free( TransposeeEntree->Csui ); +free( TransposeeEntree->NumContrainte ); +free( TransposeeEntree ); + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Recuperation de la variable duale des contraintes singleton supprimees */ + +void PNE_PostSolveContraintesSingleton( PROBLEME_PNE * Pne, int i, double * VariablesDualesDesContraintesE ) +{ +int Var; int * Cdeb; int * Csui; int * NumContrainte; double * A; double * u; +double CBarre; int ic; int CntE; double X0; double X; + +/*printf("PNE_PostSolveContraintesSingleton\n");*/ + +if ( VariablesDualesDesContraintesE == NULL ) return; + +CntE = Pne->NumeroDeLaContrainteSingleton[i]; +Var = Pne->VariableDeLaContrainteSingleton[i]; +X0 = Pne->SecondMembreDeLaContrainteSingleton[i]; +X = Pne->UTrav[Var]; +/* Calcul du cout reduit de la variable */ +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; +u = Pne->VariablesDualesDesContraintesTrav; +CBarre = Pne->LTrav[Var]; +ic = Cdeb[Var]; +while ( ic >= 0 ) { + CBarre -= u[NumContrainte[ic]] * A[ic]; + ic = Csui[ic]; +} + +/* Si la variable est sur la valeur du second membre au moment ou on a supprime la contrainte, + ou si elle est fixe, alors la variable duale de la ligne singleton est egale au cout reduit de la variable */ +/* Dans les autres cas, la variable duale de la contrainte est nulle */ +if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_FIXE ) { + /*VariablesDualesDesContraintesE[CntE] = CBarre;*/ + /* Dans ce cas on ne dispose pas du cout reduit car la variable a quitte le probleme resolu par le simplxe => on change le signe du cout */ + VariablesDualesDesContraintesE[CntE] = -Pne->LTrav[Var]; +} +else if ( fabs( X - X0 ) < 1.e-7 ) { + VariablesDualesDesContraintesE[CntE] = CBarre; +} +else { + VariablesDualesDesContraintesE[CntE] = 0.0; +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Recuperation de la variable duale des contraintes colineaires */ + +void PNE_PostSolveContraintesColineaires( PROBLEME_PNE * Pne, PROBLEME_A_RESOUDRE * Probleme, int i ) +{ +int ContrainteConservee; int ContrainteInhibee; double * u; int CntPneConservee; +int * CorrespondanceCntPneCntEntree; double uPne; int Cnt; + +ContrainteConservee = Pne->ContrainteConservee[i]; +ContrainteInhibee = Pne->ContrainteSupprimee[i]; +/* A ce stade la, normalement u[ContrainteConservee] a ete initialise */ +u = Probleme->VariablesDualesDesContraintes; +if ( u == NULL ) return; +u[ContrainteInhibee] = 0.0; + +/* Recherche du numero de la contrainte conservee dans le probleme reduit */ +CorrespondanceCntPneCntEntree = Pne->CorrespondanceCntPneCntEntree; +CntPneConservee = -1; +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + if ( CorrespondanceCntPneCntEntree[Cnt] == ContrainteConservee ) { + CntPneConservee = Cnt; + break; + } +} +if ( CntPneConservee == -1 ) return; + +/* Le seul cas ou on peut etre amene a modifier u[ContrainteConservee] est celui ou + son sens en ete transforme en = alors qu'avant c'etait < ou > */ +if ( Pne->SensContrainteTrav[CntPneConservee] != '=' ) return; +if ( Probleme->Sens[ContrainteConservee] == '=' ) return; +uPne = Pne->VariablesDualesDesContraintesTrav[CntPneConservee]; + +if ( uPne < 0.0 ) { + if ( Probleme->Sens[ContrainteConservee] == '>' ) { + u[ContrainteInhibee] = u[ContrainteConservee]; + u[ContrainteConservee] = 0.0; + } +} +else if ( uPne > 0.0 ) { + if ( Probleme->Sens[ContrainteConservee] == '<' ) { + u[ContrainteInhibee] = u[ContrainteConservee]; + u[ContrainteConservee] = 0.0; + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Recuperation de la variable duale des forcing constraints */ + +void PNE_PostSolveForcingConstraints( PROBLEME_PNE * Pne, PROBLEME_A_RESOUDRE * Probleme, + void * Transposee, int i ) +{ +int Cnt; int * Mdeb; int * NbTerm; int * Nuvar; double * A; double * u; +double * CoutLineaire; double CBarre; int il; double ai; double CB; +double uCntMin; double uCntMax; double ZeroCBarre; int ilMax; +TRANSPOSEE * TransposeeEntree; int Var; int NombreDeVariables; + +/*printf("PNE_PostSolveForcingConstraints\n");*/ + +TransposeeEntree = (TRANSPOSEE *) Transposee; +/* Cnt est dans la numerotation d'entree */ +Cnt = Pne->NumeroDeLaForcingConstraint[i]; + +uCntMin = -LINFINI_PNE; +uCntMax = LINFINI_PNE; +ZeroCBarre = 1.e-8; +NombreDeVariables = Pne->NombreDeVariablesTrav; + +CoutLineaire = Pne->LTrav; +Mdeb = Probleme->IndicesDebutDeLigne; +NbTerm = Probleme->NombreDeTermesDesLignes; +Nuvar = Probleme->IndicesColonnes; +A = Probleme->CoefficientsDeLaMatriceDesContraintes; +u = Probleme->VariablesDualesDesContraintes; + +if ( u == NULL ) return; + +il = Mdeb[Cnt]; +ilMax = il + NbTerm[Cnt]; +while ( il < ilMax ) { + Var = Nuvar[il]; + if ( Var < 0 || Var >= NombreDeVariables ) goto NextIl; + ai = A[il]; + /* Calcul du cout reduit dans le systeme des contraintes utilise pendant + l'optimisation */ + CBarre = CoutLineaire[Var]; + CBarre -= PNE_PostSolveProduitScalaireVarDualeParColonneOptimisee( Pne, Var ); + /* Calcul du cout reduit dans les contraintes d'origine sauf Cnt */ + CB = CoutLineaire[Var]; + CB -= PNE_PostSolveProduitScalaireVarDualeParColonne( Probleme, TransposeeEntree, Var, Cnt ); + /* Il faut conserver le signe */ + if ( CBarre > ZeroCBarre ) { + if ( ai > 0 ) { + if ( CB / ai < uCntMax ) uCntMax = CB / ai; + if ( uCntMax < uCntMin ) uCntMax = uCntMin; /* Mais probleme quand-meme */ + } + else if ( ai < 0 ) { + if ( CB / ai > uCntMin ) uCntMin = CB / ai; + if ( uCntMin > uCntMax ) uCntMin = uCntMax; /* Mais probleme quand-meme */ + } + } + else if ( CBarre < -ZeroCBarre ) { + if ( ai > 0 ) { + if ( CB / ai > uCntMin ) uCntMin = CB / ai; + if ( uCntMin > uCntMax ) uCntMin = uCntMax; /* Mais probleme quand-meme */ + } + else if ( ai < 0 ) { + if ( CB / ai < uCntMax ) uCntMax = CB / ai; + if ( uCntMax < uCntMin ) uCntMax = uCntMin; /* Mais probleme quand-meme */ + } + } + else { + /* CBarre = 0 */ + uCntMin = CB / ai; + uCntMax = uCntMin; + } + NextIl: + il++; +} +/* Une valeur comprise entre uCntMin et uCntMax convient */ +if ( uCntMin > -LINFINI_PNE && uCntMax < LINFINI_PNE ) u[Cnt] = 0.5 * ( uCntMin + uCntMax ); +else if ( uCntMin > -LINFINI_PNE ) u[Cnt] = uCntMin; +else if ( uCntMax < LINFINI_PNE ) u[Cnt] = uCntMax; +else u[Cnt] = 0; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Recuperation des substitutions de variables */ +/* et de la variable duale des contraintes supprimees */ + +void PNE_PostSolveVariablesSubstituees( PROBLEME_PNE * Pne, PROBLEME_A_RESOUDRE * Probleme, + int i, char TypeDOperation ) +{ +int il; int ilMax; int Var; double S; double * ValeurDeX; double * CoeffDeSubstitution; +int * NumeroDeVariableDeSubstitution; int Cnt; double * u; double CBarre; +double uN; double ai; int * Nuvar; + +/*printf("PNE_PostSolveVariablesSubstituees \n");*/ + +ValeurDeX = Pne->UTrav; +CoeffDeSubstitution = Pne->CoeffDeSubstitution; +NumeroDeVariableDeSubstitution = Pne->NumeroDeVariableDeSubstitution; + +S = Pne->ValeurDeLaConstanteDeSubstitution[i]; +il = Pne->IndiceDebutVecteurDeSubstitution[i]; +ilMax = il + Pne->NbTermesVecteurDeSubstitution[i]; +while ( il < ilMax ) { + Var = NumeroDeVariableDeSubstitution[il]; + S += CoeffDeSubstitution[il] * ValeurDeX[Var]; + /*printf("X de valeur qui est reste %e \n",ValeurDeX[Var]);*/ + il++; +} +Var = Pne->NumeroDesVariablesSubstituees[i]; +ValeurDeX[Var] = S; + +/*printf("X valeur subsituee %e \n",ValeurDeX[Var]);*/ +Pne->LTrav[Var] = Pne->CoutDesVariablesSubstituees[i]; + +/* Pour les singletons non bornes sur colonne, leur cout reduit doit etre nul donc u = c / a */ +u = Probleme->VariablesDualesDesContraintes; +if ( u == NULL ) return; +Cnt = Pne->ContrainteDeLaSubstitution[i]; +if ( Cnt >= 0 ) u[Cnt] = 0.0; +else return; + +CBarre = Pne->LTrav[Var]; +if ( TypeDOperation == SUBSITUTION_DE_VARIABLE ) { + /* Calcul du cout reduit de la variable dans le constexte du probleme reduit */ + uN = PNE_PostSolveProduitScalaireVarDualeParColonneOptimisee( Pne, Var ); + CBarre -= uN; +} +/* Recherche du coefficient de la variable */ +ai = 1.; +Nuvar = Probleme->IndicesColonnes; +il = Probleme->IndicesDebutDeLigne[Cnt]; +ilMax = il + Probleme->NombreDeTermesDesLignes[Cnt]; +while ( il < ilMax ) { + if ( Nuvar[il] == Var ) { + ai = Probleme->CoefficientsDeLaMatriceDesContraintes[il]; + break; + } + il++; +} +if ( ai == 0.0 ) return; + +/* Remarque: en ajoutant la contrainte de substitution +- si la variable est entre ses 2 bornes le cout reduit doit etre nul +- si la variable est sur borne inf le cout reduit doit etre positif ou nul +- si la variable est sur borne sup le cout reduit doit etre negatif ou nul +donc pour satisfaire ces 3 contrainte une valeur de coute reduit nul convient. +Ce calcul reste approximatif avant d'avoir trouve une methode plus scientifique */ +u[Cnt] = CBarre / ai; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Recuperation des variables colineaires */ + +void PNE_PostSolveVariablesColineaires( PROBLEME_PNE * Pne, int i ) +{ +int Var1; int Var2; int Var; double Nu; double XVar; double ZeroCBarre; double CBarre1; +double XminVar; double XmaxVar; double XminVar1; double XmaxVar1; double XminVar2; +double XmaxVar2; double XVar1; double XVar2; double CBarre2; int It; double Rho; +double uN; + +/*printf("PNE_PostSolveVariablesColineaires \n");*/ + +ZeroCBarre = 1.e-7; + +/* Par convention, la premiere variable est toujours celle qui remplace les 2 + variable */ +Var1 = Pne->PremiereVariable[i]; +Var = Var1; /* Var est la variable representante */ +Var2 = Pne->DeuxiemeVariable[i]; +Nu = Pne->ValeurDeNu[i]; + +XminVar1 = Pne->XminPremiereVariable[i]; +XmaxVar1 = Pne->XmaxPremiereVariable[i]; + +XminVar2 = Pne->XminDeuxiemeVariable[i]; +XmaxVar2 = Pne->XmaxDeuxiemeVariable[i]; + +if ( Nu > 0 ) { + XminVar = XminVar1 + ( Nu * XminVar2 ); + XmaxVar = XmaxVar1 + ( Nu * XmaxVar2 ); +} +else { + XminVar = XminVar1 + ( Nu * XmaxVar2 ); + XmaxVar = XmaxVar1 + ( Nu * XminVar2 ); +} + +XVar = Pne->UTrav[Var]; + +/* Calcul du cout reduit de la variable representante */ + +if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_FIXE ) goto CoutReduitNul; + +goto CoutReduitNul; + +uN = PNE_PostSolveProduitScalaireVarDualeParColonneOptimisee( Pne, Var ); + +CBarre1 = Pne->LTrav[Var1] - uN; +CBarre2 = Pne->LTrav[Var2] - (uN * Nu); + +if ( CBarre1 > ZeroCBarre ) { + /* La variable Var1 doit se trouver sur borne inf */ + if ( XminVar1 > - ( 0.99 * LINFINI_PNE ) ) { + XVar1 = XminVar1; + XVar2 = ( XVar - XVar1 ) / Nu; + + if ( XVar2 > XmaxVar2 ) { + printf("1- XVar2 %e XmaxVar2 %e CBarre2 %e\n",XVar2,XmaxVar2,CBarre2); + } + if ( XVar2 < XminVar2 ) { + printf("1- XVar2 %e XminVar2 %e CBarre2 %e\n",XVar2,XminVar2,CBarre2); + } + + } + else goto CoutReduitNul; +} +else if ( CBarre1 < -ZeroCBarre ) { + /* La variable Var1 doit se trouver sur borne sup */ + if ( XminVar1 < 0.99 * LINFINI_PNE ) { + XVar1 = XmaxVar1; + XVar2 = ( XVar - XVar1 ) / Nu; + + + if ( XVar2 > XmaxVar2 ) { + printf("2- XVar2 %e XmaxVar2 %e CBarre2 %e\n",XVar2,XmaxVar2,CBarre2); + } + if ( XVar2 < XminVar2 ) { + printf("2- XVar2 %e XminVar2 %e CBarre2 %e\n",XVar2,XminVar2,CBarre2); + } + + } + else goto CoutReduitNul; +} +else { + /* Cout reduit nul, il suffit que les variables satisfassent la combinaire lineaire */ + CoutReduitNul: + XVar1 = XVar; + It = 0; + while ( It < 100 ) { + It++; + if ( XVar1 < XminVar1 - 1.e-9 ) XVar1 = XminVar1; + else if ( XVar1 > XmaxVar1 + 1.e-9 ) XVar1 = XmaxVar1; + XVar2 = ( XVar - XVar1 ) / Nu; + if ( XVar2 > XmaxVar2 + 1.e-9 ) { + Rho = ( XVar2 - XmaxVar2 ) / It; + if ( Nu < 0 ) Rho *= -1.; + XVar1 += Rho; + } + else if ( XVar2 < XminVar2 - 1.e-9 ) { + Rho = ( XminVar2 - XVar2 ) / It; + if ( Nu > 0 ) Rho *= -1.; + XVar1 += Rho; + } + else goto Fin; + } + + printf("Impossible de trouver une valeur pour un couple de variables:\n"); + printf(" XVar %e Nu %e\n",XVar,Nu); + printf(" XminVar1 %e XmaxVar1 %e\n",XminVar1,XmaxVar1); + printf(" XminVar2 %e XmaxVar2 %e\n",XminVar2,XmaxVar2); + printf(" XVar1 %e XVar2 %e\n",XVar1,XVar2); + printf(" XVar1 + Nu * XVar2 %e\n",XVar1+(Nu*XVar2)); + +} + +Fin: + +Pne->UTrav[Var1] = XVar1; +Pne->UTrav[Var2] = XVar2; + +/*printf("XVar %e XVar1 %e XVar2 %e XVar1 + Nu XVar2 %e\n",XVar,XVar1,XVar2,XVar1 + (Nu * XVar2) );*/ + +return; +} + +/*----------------------------------------------------------------------------*/ + +double PNE_PostSolveProduitScalaireVarDualeParColonneOptimisee( PROBLEME_PNE * Pne, + int Var ) +{ +double * A; int * Cdeb; int * Csui; int * NumContrainte; double uN; int ic; +double * u; int Cnt; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; +u = Pne->VariablesDualesDesContraintesTrav; +uN = 0.0; + +ic = Cdeb[Var]; +while ( ic >= 0 ) { + Cnt = NumContrainte[ic]; + uN += u[Cnt] * A[ic]; + ic = Csui[ic]; +} + +return( uN ); +} + + +/*----------------------------------------------------------------------------*/ + +double PNE_PostSolveProduitScalaireVarDualeParColonne( PROBLEME_A_RESOUDRE * Probleme, + TRANSPOSEE * TransposeeEntree, + int Var, int CntExclue ) +{ +double * A; int * Cdeb; int * Csui; int * NumContrainte; double uN; int ic; +double * u; int Cnt; + +A = Probleme->CoefficientsDeLaMatriceDesContraintes; +u = Probleme->VariablesDualesDesContraintes; +Cdeb = TransposeeEntree->Cdeb; +Csui = TransposeeEntree->Csui; +NumContrainte = TransposeeEntree->NumContrainte; + +uN = 0.0; +ic = Cdeb[Var]; +while ( ic >= 0 ) { + Cnt = NumContrainte[ic]; + if ( Cnt != CntExclue ) { + if ( u[Cnt] > VALEUR_NON_INITIALISEE ) { + /* + printf("PNE_PostSolveProduitScalaireVarDualeParColonne: attention utilisation d'une variable duale de la contrainte %d non initialisee\n",Cnt); + printf("pour le calcul du produit scalaire du vecteur des variables duales car la colonne de la variable %d\n",Var); + printf("-> on force la variable duale a 0 pour faire le calcul\n"); + */ + } + else uN += u[Cnt] * A[ic]; + } + ic = Csui[ic]; +} + +return( uN ); +} + +/*----------------------------------------------------------------------------*/ +/* Construction du chainage de la transposee de la matrice d'entree + afin de pouvoir calculer des produits scalaires u N */ + +void PNE_PostSolveChainageTransposee( PROBLEME_PNE * Pne, + PROBLEME_A_RESOUDRE * Probleme, + TRANSPOSEE * TransposeeEntree ) +{ +int Var; int Cnt; int il; int ilMax; int ilk; int * Cder; int * Cdeb; int * Mdeb; +int * NbTerm; int * Nuvar; int * NumContrainte; int * Csui; int Nz; +int NombreDeVariables; int NombreDeContraintes; + +NombreDeVariables = Probleme->NombreDeVariables; +NombreDeContraintes = Probleme->NombreDeContraintes; +Mdeb = Probleme->IndicesDebutDeLigne; +NbTerm = Probleme->NombreDeTermesDesLignes; +Nuvar = Probleme->IndicesColonnes; + +/* Calcul du nombre de termes non nuls dans la matrice */ +Nz = -1; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( Mdeb[Cnt] + NbTerm[Cnt] > Nz ) Nz = Mdeb[Cnt] + NbTerm[Cnt]; +} + +Cdeb = (int *) malloc( NombreDeVariables * sizeof( int ) ); +Cder = (int *) malloc( NombreDeVariables * sizeof( int ) ); +Csui = (int *) malloc( Nz * sizeof( int ) ); +NumContrainte = (int *) malloc( Nz * sizeof( int ) ); +if ( Cdeb == NULL || Cder == NULL || Csui == NULL || NumContrainte == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_PostSolveChainageTransposee \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) Cdeb[Var] = -1; + +/* Chainage de la transposee */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Nuvar[il]; + if ( Cdeb[Var] < 0 ) { + Cdeb[Var] = il; + NumContrainte[il] = Cnt; + Csui[il] = -1; + Cder[Var] = il; + } + else { + ilk = Cder[Var]; + Csui[ilk]= il; + NumContrainte[il] = Cnt; + Csui[il] = -1; + Cder[Var] = il; + } + il++; + } +} + +TransposeeEntree->Cdeb = Cdeb; +TransposeeEntree->Csui = Csui; +TransposeeEntree->NumContrainte = NumContrainte; + +free( Cder ); + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_postsolve_si_presolve_uniquement.c b/src/ext/Sirius_Solver/pne/pne_postsolve_si_presolve_uniquement.c new file mode 100644 index 0000000000..039b68872d --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_postsolve_si_presolve_uniquement.c @@ -0,0 +1,170 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Postsolve (apres le presolve) quand on ne demande que le + presoolve. Dans ce cas on ne recupere que les variables + fixees ou les bornes qui ont ete reduites. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "prs_define.h" + +void PNE_PostSolveVariablesSubstitueesSiUniquementPresolve( PROBLEME_PNE * , PRESOLVE * , int ); + +/*----------------------------------------------------------------------------*/ + +void PNE_PostSolveSiUniquementPresolve( PROBLEME_PNE * Pne, PROBLEME_A_RESOUDRE * Probleme ) +{ +int i; int j; char * TypeDOperationDePresolve; int * IndexDansLeTypeDOperationDePresolve; +int NombreDeVariablesE; int * TypeDeBorneTravE; double * UmaxE; double * UminE; +int VarE; int * TypeDeBornePourPresolve; double * ValeurDeXPourPresolve; int * TypeDeBorneTrav; +double * BorneInfPourPresolve; double * BorneSupPourPresolve; int * CorrespondanceVarEntreeVarNouvelle; +double * UminTrav; double * UmaxTrav; PRESOLVE * Presolve; + +Presolve = (PRESOLVE *) Pne->Controls->Presolve; + +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +CorrespondanceVarEntreeVarNouvelle = Pne->CorrespondanceVarEntreeVarNouvelle; + +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; + +/* Important: si on n'a demande que le presolve, il n'y a pas eu de translation de + borne */ +/* Dans ce mode d'appel une variable d'entree ne peut jamais etre du type + VARIABLE_BORNEE_SUPERIEUREMENT. Les seuls types de bornes possibles sont: + VARIABLE_NON_BORNE + VARIABLE_BORNEE_DES_DEUX_COTES + VARIABLE_BORNEE_INFERIEUREMENT + et on n'a donc jamais de variables a inverser */ + +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( TypeDeBornePourPresolve[i] == VARIABLE_FIXE ) { + /* Attention: a ce stade on peut avoir des variables fixes qui + n'ont ete positionnees a fixes que parce qu'elles ont ete + substituees */ + UminTrav[i] = ValeurDeXPourPresolve[i]; + UmaxTrav[i] = ValeurDeXPourPresolve[i]; + } + else { + UminTrav[i] = BorneInfPourPresolve[i]; + UmaxTrav[i] = BorneSupPourPresolve[i]; + } +} + +/* Recuperation des substitutions de variables et des variables colineaire */ +/* Si presolve uniquement on ne teste pas les colonnes colineaires */ + +TypeDOperationDePresolve = Pne->TypeDOperationDePresolve; +IndexDansLeTypeDOperationDePresolve = Pne->IndexDansLeTypeDOperationDePresolve; + +for ( j = Pne->NombreDOperationsDePresolve - 1 ; j >= 0 ; j-- ) { + i = IndexDansLeTypeDOperationDePresolve[j]; + if ( TypeDOperationDePresolve[j] == SUPPRESSION_VARIABLE_NON_BORNEE || + TypeDOperationDePresolve[j] == SUBSITUTION_DE_VARIABLE ) { + PNE_PostSolveVariablesSubstitueesSiUniquementPresolve( Pne, Presolve, i ); + } +} + + +NombreDeVariablesE = Probleme->NombreDeVariables; +TypeDeBorneTravE = Probleme->TypeDeBorneDeLaVariable; +UmaxE = Probleme->Xmax; +UminE = Probleme->Xmin; +CorrespondanceVarEntreeVarNouvelle = Pne->CorrespondanceVarEntreeVarNouvelle; + +for ( VarE = 0 ; VarE < NombreDeVariablesE ; VarE++ ) { + i = CorrespondanceVarEntreeVarNouvelle[VarE]; + if ( i < 0 ) continue; + UmaxE[VarE] = UmaxTrav[i]; + UminE[VarE] = UminTrav[i]; +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Recuperation des substitutions de variables */ + +void PNE_PostSolveVariablesSubstitueesSiUniquementPresolve( PROBLEME_PNE * Pne, + PRESOLVE * Presolve, + int i ) +{ +int Var; double S; double * CoeffDeSubstitution; int il; int ilMax; char VariableFixe; +int * NumeroDeVariableDeSubstitution; double Smin; double Smax; double * ValeurDeXPourPresolve; +double * BorneInfPourPresolve; double * BorneSupPourPresolve; int * TypeDeBornePourPresolve; +double c; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; + +CoeffDeSubstitution = Pne->CoeffDeSubstitution; +NumeroDeVariableDeSubstitution = Pne->NumeroDeVariableDeSubstitution; + +S = Pne->ValeurDeLaConstanteDeSubstitution[i]; +Smin = S; +Smax = S; +VariableFixe = OUI_PNE; +il = Pne->IndiceDebutVecteurDeSubstitution[i]; +ilMax = il + Pne->NbTermesVecteurDeSubstitution[i]; +while ( il < ilMax ) { + Var = NumeroDeVariableDeSubstitution[il]; + if ( TypeDeBornePourPresolve[Var] != VARIABLE_FIXE ) VariableFixe = NON_PNE; + c = CoeffDeSubstitution[il]; + S += c * ValeurDeXPourPresolve[Var]; + if ( c > 0 ) { + Smin += c * BorneInfPourPresolve[Var]; + Smax += c * BorneSupPourPresolve[Var]; + } + else { + Smin += c * BorneSupPourPresolve[Var]; + Smax += c * BorneInfPourPresolve[Var]; + } + il++; +} +Var = Pne->NumeroDesVariablesSubstituees[i]; +/* Si c'est une variable remplacee elle a ete mise a VARIABLE_FIXE dans le presolve donc + il se peut qu'elle ne soit pas fixe en realite. + Elle n'est fixe que si toutes les variables qui servent a la calculer sont fixes */ +Pne->UTrav[Var] = S; +if ( VariableFixe == OUI_PNE ) { + Pne->UminTrav[Var] = S; + Pne->UmaxTrav[Var] = S; +} +else { + Pne->UminTrav[Var] = Smin; + Pne->UmaxTrav[Var] = Smax; +} + +return; +} + +/*----------------------------------------------------------------------------*/ diff --git a/src/ext/Sirius_Solver/pne/pne_presolve_simplifie.c b/src/ext/Sirius_Solver/pne/pne_presolve_simplifie.c new file mode 100644 index 0000000000..3d9230336e --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_presolve_simplifie.c @@ -0,0 +1,396 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Presolve simplifie. Appele par le reduced cost fixing au noeud + racine et par le noede presolve. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define MX_CYCLES_REDUCED_COST_FIXING_AU_NOEUD_RACINE 5 +# define MX_CYCLES_REDUCED_COST_FIXING_POUR_NODE_PRESOLVE 5 + +# define TRACES 0 + +# define PRISE_EN_COMPTE_DES_CONTRAINTES_DE_BORNES_VARIABLES NON_PNE + +# define POURCENT_LIMITE 0.01 +# define SEUIL_LIMITE 10 + +/*----------------------------------------------------------------------------*/ +/* Appele a chaque fois qu'on trouve une solution entiere */ +void PNE_PresolveSimplifie( PROBLEME_PNE * Pne, char * ContrainteActivable, char Mode, int * Faisabilite ) +{ +int Var; int * TypeDeBorne; int * TypeDeVariable; double S; double * Bmin; double * Bmax; +char * BminValide; char * BmaxValide; char BmnValide; char BmxValide; char SensCnt; +double Bmn; double Bmx; double BCnt; double Ai; double * A; double Xs; double Xi; +double Xs0; double Xi0; int NombreDeVariables; double BminNew; double BmaxNew; int i; +double NouvelleValeur; char * SensContrainte; double * B; int * Cdeb; int * Csui; int ic; +int * NumContrainte; int Cnt; int NombreDeContraintes; char ForcingConstraint; +char * BorneSupConnue; double * ValeurDeBorneSup; char * BorneInfConnue; double * ValeurDeBorneInf; +char BrnInfConnue; char BorneMiseAJour; char UneVariableAEteFixee; char RefaireUnCycle; +char XsValide; char XiValide; int NbCycles; PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; +char SigneCoeff; double * L; int NombreDeVariablesNonFixes; int * NumeroDesVariablesNonFixes; +double CoutVar; int MxCycles; int * CNbTerm; int Limite; + +/*printf("PresolveSimplifie Mode = %d\n",Mode);*/ + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; +if ( ProbingOuNodePresolve == NULL ) return; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +NombreDeVariablesNonFixes = Pne->NombreDeVariablesNonFixes; +NumeroDesVariablesNonFixes = Pne->NumeroDesVariablesNonFixes; + +L = Pne->LTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; + +BorneSupConnue = ProbingOuNodePresolve->BorneSupConnue; +ValeurDeBorneSup = ProbingOuNodePresolve->ValeurDeBorneSup; +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; + +Bmin = ProbingOuNodePresolve->Bmin; +Bmax = ProbingOuNodePresolve->Bmax; +BminValide = ProbingOuNodePresolve->BminValide; +BmaxValide = ProbingOuNodePresolve->BmaxValide; + +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; + +Cdeb = Pne->CdebTrav; +CNbTerm = Pne->CNbTermTrav; +Csui = Pne->CsuiTrav; +A = Pne->ATrav; +NumContrainte = Pne->NumContrainteTrav; + +if ( Mode == PRESOLVE_SIMPLIFIE_POUR_NODE_PRESOLVE ) MxCycles = MX_CYCLES_REDUCED_COST_FIXING_POUR_NODE_PRESOLVE; +else MxCycles = MX_CYCLES_REDUCED_COST_FIXING_AU_NOEUD_RACINE; + +Pne->ProbingOuNodePresolve->Faisabilite = OUI_PNE; +NbCycles = 0; +DebutDeCycle: + +RefaireUnCycle = NON_PNE; + +/* Forcing constraints et contraintes inactives */ + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteActivable[Cnt] == NON_PNE ) continue; + ForcingConstraint = PNE_DeterminerForcingConstraint( Pne, ProbingOuNodePresolve, Cnt, SensContrainte[Cnt], + BminValide[Cnt], BmaxValide[Cnt], Bmin[Cnt], Bmax[Cnt], B[Cnt] ); + if ( ForcingConstraint == OUI_PNE ) { + ContrainteActivable[Cnt] = NON_PNE; + continue; + } + if ( SensContrainte[Cnt] == '<' ) { + if ( BmaxValide[Cnt] == OUI_PNE ) { + if ( Bmax[Cnt] < B[Cnt] - 1.e-6 ) { + ContrainteActivable[Cnt] = NON_PNE; + continue; + } + } + } +} + +/* Essayer aussi les contraintes a une seule variable pour fixer des variables avec Bmin Bmax non calculables cf le Node Presolve REF */ + +Limite = (int) ( POURCENT_LIMITE * NombreDeContraintes ); +if ( Limite < SEUIL_LIMITE ) Limite = SEUIL_LIMITE; + +for ( i = 0 ; i < NombreDeVariablesNonFixes ; i++ ) { + + Var = NumeroDesVariablesNonFixes[i]; + + /*printf(" attention mise en commentaire de l'instruction qui suit dans PNE_PresolveSimplifie \n");*/ + /*if ( Mode == PRESOLVE_SIMPLIFIE_POUR_NODE_PRESOLVE && TypeDeVariable[Var] != ENTIER ) continue;*/ + if ( Mode == PRESOLVE_SIMPLIFIE_POUR_NODE_PRESOLVE && TypeDeVariable[Var] != ENTIER ) { + if ( CNbTerm[Var] > Limite ) continue; + } + + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) continue; + + CoutVar = L[Var]; + SigneCoeff = '?'; + + ic = Cdeb[Var]; + while ( ic >= 0 ) { + Ai = A[ic]; + if ( Ai == 0.0 ) goto NextIc; + Cnt = NumContrainte[ic]; + if ( ContrainteActivable[Cnt] == NON_PNE ) goto NextIc; + + SensCnt = SensContrainte[Cnt]; + + /* Pour la fixation sur critere */ + /* On ne fait la fixation sur critere que si le cout de la variable est nul */ + if ( CoutVar == 0.0 && SigneCoeff != 'X' ) { + if ( SensCnt == '=' ) SigneCoeff = 'X'; + else { + if ( Ai > 0.0 ) { + if ( SigneCoeff == '?' ) SigneCoeff = '+'; + else if ( SigneCoeff == '-' ) SigneCoeff = 'X'; + } + else { + if ( SigneCoeff == '?' ) SigneCoeff = '-'; + else if ( SigneCoeff == '+' ) SigneCoeff = 'X'; + } + } + } + + BmnValide = BminValide[Cnt]; + BmxValide = BmaxValide[Cnt]; + if ( BmnValide == NON_PNE && BmnValide == NON_PNE ) goto NextIc; + + Bmn = Bmin[Cnt]; + Bmx = Bmax[Cnt]; + BCnt = B[Cnt]; + + XsValide = NON_PNE; + XiValide = NON_PNE; + Xs = ValeurDeBorneSup[Var]; + Xi = ValeurDeBorneInf[Var]; + Xs0 = Xs; + Xi0 = Xi; + + UneVariableAEteFixee = NON_PNE; + BorneMiseAJour = NON_PNE; + + if ( SensCnt == '=' ) { + /* On regarde le min et le max */ + if ( BmnValide == OUI_PNE ) { + BminNew = Bmn; + if ( Ai > 0.0 ) BminNew -= Ai * Xi0; /* On avait pris le min */ + else BminNew -= Ai * Xs0; /* On avait pris le mas */ + S = BCnt - BminNew; + if ( Ai > 0 ) { Xs = S / Ai; XsValide = OUI_PNE; } + else { Xi = -S / fabs( Ai ); XiValide = OUI_PNE; } + } + if ( BmxValide == OUI_PNE ) { + BmaxNew = Bmx; + if ( Ai > 0.0 ) BmaxNew -= Ai * Xs0; /* On avait pris le max */ + else BmaxNew -= Ai * Xi0; /* On avait pris le min */ + S = BCnt - BmaxNew; + if ( Ai > 0 ) { Xi = S / Ai; XiValide = OUI_PNE; } + else { Xs = -S / fabs( Ai ); XsValide = OUI_PNE; } + } + } + else { /* SensContrainte est '<' */ + /* On peut calculer un majorant */ + if ( BmnValide == OUI_PNE ) { + BminNew = Bmn; + if ( Ai > 0.0 ) BminNew -= Ai * Xi0; /* On avait pris le min */ + else BminNew -= Ai * Xs0; /* On avait pris le max */ + S = BCnt - BminNew; + if ( Ai > 0 ) { Xs = S / Ai; XsValide = OUI_PNE; } + else { Xi = -S / fabs( Ai ); XiValide = OUI_PNE; } + } + } + + /* Que si Xi ou Xs sont valides et si une des 2 bornes est plus petite ou plus grande */ + if ( XiValide != OUI_PNE && XsValide != OUI_PNE ) goto NextIc; + if ( Xi <= Xi0 && Xs >= Xs0 ) goto NextIc; + PNE_ModifierLaBorneDUneVariable( Pne, Var, SensCnt, XsValide, Xs, XiValide, Xi, &NouvelleValeur, + &BorneMiseAJour, &UneVariableAEteFixee, Faisabilite ); + if ( *Faisabilite == NON_PNE ) { + # if TRACES == 1 + printf("Pas de solution dans le presolve simplifie\n"); + # endif + return; + } + /* Si la variable a ete fixee ou une borne mise a jour on modifie les bornes des contraintes */ + if ( UneVariableAEteFixee != NON_PNE || BorneMiseAJour != NON_PNE ) { + # if TRACES == 1 + printf("Variable %d NouvelleValeur de borne %e\n",Var,NouvelleValeur); + # endif + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) *Faisabilite = NON_PNE; + if ( *Faisabilite == NON_PNE ) { + # if TRACES == 1 + printf("Pas de solution dans le presolve simplifie\n"); + # endif + return; + } + RefaireUnCycle = OUI_PNE; + if ( UneVariableAEteFixee != NON_PNE ) { + break; + } + } + NextIc: + ic = Csui[ic]; + } + + if ( UneVariableAEteFixee != NON_PNE ) continue; + + /* Fixation sur critere */ + if ( CoutVar != 0.0 ) continue; + + if ( SigneCoeff == 'X' ) continue; + + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) continue; + + NouvelleValeur = -1; + BorneMiseAJour = NON_PNE; + UneVariableAEteFixee = NON_PNE; + + if ( SigneCoeff == '+' ) { + if ( CoutVar >= 0.0 ) { + /* On fixe a Umin */ + if ( BorneInfConnue[Var] == OUI_PNE ) { + # if TRACES == 1 + printf("Fixation de la variable %d a %e\n",Var,ValeurDeBorneInf[Var]); + # endif + NouvelleValeur = ValeurDeBorneInf[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + } + } + } + else if ( SigneCoeff == '-' ) { + if ( CoutVar <= 0.0 ) { + /* On fixe a Umax */ + if ( BorneSupConnue[Var] == OUI_PNE ) { + # if TRACES == 1 + printf("Fixation de la variable %d a %e\n",Var,ValeurDeBorneSup[Var]); + # endif + NouvelleValeur = ValeurDeBorneSup[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + } + } + } + else if ( SigneCoeff == '?' ) { + /* La variable n'apparait pas dans les contraintes */ + if ( CoutVar >= 0.0 ) { + /* On fixe a Umin */ + if ( BorneInfConnue[Var] == OUI_PNE ) { + # if TRACES == 1 + printf("Fixation de la variable %d a %e\n",Var,ValeurDeBorneInf[Var]); + # endif + NouvelleValeur = ValeurDeBorneInf[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + } + } + else { + if ( BorneSupConnue[Var] == OUI_PNE ) { + # if TRACES == 1 + printf("Fixation de la variable %d a %e\n",Var,ValeurDeBorneSup[Var]); + # endif + NouvelleValeur = ValeurDeBorneSup[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + } + } + } + if ( UneVariableAEteFixee != NON_PNE || BorneMiseAJour != NON_PNE ) { + # if TRACES == 1 + printf("Variable %d NouvelleValeur de borne %e\n",Var,NouvelleValeur); + # endif + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) *Faisabilite = NON_PNE; + if ( *Faisabilite == NON_PNE ) { + # if TRACES == 1 + printf("Pas de solution dans le presolve simplifie\n"); + # endif + return; + } + RefaireUnCycle = OUI_PNE; + } + +} + +if ( Mode == PRESOLVE_SIMPLIFIE_POUR_NODE_PRESOLVE ) goto FIN_FORCING; + +/* Forcing constraints et contraintes inactives */ + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteActivable[Cnt] == NON_PNE ) continue; + ForcingConstraint = PNE_DeterminerForcingConstraint( Pne, ProbingOuNodePresolve, Cnt, SensContrainte[Cnt], + BminValide[Cnt], BmaxValide[Cnt], Bmin[Cnt], Bmax[Cnt], B[Cnt] ); + if ( ForcingConstraint == OUI_PNE ) { + ContrainteActivable[Cnt] = NON_PNE; + RefaireUnCycle = OUI_PNE; + continue; + } + if ( SensContrainte[Cnt] == '<' ) { + if ( BmaxValide[Cnt] == OUI_PNE ) { + if ( Bmax[Cnt] < B[Cnt] - 1.e-6 ) { + ContrainteActivable[Cnt] = NON_PNE; + RefaireUnCycle = OUI_PNE; + continue; + } + } + } +} + +FIN_FORCING: + + +/* Test */ +//if ( Mode == PRESOLVE_SIMPLIFIE_POUR_REDUCED_COST_FIXING_AU_NOEUD_RACINE && 0 ) { + /*printf("Test PNE_PresolveSimplifieVariableProbin en cours de mise au point il suffit de ne pas l'appeler si pas bon\n");*/ + /*PNE_PresolveSimplifieVariableProbing( Pne, Faisabilite, &RefaireUnCycle );*/ +//} +/* Fin test */ + +/* Test */ +# if PRISE_EN_COMPTE_DES_CONTRAINTES_DE_BORNES_VARIABLES == OUI_PNE + # if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + if ( Mode == PRESOLVE_SIMPLIFIE_POUR_REDUCED_COST_FIXING_AU_NOEUD_RACINE || 1 ) { + PNE_PresolveSimplifieContraintesDeBornesVariables( Pne, Faisabilite, &RefaireUnCycle ); + if ( *Faisabilite == NON_PNE ) { + return; + } + } + # endif +# endif +/* Fin test */ + + +if ( RefaireUnCycle == OUI_PNE ) { + NbCycles++; + if ( NbCycles < MxCycles ) { + # if TRACES == 1 + printf("-> Rebouclage dans de reduced cost fixing au noeud racine\n"); + # endif + goto DebutDeCycle; + } +} + +return; +} + +/*-------------------------------------------------------------------------------*/ diff --git a/src/ext/Sirius_Solver/pne/pne_presolve_simplifie_bornes_variables.c b/src/ext/Sirius_Solver/pne/pne_presolve_simplifie_bornes_variables.c new file mode 100644 index 0000000000..9e7cea48ce --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_presolve_simplifie_bornes_variables.c @@ -0,0 +1,311 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Prise en compte des contraintes de borne variable dans le + presolve simplifie. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES NON_PNE + +# define ZERFIX 1.e-8 +# define MARGE 1.e-5 + +# if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + +/*----------------------------------------------------------------------------*/ + +void PNE_PresolveSimplifieContraintesDeBornesVariables( PROBLEME_PNE * Pne, int * Faisabilite, + char * RefaireUnCycle ) +{ +int Cnt; int * First; int ilbin; int ilcont; double B; int Varcont; int * Colonne; +double * SecondMembre; double * Coefficient; int Varbin; CONTRAITES_DE_BORNE_VARIABLE * ContraintesDeBorneVariable; +int NombreDeContraintesDeBorne; int * TypeDeVariable; char * BorneSupConnue; char * BorneInfConnue; +double XmaxVarcont; double * ValeurDeBorneSup; double * ValeurDeBorneInf; double XminVarcont; +char BrnInfConnue; PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; double S0; double S1; +char UneVariableAEteFixee; char BorneMiseAJour; double NouvelleValeur; + +*RefaireUnCycle = NON_PNE; +if ( *Faisabilite == NON_PNE ) return; + +# if UTILISER_LE_GRAPHE_DE_CONFLITS == OUI_PNE + # if PROBING_JUSTE_APRES_LE_PRESOLVE == NON_PNE + return; + # endif +# endif + +if ( Pne->ContraintesDeBorneVariable == NULL ) return; + +if ( Pne->ProbingOuNodePresolve == NULL ) return; + +ContraintesDeBorneVariable = Pne->ContraintesDeBorneVariable; + +TypeDeVariable = Pne->TypeDeVariableTrav; + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; +BorneSupConnue = ProbingOuNodePresolve->BorneSupConnue; +ValeurDeBorneSup = ProbingOuNodePresolve->ValeurDeBorneSup; +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; + +First = ContraintesDeBorneVariable->First; +SecondMembre = ContraintesDeBorneVariable->SecondMembre; +Colonne = ContraintesDeBorneVariable->Colonne; +Coefficient = ContraintesDeBorneVariable->Coefficient; + +NombreDeContraintesDeBorne = ContraintesDeBorneVariable->NombreDeContraintesDeBorne; + +/* La variable continue est toujours placee en premier */ + +for ( Cnt = 0 ; Cnt < NombreDeContraintesDeBorne ; Cnt++ ) { + if ( First[Cnt] < 0 ) continue; + ilcont = First[Cnt]; + ilbin = ilcont + 1; + B = SecondMembre[Cnt]; + + Varcont = Colonne[ilcont]; + Varbin = Colonne[ilbin]; + + UneVariableAEteFixee = NON_PNE; + BorneMiseAJour = NON_PNE; + + BrnInfConnue = BorneInfConnue[Varbin]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) { + /* La variable binaire est fixee */ + if ( Coefficient[ilcont] > 0 ) { + /* La contrainte est une contrainte de borne sup */ + XmaxVarcont = ( B - ( Coefficient[ilbin] * ValeurDeBorneInf[Varbin] ) ) / Coefficient[ilcont]; + if ( BorneSupConnue[Varcont] == OUI_PNE || 1 ) { + if ( XmaxVarcont < ValeurDeBorneSup[Varcont] - MARGE ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable %d on peut abaisser a borne sup de %e a %e\n",Varcont,ValeurDeBorneSup[Varcont],XmaxVarcont); + # endif + NouvelleValeur = XmaxVarcont; + BorneMiseAJour = MODIF_BORNE_SUP; + *RefaireUnCycle = OUI_PNE; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Varcont, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + *Faisabilite = NON_PNE; + return; + } + } + } + if ( BorneInfConnue[Varcont] == OUI_PNE ) { + if ( ValeurDeBorneInf[Varcont] > XmaxVarcont + MARGE ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable %d pas de solution car XmaxVarcont = %e et ValeurDeBorneInf = %e\n",Varcont,XmaxVarcont,ValeurDeBorneInf[Varcont]); + # endif + *Faisabilite = NON_PNE; + return; + } + else if ( fabs( ValeurDeBorneInf[Varcont] - XmaxVarcont ) < ZERFIX ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable %d fixee a ValeurDeBorneInf = %e\n",Varcont,ValeurDeBorneInf[Varcont]); + # endif + /* A completer */ + NouvelleValeur = ValeurDeBorneInf[Varcont]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + *RefaireUnCycle = OUI_PNE; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Varcont, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + *Faisabilite = NON_PNE; + return; + } + } + } + } + else { + /* La contrainte est une contrainte de borne inf */ + XminVarcont = ( -B + ( Coefficient[ilbin] * ValeurDeBorneInf[Varbin] ) ) / fabs( Coefficient[ilcont] ); + if ( BorneInfConnue[Varcont] == OUI_PNE || 1 ) { + if ( XminVarcont > ValeurDeBorneInf[Varcont] + MARGE ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable %d on peut remonter a borne inf de %e a %e\n",Varcont,ValeurDeBorneInf[Varcont],XminVarcont); + # endif + NouvelleValeur = XminVarcont; + BorneMiseAJour = MODIF_BORNE_INF; + *RefaireUnCycle = OUI_PNE; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Varcont, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + *Faisabilite = NON_PNE; + return; + } + } + } + if ( BorneSupConnue[Varcont] == OUI_PNE ) { + if ( ValeurDeBorneSup[Varcont] < XminVarcont - MARGE ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable %d pas de solution car XminVarcont = %e et ValeurDeBorneSup = %e\n",Varcont,XminVarcont,ValeurDeBorneSup[Varcont]); + # endif + *Faisabilite = NON_PNE; + return; + } + else if ( fabs( XminVarcont - ValeurDeBorneSup[Varcont] ) < ZERFIX ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable %d fixee a ValeurDeBorneInf = %e\n",Varcont,ValeurDeBorneSup[Varcont]); + # endif + NouvelleValeur = ValeurDeBorneSup[Varcont]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + *RefaireUnCycle = OUI_PNE; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Varcont, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + *Faisabilite = NON_PNE; + return; + } + } + } + } + } + else { + /* La variable binaire n'est pas fixee */ + if ( Coefficient[ilcont] > 0 ) { + /* La contrainte est une contrainte de borne sup */ + /* Fixation a 0 */ + S0 = ( B - ( Coefficient[ilbin] * ValeurDeBorneInf[Varbin] ) ) / Coefficient[ilcont]; + XmaxVarcont = S0; + if ( BorneInfConnue[Varcont] == OUI_PNE ) { + if ( ValeurDeBorneInf[Varcont] > XmaxVarcont + MARGE ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable entiere %d valeur 0 interdite\n",Varbin); + # endif + NouvelleValeur = ValeurDeBorneSup[Varbin]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + *RefaireUnCycle = OUI_PNE; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Varbin, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + *Faisabilite = NON_PNE; + return; + } + } + } + /* Fixation a 1 */ + S1 = ( B - ( Coefficient[ilbin] * ValeurDeBorneSup[Varbin] ) ) / Coefficient[ilcont]; + XmaxVarcont = S1; + if ( BorneInfConnue[Varcont] == OUI_PNE ) { + if ( ValeurDeBorneInf[Varcont] > XmaxVarcont + MARGE ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable entiere %d valeur 1 interdite\n",Varbin); + # endif + NouvelleValeur = ValeurDeBorneInf[Varbin]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + *RefaireUnCycle = OUI_PNE; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Varbin, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + *Faisabilite = NON_PNE; + return; + } + } + } + if ( S0 < S1 ) XmaxVarcont = S1; + else XmaxVarcont = S0; + if ( BorneSupConnue[Varcont] == OUI_PNE || 1 ) { + if ( XmaxVarcont < ValeurDeBorneSup[Varcont] - MARGE ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable %d on peut abaisser a borne sup de %e a %e\n",Varcont,ValeurDeBorneSup[Varcont],XmaxVarcont); + # endif + NouvelleValeur = XmaxVarcont; + BorneMiseAJour = MODIF_BORNE_SUP; + *RefaireUnCycle = OUI_PNE; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Varcont, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + *Faisabilite = NON_PNE; + return; + } + } + } + } + else { + /* La contrainte est une contrainte de borne inf */ + S0 = ( -B + ( Coefficient[ilbin] * ValeurDeBorneInf[Varbin] ) ) / fabs( Coefficient[ilcont] ); + XminVarcont = S0; + if ( BorneSupConnue[Varcont] == OUI_PNE ) { + if ( ValeurDeBorneSup[Varcont] < XminVarcont - MARGE ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable entiere %d valeur 0 interdite\n",Varbin); + # endif + NouvelleValeur = ValeurDeBorneSup[Varbin]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + *RefaireUnCycle = OUI_PNE; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Varbin, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + *Faisabilite = NON_PNE; + return; + } + } + } + S1 = ( -B + ( Coefficient[ilbin] * ValeurDeBorneSup[Varbin] ) ) / fabs( Coefficient[ilcont] ); + XminVarcont = S1; + if ( BorneSupConnue[Varcont] == OUI_PNE ) { + if ( ValeurDeBorneSup[Varcont] < XminVarcont - MARGE ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable entiere %d valeur 1 interdite\n",Varbin); + # endif + NouvelleValeur = ValeurDeBorneInf[Varbin]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + *RefaireUnCycle = OUI_PNE; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Varbin, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + *Faisabilite = NON_PNE; + return; + } + } + } + if ( S0 < S1 ) XminVarcont = S0; + else XminVarcont = S1; + if ( BorneInfConnue[Varcont] == OUI_PNE || 1 ) { + if ( XminVarcont > ValeurDeBorneInf[Varcont] + MARGE ) { + # if TRACES == OUI_PNE + printf("Contrainte de borne variable: variable %d on peut remonter a borne inf de %e a %e\n",Varcont,ValeurDeBorneInf[Varcont],XminVarcont); + # endif + NouvelleValeur = XminVarcont; + BorneMiseAJour = MODIF_BORNE_INF; + *RefaireUnCycle = OUI_PNE; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Varcont, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + *Faisabilite = NON_PNE; + return; + } + } + } + } + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +# endif diff --git a/src/ext/Sirius_Solver/pne/pne_presolve_simplifie_variable_probing.c b/src/ext/Sirius_Solver/pne/pne_presolve_simplifie_variable_probing.c new file mode 100644 index 0000000000..a77e66b1ec --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_presolve_simplifie_variable_probing.c @@ -0,0 +1,285 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Presolve simplifie. Appele par le reduced cost fixing au noeud + racine et par le node presolve. + On instancie les variables a 0 et a 1 a la recherche + d'infaisabilites afn de pouvoir fixer la variable. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 1 +# define MARGE 1.e-6 +# define INSTANCATION_A_XMIN 1 +# define INSTANCATION_A_XMAX 2 + +void PNE_PresolveSimplifieVariableProbingSauvegardeConditionsInitiales( PROBLEME_PNE * , double * , double * ); +void PNE_PresolveSimplifieVariableProbingReinitConditionsInitiales( PROBLEME_PNE * , double * , double * ); + +/*----------------------------------------------------------------------------*/ +/* Appele a chaque fois qu'on trouve une solution entiere */ +void PNE_PresolveSimplifieVariableProbing( PROBLEME_PNE * Pne, int * Faisabilite, char * RefaireUnCycle ) +{ +int Var; int * TypeDeVariable; double * Bmin; double * Bmax; char * BminValide; +char * BmaxValide; char BmnValide; char BmxValide; char SensCnt; double Bmn; double Bmx; +double BCnt; int NombreDeVariables; int i; double NouvelleValeur; char * SensContrainte; +double * B; int Cnt; int NombreDeContraintes; char * BorneSupConnue;double * ValeurDeBorneSup; +char * BorneInfConnue; double * ValeurDeBorneInf; char BrnInfConnue; char BorneMiseAJour; +char UneVariableAEteFixee; PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; +int NombreDeVariablesNonFixes; int * NumeroDesVariablesNonFixes; char ProblemeInfaisable; +double ValeurDeVar; int j; char TypeDInstanciation; int NombreDeContraintesAAnalyser; +int * NumeroDeContrainteAAnalyser ; char * BorneInfConnueSv; char * BorneSupConnueSv; +double * ValeurDeBorneInfSv; double * ValeurDeBorneSupSv; double * BminSv; double * BmaxSv; +int * NumeroDeContrainteModifiee; int * NbFoisContrainteModifiee; char * ContrainteAAnalyser; + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +NombreDeVariablesNonFixes = Pne->NombreDeVariablesNonFixes; +NumeroDesVariablesNonFixes = Pne->NumeroDesVariablesNonFixes; + +TypeDeVariable = Pne->TypeDeVariableTrav; + +BorneSupConnueSv = ProbingOuNodePresolve->BorneSupConnueSv; +BorneSupConnue = ProbingOuNodePresolve->BorneSupConnue; +ValeurDeBorneSupSv = ProbingOuNodePresolve->ValeurDeBorneSupSv; +ValeurDeBorneSup = ProbingOuNodePresolve->ValeurDeBorneSup; + +BorneInfConnueSv = ProbingOuNodePresolve->BorneInfConnueSv; +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInfSv = ProbingOuNodePresolve->ValeurDeBorneInfSv; +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; + +/* On recupere les bornes des contraintes au noeud racine */ +Bmin = ProbingOuNodePresolve->Bmin; +Bmax = ProbingOuNodePresolve->Bmax; +BminValide = ProbingOuNodePresolve->BminValide; +BmaxValide = ProbingOuNodePresolve->BmaxValide; + +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; + +/* Attention ce n'est pas dans qu'il faut sauvegarder : free a faire */ +BminSv = (double *) malloc( NombreDeContraintes * sizeof( double ) ); +BmaxSv = (double *) malloc( NombreDeContraintes * sizeof( double ) ); + +PNE_PresolveSimplifieVariableProbingSauvegardeConditionsInitiales( Pne, BminSv, BmaxSv ); + +ProbingOuNodePresolve->NbParcours = 0; +ProbingOuNodePresolve->NbContraintesModifiees = 0; +NumeroDeContrainteModifiee = ProbingOuNodePresolve->NumeroDeContrainteModifiee; +NumeroDeContrainteAAnalyser = ProbingOuNodePresolve->NumeroDeContrainteAAnalyser; +ContrainteAAnalyser = ProbingOuNodePresolve->ContrainteAAnalyser; + +NbFoisContrainteModifiee = ProbingOuNodePresolve->NbFoisContrainteModifiee; +ProbingOuNodePresolve->NombreDeContraintesAAnalyser = 0; + +/* Variable probing simplifie: on fixe alternativement a 0 et a 1 en tenant compte du graphe de conflits + puis on compare Bmin et Bmax aux seconds membres */ + +for ( i = 0 ; i < NombreDeVariablesNonFixes ; i++ ) { + + Var = NumeroDesVariablesNonFixes[i]; + if ( TypeDeVariable[Var] != ENTIER ) continue; + + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) continue; + + /* Fixation a 0 et etablissement d'une liste de Bmin Bmax modifies */ + TypeDInstanciation = INSTANCATION_A_XMAX; + + Instanciation: + + /* Reinit des donnees */ + + PNE_PresolveSimplifieVariableProbingReinitConditionsInitiales( Pne, BminSv, BmaxSv ); + + if ( TypeDInstanciation == INSTANCATION_A_XMAX ) ValeurDeVar = 1; + else if ( TypeDInstanciation == INSTANCATION_A_XMIN ) ValeurDeVar = 0; + else break; + + ProbingOuNodePresolve->NombreDeContraintesAAnalyser = 0; + ProbingOuNodePresolve->VariableInstanciee = Var; + ProbingOuNodePresolve->Faisabilite = OUI_PNE; + ProbingOuNodePresolve->ValeurDeLaVariableInstanciee = ValeurDeVar; + + ProblemeInfaisable = NON_PNE; + + PNE_VariableProbingPreparerInstanciation( Pne, Var, ValeurDeVar ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + /* On doit fixer la variable a l'oppose */ + printf("Apres VariableProbingPreparerInstanciation Pne->ProbingOuNodePresolve->Faisabilite %d\n",Pne->ProbingOuNodePresolve->Faisabilite); + ProblemeInfaisable = OUI_PNE; + Pne->ProbingOuNodePresolve->Faisabilite = OUI_PNE; + } + + if ( ProblemeInfaisable == OUI_PNE ) { + UneVariableAEteFixee = NON_PNE; + BorneMiseAJour = NON_PNE; + if ( TypeDInstanciation == INSTANCATION_A_XMIN ) { + NouvelleValeur = 1; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + } + else if ( TypeDInstanciation == INSTANCATION_A_XMAX ) { + NouvelleValeur = 0; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + } + else goto Fin; + + /* On modifie les bornes des contraintes */ + # if TRACES == 1 + printf("Variable %d NouvelleValeur de borne %e\n",Var,NouvelleValeur); + # endif + + PNE_PresolveSimplifieVariableProbingReinitConditionsInitiales( Pne, BminSv, BmaxSv ); + + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) *Faisabilite = NON_PNE; + if ( *Faisabilite == NON_PNE ) { + # if TRACES == 1 + printf("Pas de solution dans le presolve simplifie\n"); + # endif + goto Fin; + } + + /* Il faut a nouveau sauvegarder les Bmin Bmax et la fixation des variables puisqu'ils + sont modifies par l'instanciation */ + PNE_PresolveSimplifieVariableProbingSauvegardeConditionsInitiales( Pne, BminSv, BmaxSv ); + + *RefaireUnCycle = OUI_PNE; + + /* Inutile d'analyser les contraintes suivante, on peut passer aux instanciations des autres variables */ + break; + } + + /* Si on a fixe une variable, inutile de faire l'autre instanciation */ + if ( ProblemeInfaisable == NON_PNE ) { + if ( TypeDInstanciation == INSTANCATION_A_XMAX ) { + TypeDInstanciation = INSTANCATION_A_XMIN; + goto Instanciation; + } + } + +} + +Fin: + +if ( *RefaireUnCycle == OUI_PNE ) { + PNE_PresolveSimplifieVariableProbingReinitConditionsInitiales( Pne, BminSv, BmaxSv ); +} + +free( BminSv ); +free( BmaxSv ); + +return; +} + +/*-------------------------------------------------------------------------------*/ + +void PNE_PresolveSimplifieVariableProbingReinitConditionsInitiales( PROBLEME_PNE * Pne, double * BminSv, + double * BmaxSv ) +{ +double * Bmin; double * Bmax; int NombreDeVariables; int Cnt; int * NumeroDeContrainteAAnalyser; +PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; int j; int * NumeroDeContrainteModifiee; +int * NbFoisContrainteModifiee; char * ContrainteAAnalyser; + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; + +NombreDeVariables = Pne->NombreDeVariablesTrav; + +memcpy( (char *) ProbingOuNodePresolve->BorneInfConnue, (char *) ProbingOuNodePresolve->BorneInfConnueSv, NombreDeVariables * sizeof( char ) ); +memcpy( (char *) ProbingOuNodePresolve->BorneSupConnue, (char *) ProbingOuNodePresolve->BorneSupConnueSv, NombreDeVariables * sizeof( char ) ); +memcpy( (char *) ProbingOuNodePresolve->ValeurDeBorneInf, (char *) ProbingOuNodePresolve->ValeurDeBorneInfSv, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) ProbingOuNodePresolve->ValeurDeBorneSup, (char *) ProbingOuNodePresolve->ValeurDeBorneSupSv, NombreDeVariables * sizeof( double ) ); + +Bmin = ProbingOuNodePresolve->Bmin; +Bmax = ProbingOuNodePresolve->Bmax; + +NumeroDeContrainteModifiee = ProbingOuNodePresolve->NumeroDeContrainteModifiee; +NumeroDeContrainteAAnalyser = ProbingOuNodePresolve->NumeroDeContrainteAAnalyser; +ContrainteAAnalyser = ProbingOuNodePresolve->ContrainteAAnalyser; +NbFoisContrainteModifiee = ProbingOuNodePresolve->NbFoisContrainteModifiee; + +for ( j = 0 ; j < ProbingOuNodePresolve->NbContraintesModifiees ; j++ ) { + Cnt = NumeroDeContrainteModifiee[j]; + Bmin[Cnt] = BminSv[Cnt]; + Bmax[Cnt] = BmaxSv[Cnt]; + NbFoisContrainteModifiee[Cnt] = 0; +} +ProbingOuNodePresolve->NbContraintesModifiees = 0; + +for ( j = 0 ; j < ProbingOuNodePresolve->NombreDeContraintesAAnalyser ; j++ ) { + ContrainteAAnalyser[NumeroDeContrainteAAnalyser[j]] = NON_PNE; +} +ProbingOuNodePresolve->NombreDeContraintesAAnalyser = 0; + +return; +} + +/*-------------------------------------------------------------------------------*/ + +void PNE_PresolveSimplifieVariableProbingSauvegardeConditionsInitiales( PROBLEME_PNE * Pne, double * BminSv, + double * BmaxSv ) +{ +PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; int NombreDeVariables; int NombreDeContraintes; +int Cnt; int * NbFoisContrainteModifiee; char * ContrainteAAnalyser; + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; + +memcpy( (char *) ProbingOuNodePresolve->BorneInfConnueSv, (char *) ProbingOuNodePresolve->BorneInfConnue, NombreDeVariables * sizeof( char ) ); +memcpy( (char *) ProbingOuNodePresolve->BorneSupConnueSv, (char *) ProbingOuNodePresolve->BorneSupConnue, NombreDeVariables * sizeof( char ) ); +memcpy( (char *) ProbingOuNodePresolve->ValeurDeBorneInfSv, (char *) ProbingOuNodePresolve->ValeurDeBorneInf, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) ProbingOuNodePresolve->ValeurDeBorneSupSv, (char *) ProbingOuNodePresolve->ValeurDeBorneSup, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) BminSv, (char *) ProbingOuNodePresolve->Bmin, NombreDeContraintes * sizeof( double ) ); +memcpy( (char *) BmaxSv, (char *) ProbingOuNodePresolve->Bmax, NombreDeContraintes * sizeof( double ) ); + +NbFoisContrainteModifiee = ProbingOuNodePresolve->NbFoisContrainteModifiee; +ContrainteAAnalyser = ProbingOuNodePresolve->ContrainteAAnalyser; + +for ( Cnt = 0; Cnt < NombreDeContraintes ; Cnt++ ) { + NbFoisContrainteModifiee[Cnt] = 0; + ContrainteAAnalyser[Cnt] = NON_PNE; +} + +ProbingOuNodePresolve->NbContraintesModifiees = 0; +ProbingOuNodePresolve->NombreDeContraintesAAnalyser = 0; + +return; +} + +/*-------------------------------------------------------------------------------*/ diff --git a/src/ext/Sirius_Solver/pne/pne_probing.c b/src/ext/Sirius_Solver/pne/pne_probing.c new file mode 100644 index 0000000000..f3473dcae3 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_probing.c @@ -0,0 +1,763 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Variable probing + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define VERBOSE_VARIABLE_PROBING 0 + +# define DEBUG NON_PNE /* NON_PNE */ + +# define MAJ_FLAG OUI_PNE /*OUI_PNE*/ + +/* Remarque: il y a aussi une limite liee au nombre de balayages de la matrice */ +# define DUREE_DU_PROBING 1800 /*2*/ /* En seconde */ +# define NB_MAX_PARCOURS_MATRICE (2*1000) + +/*----------------------------------------------------------------------------*/ + +void PNE_VariableProbingSauvegardesDonnees( PROBLEME_PNE * Pne ) +{ +int NombreDeVariables; int NombreDeContraintes; +PROBING_OU_NODE_PRESOLVE * Prb; +Prb = Pne->ProbingOuNodePresolve; +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; + +memcpy( (char *) Prb->BorneInfConnueSv, (char *) Prb->BorneInfConnue, NombreDeVariables * sizeof( char ) ); +memcpy( (char *) Prb->BorneSupConnueSv, (char *) Prb->BorneSupConnue, NombreDeVariables * sizeof( char ) ); +memcpy( (char *) Prb->ValeurDeBorneInfSv, (char *) Prb->ValeurDeBorneInf, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) Prb->ValeurDeBorneSupSv, (char *) Prb->ValeurDeBorneSup, NombreDeVariables * sizeof( double ) ); + +memcpy( (char *) Prb->BminSv, (char *) Prb->Bmin, NombreDeContraintes * sizeof( double ) ); +memcpy( (char *) Prb->BmaxSv, (char *) Prb->Bmax, NombreDeContraintes * sizeof( double ) ); + +Prb->NbVariablesModifiees = 0; +Prb->NbContraintesModifiees = 0; +memset( (char *) Prb->VariableModifiee, NON_PNE, NombreDeVariables * sizeof( char ) ); +memset( (int *) Prb->NbFoisContrainteModifiee, 0, NombreDeContraintes * sizeof( int ) ); + +Prb->NbCntCoupesDeProbing = 0; +memset( (char *) Prb->FlagCntCoupesDeProbing, 0, NombreDeContraintes * sizeof( char ) ); + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_VariableProbingReinitDonnees( PROBLEME_PNE * Pne ) +{ +int NombreDeVariables; int NombreDeContraintes; int Var; int Cnt; int i; int * NumeroDeVariableModifiee; +char * VariableModifiee; int * NumeroDeContrainteModifiee; int * NbFoisContrainteModifiee; +char * BorneInfConnue; char * BorneInfConnueSv; char * BorneSupConnue; char * BorneSupConnueSv; +double * ValeurDeBorneInf; double * ValeurDeBorneInfSv; double * ValeurDeBorneSup; +double * ValeurDeBorneSupSv; double * Bmin; double * BminSv; double * Bmax; double * BmaxSv; +PROBING_OU_NODE_PRESOLVE * Prb; +Prb = Pne->ProbingOuNodePresolve; +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; + +/* Recuperation des variables */ +/* +memcpy( (char *) Prb->BorneInfConnue, (char *) Prb->BorneInfConnueSv, NombreDeVariables * sizeof( char ) ); +memcpy( (char *) Prb->BorneSupConnue, (char *) Prb->BorneSupConnueSv, NombreDeVariables * sizeof( char ) ); +memcpy( (char *) Prb->ValeurDeBorneInf, (char *) Prb->ValeurDeBorneInfSv, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) Prb->ValeurDeBorneSup, (char *) Prb->ValeurDeBorneSupSv, NombreDeVariables * sizeof( double ) ); +*/ +NumeroDeVariableModifiee = Prb->NumeroDeVariableModifiee; +VariableModifiee = Prb->VariableModifiee; +BorneInfConnue = Prb->BorneInfConnue; +BorneInfConnueSv = Prb->BorneInfConnueSv; +BorneSupConnue = Prb->BorneSupConnue; +BorneSupConnueSv = Prb->BorneSupConnueSv; +ValeurDeBorneInf = Prb->ValeurDeBorneInf; +ValeurDeBorneInfSv = Prb->ValeurDeBorneInfSv; +ValeurDeBorneSup = Prb->ValeurDeBorneSup; +ValeurDeBorneSupSv = Prb->ValeurDeBorneSupSv; +for ( i = 0 ; i < Prb->NbVariablesModifiees ; i++ ) { + Var = NumeroDeVariableModifiee[i]; + BorneInfConnue[Var] = BorneInfConnueSv[Var]; + BorneSupConnue[Var] = BorneSupConnueSv[Var]; + ValeurDeBorneInf[Var] = ValeurDeBorneInfSv[Var]; + ValeurDeBorneSup[Var] = ValeurDeBorneSupSv[Var]; + VariableModifiee[Var] = NON_PNE; +} +Prb->NbVariablesModifiees = 0; + +# if DEBUG == OUI_PNE + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + if ( BorneInfConnue[i] != BorneInfConnueSv[i] ) { + printf("Bug dans PNE_VariableProbingReinitDonnees 1\n"); + exit(0); + } + if ( BorneSupConnue[i] != BorneSupConnueSv[i] ) { + printf("Bug dans PNE_VariableProbingReinitDonnees 2\n"); + exit(0); + } + if (ValeurDeBorneInf[i] != ValeurDeBorneInfSv[i] ) { + printf("Bug dans PNE_VariableProbingReinitDonnees 3\n"); + exit(0); + } + if (ValeurDeBorneSup[i] != ValeurDeBorneSupSv[i] ) { + printf("Bug dans PNE_VariableProbingReinitDonnees 4\n"); + exit(0); + } + } +# endif + +/* Recuperation des contraintes */ +/* +memcpy( (char *) Prb->Bmin, (char *) Prb->BminSv, NombreDeContraintes * sizeof( double ) ); +memcpy( (char *) Prb->Bmax, (char *) Prb->BmaxSv, NombreDeContraintes * sizeof( double ) ); +*/ +NumeroDeContrainteModifiee = Prb->NumeroDeContrainteModifiee; +NbFoisContrainteModifiee = Prb->NbFoisContrainteModifiee; +Bmin = Prb->Bmin; +BminSv = Prb->BminSv; +Bmax = Prb->Bmax; +BmaxSv = Prb->BmaxSv; +for ( i = 0 ; i < Prb->NbContraintesModifiees ; i++ ) { + Cnt = NumeroDeContrainteModifiee[i]; + Bmin[Cnt] = BminSv[Cnt]; + Bmax[Cnt] = BmaxSv[Cnt]; + NbFoisContrainteModifiee[Cnt] = 0; +} +Prb->NbContraintesModifiees = 0; + +# if DEBUG == OUI_PNE + for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + if ( Bmin[i] != BminSv[i] ) { + printf("Bug dans PNE_VariableProbingReinitDonnees 5\n"); + exit(0); + } + if ( Bmax[i] != BmaxSv[i] ) { + printf("Bug dans PNE_VariableProbingReinitDonnees 6\n"); + exit(0); + } + } +# endif + +Prb->NombreDeVariablesFixees = 0; /* Sert a construire le graphe de conflit */ + +# if DEBUG == OUI_PNE + if ( Prb->NombreDeContraintesAAnalyser > 0 ) { + printf("Erreur dans PNE_VariableProbingReinitDonnees: NombreDeContraintesAAnalyser doit etre nul et vaut %d\n",Prb->NombreDeContraintesAAnalyser); + exit(0); + } + if ( Prb->NbCntCoupesDeProbing > 0 ) { + printf("Erreur dans PNE_VariableProbingReinitDonnees: NbCntCoupesDeProbing doit etre nul et vaut %d\n",Prb->NbCntCoupesDeProbing); + exit(0); + } + + for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( Prb->FlagCntCoupesDeProbing[Cnt] != 0 ) { + printf("Erreur dans PNE_VariableProbingReinitDonnees: FlagCntCoupesDeProbing[%d] doit etre nul\n",Cnt); + exit(0); + } + if ( Prb->ContrainteAAnalyser[Cnt] != NON_PNE ) { + printf("Erreur dans PNE_VariableProbingReinitDonnees: ContrainteAAnalyser[%d] doit etre nul egal a NON_PNE\n",Cnt); + exit(0); + } + } +# endif + +Prb->NombreDeContraintesAAnalyser = 0; +Prb->NbCntCoupesDeProbing = 0; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* On fait du variable probing en faisant du node presolve apres fixation + de variables */ +void PNE_VariableProbingPreparerInstanciation( PROBLEME_PNE * Pne, int Var, double ValeurDeVar ) +{ +int Edge; int Noeud; int Complement; int Nv; int Pivot; double * ValeurDeBorneSup; double * ValeurDeBorneInf; +char * BorneInfConnue; char * BorneSupConnue; int * First; int * Adjacent; int * Next; +char BorneMiseAJour; char UneVariableAEteFixee; + +BorneInfConnue = Pne->ProbingOuNodePresolve->BorneInfConnue; +BorneSupConnue = Pne->ProbingOuNodePresolve->BorneSupConnue; +ValeurDeBorneInf = Pne->ProbingOuNodePresolve->ValeurDeBorneInf; +ValeurDeBorneSup = Pne->ProbingOuNodePresolve->ValeurDeBorneSup; + +BorneMiseAJour = NON_PNE; + +PNE_InitListeDesContraintesAExaminer( Pne, Var, ValeurDeVar, BorneMiseAJour ); +if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + +if ( ValeurDeVar == 1 ) UneVariableAEteFixee = FIXE_AU_DEPART; +else if ( ValeurDeVar == 0 ) UneVariableAEteFixee = FIXE_AU_DEPART; +else { printf("BUG dans VariableProbingPreparerInstanciation\n"); return; } + +PNE_MajIndicateursDeBornes( Pne, ValeurDeBorneInf, ValeurDeBorneSup, BorneInfConnue, BorneSupConnue, + ValeurDeVar, Var, UneVariableAEteFixee, BorneMiseAJour ); + +/* On applique le conflict graph s'il existe */ +if ( Pne->ConflictGraph == NULL ) return; + +Pivot = Pne->ConflictGraph->Pivot; +First = Pne->ConflictGraph->First; +Adjacent = Pne->ConflictGraph->Adjacent; +Next = Pne->ConflictGraph->Next; + +if ( ValeurDeVar == 1.0 ) { Noeud = Var; Complement = Pivot + Var; } +else { Noeud = Pivot + Var; Complement = Var; } + +Edge = First[Noeud]; +while ( Edge >= 0 ) { + Nv = Adjacent[Edge]; + /* Attention a ne pas prendre le complement */ + if ( Nv == Complement ) goto NextEdge; + if ( Nv < Pivot ) { + Var = Nv; + /* On ne doit pas avoir U[Var] = 1.0 */ + if ( ValeurDeBorneInf[Var] > 0.0001 ) { Pne->ProbingOuNodePresolve->Faisabilite = NON_PNE; return; } + if ( ValeurDeBorneInf[Var] == ValeurDeBorneSup[Var] ) goto NextEdge; + ValeurDeVar = 0.0; + PNE_VariableProbingPreparerInstanciation( Pne, Var, ValeurDeVar ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + } + else { + /* La valeur borne inf est interdite pour la variable */ + /* On doit donc fixer la variable a Umax et fixer les voisins de ce noeud */ + Var = Nv - Pivot; + /* On ne doit pas avoir U[Var] = 0.0 */ + if ( ValeurDeBorneSup[Var] < 0.9999 ) { Pne->ProbingOuNodePresolve->Faisabilite = NON_PNE; return; } + if ( ValeurDeBorneInf[Var] == ValeurDeBorneSup[Var] ) goto NextEdge; + ValeurDeVar = 1.0; + PNE_VariableProbingPreparerInstanciation( Pne, Var, ValeurDeVar ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + } + NextEdge: + Edge = Next[Edge]; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_VariableProbingRazContraintesAAnalyser( PROBLEME_PNE * Pne, PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve ) +{ +int Cnt; int NombreDeContraintes; char * ContrainteAAnalyser; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +ContrainteAAnalyser = ProbingOuNodePresolve->ContrainteAAnalyser; +for ( Cnt = 0; Cnt < NombreDeContraintes ; Cnt++ ) { + ContrainteAAnalyser[Cnt] = NON_PNE; +} +ProbingOuNodePresolve->NombreDeContraintesAAnalyser = 0; +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_VariableProbingRazCoupesDeProbingPotentielles( PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve ) +{ +int Cnt; int i; int * NumCntCoupesDeProbing; char * FlagCntCoupesDeProbing; +NumCntCoupesDeProbing = ProbingOuNodePresolve->NumCntCoupesDeProbing; +FlagCntCoupesDeProbing = ProbingOuNodePresolve->FlagCntCoupesDeProbing; +for ( i = 0; i < ProbingOuNodePresolve->NbCntCoupesDeProbing ; i++ ) { + Cnt = NumCntCoupesDeProbing[i]; + FlagCntCoupesDeProbing[Cnt] = 0; +} +ProbingOuNodePresolve->NbCntCoupesDeProbing = 0; +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_VariableProbingFixerUneVariableInstanciee( PROBLEME_PNE * Pne, PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve, + int Var, double ValeurDeVar ) +{ +int NombreDeVariables; int NombreDeContraintes; int Noeud; char BorneMiseAJour; char UneVariableAEteFixee; + +if ( ValeurDeVar < 0 ) { + printf("Bug dans PNE_VariableProbingFixerUneVariableInstanciee:\n"); + printf(" -> on cherche a fixer la variable binaire %d a %e\n",Var,ValeurDeVar); + exit(0); +} + +ProbingOuNodePresolve->Faisabilite = OUI_PNE; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +/* Il faut tout reinitialiser car les indicateurs de contrainte modifiee ou de variable modifiee + peuvent ne pas etre en accord */ +memcpy( (char *) ProbingOuNodePresolve->BorneInfConnue, (char *) ProbingOuNodePresolve->BorneInfConnueSv, NombreDeVariables * sizeof( char ) ); +memcpy( (char *) ProbingOuNodePresolve->BorneSupConnue, (char *) ProbingOuNodePresolve->BorneSupConnueSv, NombreDeVariables * sizeof( char ) ); +memcpy( (char *) ProbingOuNodePresolve->ValeurDeBorneInf, (char *) ProbingOuNodePresolve->ValeurDeBorneInfSv, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) ProbingOuNodePresolve->ValeurDeBorneSup, (char *) ProbingOuNodePresolve->ValeurDeBorneSupSv, NombreDeVariables * sizeof( double ) ); + +memcpy( (char *) ProbingOuNodePresolve->Bmin, (char *) ProbingOuNodePresolve->BminSv, NombreDeContraintes * sizeof( double ) ); +memcpy( (char *) ProbingOuNodePresolve->Bmax, (char *) ProbingOuNodePresolve->BmaxSv, NombreDeContraintes * sizeof( double ) ); + +ProbingOuNodePresolve->NbVariablesModifiees = 0; +ProbingOuNodePresolve->NbContraintesModifiees = 0; +memset( (char *) ProbingOuNodePresolve->VariableModifiee , NON_PNE, NombreDeVariables * sizeof( char ) ); +memset( (int *) ProbingOuNodePresolve->NbFoisContrainteModifiee, 0, NombreDeContraintes * sizeof( int ) ); + +# if VERBOSE_VARIABLE_PROBING == 1 + printf("Instanciation de la variable %d a %e: Pas de solution\n",Var,ValeurDeVar); +# endif + +/* On peut fixer definitivement la variable */ +if ( Pne->ConflictGraph != NULL ) { + Noeud = -1; + if ( ValeurDeVar == Pne->UminTrav[Var] ) Noeud = Pne->ConflictGraph->Pivot + Var; + else if ( ValeurDeVar == Pne->UmaxTrav[Var] ) Noeud = Var; + else { + printf("Erreur dans PNE_VariableProbingFixerUneVariableInstanciee la valeur d instanciation de la variable %d n'est ni le min ni le max\n",Var); + } + if ( Noeud < 0 ) return; + + /* Mise a jour des indicateurs de variables a instancier a nouveau */ + PNE_ProbingMajFlagVariablesAInstancier( Pne, Var, ValeurDeVar ); + + PNE_ConflictGraphFixerLesNoeudsVoisinsDunNoeud( Pne, Noeud ); +} +else { + BorneMiseAJour = NON_PNE; + if ( ValeurDeVar == Pne->UminTrav[Var] ) UneVariableAEteFixee = FIXE_AU_DEPART; + else if ( ValeurDeVar == Pne->UmaxTrav[Var] ) UneVariableAEteFixee = FIXE_AU_DEPART; + else { + printf("Erreur dans PNE_VariableProbingFixerUneVariableInstanciee la valeur d instanciation de la variable %d n'est ni le min ni le max\n",Var); + return; + } + Pne->UminTrav[Var] = ValeurDeVar; + Pne->UmaxTrav[Var] = ValeurDeVar; + Pne->UTrav[Var] = ValeurDeVar; + + PNE_ProbingMajBminBmax( Pne, Var, ValeurDeVar, BorneMiseAJour ); + + PNE_MajIndicateursDeBornes( Pne, ProbingOuNodePresolve->ValeurDeBorneInf, ProbingOuNodePresolve->ValeurDeBorneSup, + ProbingOuNodePresolve->BorneInfConnue, ProbingOuNodePresolve->BorneSupConnue, + ValeurDeVar, Var, UneVariableAEteFixee, BorneMiseAJour ); +} + +PNE_VariableProbingSauvegardesDonnees( Pne ); + +/* La liste des contraintes a analyser peut ne pas etre entierement a l'etat initial dans ce cas */ +PNE_VariableProbingRazContraintesAAnalyser( Pne, ProbingOuNodePresolve ); + +/* La liste des coupes de probing potentielles peut ne pas etre entierement a l'etat initial dans ce cas */ +PNE_VariableProbingRazCoupesDeProbingPotentielles( ProbingOuNodePresolve ); + +return; +} + +/*----------------------------------------------------------------------------*/ +/* On fait du variable probing en faisant du node presolve apres fixation + de variables */ +void PNE_VariableProbing( PROBLEME_PNE * Pne ) +{ +int Cnt; int Var; double ValeurDeVar; char CodeRet; int NombreDeVariablesTrav; +int NombreDeContraintesTrav; double * UminTrav; double * UminTravSv; double * UmaxTrav; +double * UmaxTravSv; double * UTrav; int NbFix; char * BorneInfConnue; int NbEdges; +char * BorneSupConnue; double * ValeurDeBorneInf; double * ValeurDeBorneSup; +int * NumeroDeCoupeDeProbing; int i; double * Umin0; double * Umax0; int NbVarAInstancier; +int * NumVarAInstancier; PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; char FaireProbing; +char LaVariableDoitEtreFixee; double ValeurDeLaVariableAFixer; double DureeDuProbing; +int Iteration; int Nb; int NbTermesMatrice; int * NbTerm; double X; char * ContrainteAAnalyser; + +Umin0 = NULL; +Umax0 = NULL; + +FaireProbing = OUI_PNE; + +if ( Pne->ChainageTransposeeExploitable == NON_PNE ) PNE_ConstruireLeChainageDeLaTransposee( Pne ); + +DureeDuProbing = DUREE_DU_PROBING; + +if ( Pne->Controls != NULL ) { + /* Pas de variable probing s'il s'agit d'un sous probleme appele par le solveur lui-meme */ + if ( Pne->Controls->FaireDuVariableProbing == NON_PNE ) { + FaireProbing = NON_PNE; + } +} + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Probing on binaries and computing the conflict graph\n"); +} + +Pne->ArreterCliquesEtProbing = NON_PNE; +time( &(Pne->HeureDeCalendrierDebutCliquesEtProbing) ); + +NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; +NombreDeContraintesTrav = Pne->NombreDeContraintesTrav; + +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; +UTrav = Pne->UTrav; +NbTerm = Pne->NbTermTrav; + +/* Sauvegarde des bornes inf et sup des variables. Elles vont nous servir a identifier les variables + qu'on a pu fixer */ +Umin0 = (double *) malloc( NombreDeVariablesTrav * sizeof( double ) ); +if ( Umin0 == NULL ) goto Fin; +Umax0 = (double *) malloc( NombreDeVariablesTrav * sizeof( double ) ); +if ( Umax0 == NULL ) goto Fin; +memcpy( (char *) Umin0, (char *) UminTrav, NombreDeVariablesTrav * sizeof( double ) ); +memcpy( (char *) Umax0, (char *) UmaxTrav, NombreDeVariablesTrav * sizeof( double ) ); + +if ( Pne->ProbingOuNodePresolve == NULL ) { + PNE_ProbingNodePresolveAlloc( Pne, &CodeRet ); + if ( CodeRet == NON_PNE ) goto Fin;; +} +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; + +ProbingOuNodePresolve->NbParcours = 0; + +# if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + PNE_ProbingInitDetectionDesBornesVariables( Pne ); +# endif + +ProbingOuNodePresolve->VariableInstanciee = -1; + +ProbingOuNodePresolve->NombreDeVariablesFixeesDansLeProbing = 0; + +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; +ValeurDeBorneSup = ProbingOuNodePresolve->ValeurDeBorneSup; +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +BorneSupConnue = ProbingOuNodePresolve->BorneSupConnue; +NumeroDeCoupeDeProbing = ProbingOuNodePresolve->NumeroDeCoupeDeProbing; +NumVarAInstancier = ProbingOuNodePresolve->NumVarAInstancier; + +# if PROBING_JUSTE_APRES_LE_PRESOLVE == OUI_PNE + PNE_ProbingInitVariablesAInstancierApresLePresolve( Pne, ProbingOuNodePresolve ); +# else + PNE_ProbingInitVariablesAInstancier( Pne, ProbingOuNodePresolve ); +# endif +PNE_ProbingMajVariablesAInstancier( Pne, ProbingOuNodePresolve ); + +NbTermesMatrice = 0; +for ( Cnt = 0 ; Cnt < NombreDeContraintesTrav ; Cnt++ ) { + NumeroDeCoupeDeProbing[Cnt] = -1; + NbTermesMatrice += NbTerm[Cnt]; +} +X = NbTermesMatrice * NB_MAX_PARCOURS_MATRICE; +if ( X < 0 ) X = pow(2, ( 8 * sizeof( int ) ) - 1 ) - 1; + +Nb = (int) floor( pow(2, ( 8 * sizeof( int ) ) - 1 ) - 1 ); + +if ( (int) X < Nb ) ProbingOuNodePresolve->SeuilNbTermesMatrice = (int) X; +else ProbingOuNodePresolve->SeuilNbTermesMatrice = Nb; + +Iteration = 0; +DebutVariableProbing: + +Iteration++; + +ContrainteAAnalyser = ProbingOuNodePresolve->ContrainteAAnalyser; +for ( Cnt = 0; Cnt < NombreDeContraintesTrav ; Cnt++ ) { + ContrainteAAnalyser[Cnt] = NON_PNE; +} +ProbingOuNodePresolve->NombreDeContraintesAAnalyser = 0; + +ProbingOuNodePresolve->Faisabilite = OUI_PNE; + +PNE_InitBorneInfBorneSupDesVariables( Pne ); +PNE_CalculMinEtMaxDesContraintes( Pne, &(ProbingOuNodePresolve->Faisabilite) ); +if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + # if VERBOSE_VARIABLE_PROBING == 1 + printf("PNE_CalculMinEtMaxDesContraintes pas de solution\n"); + # endif + goto Fin; +} +PNE_VariableProbingSauvegardesDonnees( Pne ); + +/* Liste des variables a tester */ + +NbVarAInstancier = ProbingOuNodePresolve->NbVarAInstancier; +if ( Pne->AffichageDesTraces == OUI_PNE && 0 ) { + printf("Probing on %d variable(s)\n",ProbingOuNodePresolve->NbVarAInstancier); +} +for ( i = 0 ; i < NbVarAInstancier && FaireProbing == OUI_PNE ; i++ ) { + + if ( Pne->ConflictGraph != NULL ) { if ( Pne->ConflictGraph->NbEdges > 1000000 ) break; } + + if ( Pne->ArreterCliquesEtProbing == NON_PNE ) { + + time( &(Pne->HeureDeCalendrierCourantCliquesEtProbing) ); + Pne->TempsEcoule = difftime( Pne->HeureDeCalendrierCourantCliquesEtProbing, Pne->HeureDeCalendrierDebutCliquesEtProbing ); + if ( Pne->TempsEcoule > DureeDuProbing ) { + Pne->ArreterCliquesEtProbing = OUI_PNE; + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Probing was stopped. Timeout is %e elapsed is %e\n",DureeDuProbing,Pne->TempsEcoule); + } + } + } + if ( Pne->ArreterCliquesEtProbing == OUI_PNE ) break; + + Var = NumVarAInstancier[i]; + # if DEBUG == OUI_PNE + if ( Pne->TypeDeVariableTrav[Var] != ENTIER ) { + printf("Bug dans PNE_VariableProbing la variable a instancier %d n'est pas binaire\n",Var); + exit(0); + } + # endif + + LaVariableDoitEtreFixee = NON_PNE; + ValeurDeLaVariableAFixer = -1; + + /* Instanciation a 1 */ + PNE_VariableProbingReinitDonnees( Pne ); + + if ( BorneInfConnue[Var] == FIXE_AU_DEPART || BorneInfConnue[Var] == FIXATION_SUR_BORNE_INF || + BorneInfConnue[Var] == FIXATION_SUR_BORNE_SUP ) continue; + + ProbingOuNodePresolve->VariableInstanciee = Var; + ProbingOuNodePresolve->Faisabilite = OUI_PNE; + ValeurDeVar = 1.0; + ProbingOuNodePresolve->ValeurDeLaVariableInstanciee = ValeurDeVar; + PNE_VariableProbingPreparerInstanciation( Pne, Var, ValeurDeVar ); + + # if VERBOSE_VARIABLE_PROBING == 1 + printf("Instanciation de la variable %d a %e\n",Var,ValeurDeVar); + # endif + + NbEdges = 0; + if ( Pne->ConflictGraph != NULL ) NbEdges = Pne->ConflictGraph->NbEdges; + + # if VERBOSE_VARIABLE_PROBING == 1 + printf("Analyse de contraintes NombreDeContraintesAAnalyser %d\n", ProbingOuNodePresolve->NombreDeContraintesAAnalyser); + # endif + + PNE_AnalyseListeDeContraintes( Pne ); + + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + /* Pb infaisable si la variable vaut 1 => on la fixe a 0 */ + # if VERBOSE_VARIABLE_PROBING == 1 + printf(" La valeur n'est pas admissible, la variable doit etre fixee a 0\n"); + # endif + LaVariableDoitEtreFixee = OUI_PNE; + ValeurDeLaVariableAFixer = 0; + /* A ce stade la liste des variables et des contraintes modifiees est quand-meme correcte */ + /* La liste des contraintes a analyser peut ne pas etre entierement a l'etat initial dans ce cas */ + PNE_VariableProbingRazContraintesAAnalyser( Pne, ProbingOuNodePresolve ); + /* La liste des coupes de probing potentielles peut ne pas etre entierement a l'etat initial dans ce cas */ + PNE_VariableProbingRazCoupesDeProbingPotentielles( ProbingOuNodePresolve ); + } + else { + PNE_CreerLesCoupesDeProbing( Pne, ProbingOuNodePresolve ); + if ( ProbingOuNodePresolve->NombreDeVariablesFixees != 0 ) PNE_MajConflictGraph( Pne, Var, ValeurDeVar ); + /* Si des implications on ete crees (i.e. si le nombre de branches du graphe de conflit a ete augmente) + on met a jour la liste des variables qu'on testera au prochain coup */ + if ( Pne->ConflictGraph != NULL ) { + if ( Pne->ConflictGraph->NbEdges > NbEdges && MAJ_FLAG == OUI_PNE ) { + PNE_ProbingMajFlagVariablesAInstancier( Pne, Var, ValeurDeVar ); + } + } + # if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + if ( Iteration == 1 ) PNE_ProbingConstruireContraintesDeBornes( Pne, ProbingOuNodePresolve, Umin0, Umax0 ); + # endif + } + + /* Instanciation a 0 */ + PNE_VariableProbingReinitDonnees( Pne ); + + ProbingOuNodePresolve->VariableInstanciee = Var; + ProbingOuNodePresolve->Faisabilite = OUI_PNE; + ValeurDeVar = 0.0; + ProbingOuNodePresolve->ValeurDeLaVariableInstanciee = ValeurDeVar; + PNE_VariableProbingPreparerInstanciation( Pne, Var, ValeurDeVar ); + + # if VERBOSE_VARIABLE_PROBING == 1 + printf("Instanciation de la variable %d a %e\n",Var,ValeurDeVar); + # endif + + NbEdges = 0; + if ( Pne->ConflictGraph != NULL ) NbEdges = Pne->ConflictGraph->NbEdges; + + # if VERBOSE_VARIABLE_PROBING == 1 + printf("Analyse de contraintes NombreDeContraintesAAnalyser %d\n", ProbingOuNodePresolve->NombreDeContraintesAAnalyser); + # endif + + PNE_AnalyseListeDeContraintes( Pne ); + + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + if ( LaVariableDoitEtreFixee == OUI_PNE ) { + /* La valeur 1 n'etait deja pas admissible */ + ProbingOuNodePresolve->Faisabilite = NON_PNE; + goto Fin; + } + /* Pb infaisable si la variable vaut 0 => on la fixe a 1 */ + # if VERBOSE_VARIABLE_PROBING == 1 + printf(" La valeur n'est pas admissible, la variable doit etre fixee a 1\n"); + # endif + LaVariableDoitEtreFixee = OUI_PNE; + ValeurDeLaVariableAFixer = 1; + /* A ce stade la liste des variables et des contraintes modifiees est quand-meme correcte */ + /* La liste des contraintes a analyser peut ne pas etre entierement a l'etat initial dans ce cas */ + PNE_VariableProbingRazContraintesAAnalyser( Pne, ProbingOuNodePresolve ); + /* La liste des coupes de probing potentielles peut ne pas etre entierement a l'etat initial dans ce cas */ + PNE_VariableProbingRazCoupesDeProbingPotentielles( ProbingOuNodePresolve ); + } + else { + PNE_CreerLesCoupesDeProbing( Pne, ProbingOuNodePresolve ); + if ( ProbingOuNodePresolve->NombreDeVariablesFixees != 0 ) PNE_MajConflictGraph( Pne, Var, ValeurDeVar ); + /* Si des implications on ete crees (i.e. si le nombre de branches du graphe de conflit a ete augmente) + on met a jour la liste des variables qu'on testera au prochain coup */ + if ( Pne->ConflictGraph != NULL ) { + if ( Pne->ConflictGraph->NbEdges > NbEdges && MAJ_FLAG == OUI_PNE ) { + PNE_ProbingMajFlagVariablesAInstancier( Pne, Var, ValeurDeVar ); + } + } + # if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + if ( Iteration == 1 ) PNE_ProbingConstruireContraintesDeBornes( Pne, ProbingOuNodePresolve, Umin0, Umax0 ); + # endif + } + + /* Si la variable doit etre fixee on tient aussi compte du graphe de conflit */ + if ( LaVariableDoitEtreFixee == OUI_PNE ) { + PNE_VariableProbingFixerUneVariableInstanciee( Pne, ProbingOuNodePresolve, Var, ValeurDeLaVariableAFixer ); + if ( ProbingOuNodePresolve->Faisabilite == NON_PNE ) goto Fin; + } + +} + +PNE_ProbingMajVariablesAInstancier( Pne, ProbingOuNodePresolve ); +if ( ProbingOuNodePresolve->NbVarAInstancier > 0 ) { + /*printf("1- NbVarAInstancier %d\n",ProbingOuNodePresolve->NbVarAInstancier);*/ + goto DebutVariableProbing; +} + +if ( Pne->ConflictGraph != NULL ) { + # if VERBOSE_VARIABLE_PROBING == 1 + printf("Extend conflict graph\n"); + # endif + ProbingOuNodePresolve->Faisabilite = OUI_PNE; + PNE_VariableProbingReinitDonnees( Pne ); + + /* Si Cliques est plein on evite ExtendConflictGraph car c'est consommateur de temps de calcul */ + if ( Pne->Cliques == NULL ) PNE_ExtendConflictGraph( Pne ); + else if ( Pne->Cliques->Full != OUI_PNE ) PNE_ExtendConflictGraph( Pne ); + + PNE_ConflictGraphFixerVariables( Pne ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) { + /* Le probleme n'a pas de solution */ + goto Fin; + } + + PNE_ProbingMajVariablesAInstancier( Pne, ProbingOuNodePresolve ); + if ( ProbingOuNodePresolve->NbVarAInstancier > 0 ) { + /*printf("2- NbVarAInstancier %d\n",ProbingOuNodePresolve->NbVarAInstancier);*/ + goto DebutVariableProbing; + } + +} + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + if ( Pne->ConflictGraph != NULL ) { + if ( Pne->ConflictGraph->NbEdges > 0 ) printf("Conflict graph has %d edges\n",Pne->ConflictGraph->NbEdges); + else printf("Conflict graph is empty\n"); + } + else printf("Conflict graph is empty\n"); +} + +ProbingOuNodePresolve->Faisabilite = OUI_PNE; + +# if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + PNE_ProbingCloseDetectionDesBornesVariables( Pne ); +# endif + +/* Mettre a jour les Umin max sv */ + +UminTravSv = Pne->UminTravSv; +UmaxTravSv = Pne->UmaxTravSv; + +NbFix = 0; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Umin0[Var] == Umax0[Var] ) continue; + if ( UminTrav[Var] == UmaxTrav[Var] ) { + NbFix++; + # if PROBING_JUSTE_APRES_LE_PRESOLVE == OUI_PNE + Pne->TypeDeBorneTrav[Var] = VARIABLE_FIXE; + Pne->TypeDeVariableTrav[Var] = REEL; + UTrav[Var] = UminTrav[Var]; + UminTrav[Var] = Umin0[Var]; + UmaxTrav[Var] = Umax0[Var]; + # else + UminTravSv[Var] = UminTrav[Var]; + UmaxTravSv[Var] = UminTrav[Var]; + # endif + } +} +if ( Pne->AffichageDesTraces == OUI_PNE ) { + if ( NbFix > 0 ) printf("%d variable(s) fixed using probing techniques\n",NbFix); + # if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + if ( Pne->ContraintesDeBorneVariable != NULL ) { + if ( Pne->ContraintesDeBorneVariable->NombreDeContraintesDeBorne > 0 ) { + printf("Adding %d implicit variable bound constraint(s)\n",Pne->ContraintesDeBorneVariable->NombreDeContraintesDeBorne); + } + } + # endif +} + +ProbingOuNodePresolve->NombreDeVariablesFixeesDansLeProbing = NbFix; + +ProbingOuNodePresolve->VariableInstanciee = -1; + +/* En mode Probing apres le premier simplexe, il faut recalculer BmiSv BmasSv avec UminTravSv UmaxTravSv */ + +# if PROBING_JUSTE_APRES_LE_PRESOLVE == NON_PNE + if ( NbFix > 0 && 0 ) { + /* En mode probing juste apres le presolve le recalcul est inutile */ + /* En mode probing apres les simplexes du noeud racine le recalcul est inutile car: + - on met a jour UminSv et UmaxSv en fonction de Umin et Umax + - le node presolve au noeud racine se calcule a chaque fois un Bmin Bmax fonction de Umin Umax + qui sont toujours egaux au Umin Umax au noeud racine + */ + PNE_InitBorneInfBorneSupDesVariables( Pne ); + PNE_CalculMinEtMaxDesContraintes( Pne, &(ProbingOuNodePresolve->Faisabilite) ); + /* Et on sauvegarde le resultat comme point de depart pour les noeuds suibvants */ + memcpy( (char *) ProbingOuNodePresolve->BminSv, (char *) ProbingOuNodePresolve->Bmin, Pne->NombreDeContraintesTrav * sizeof( double ) ); + memcpy( (char *) ProbingOuNodePresolve->BmaxSv, (char *) ProbingOuNodePresolve->Bmax, Pne->NombreDeContraintesTrav * sizeof( double ) ); + } +# endif + +Fin: + +free( Umin0 ); +free( Umax0 ); + +if ( Pne->ProbingOuNodePresolve != NULL ) Pne->ProbingOuNodePresolve->VariableInstanciee = -1; + +return; +} + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_probing_analyse_liste_de_contraintes.c b/src/ext/Sirius_Solver/pne/pne_probing_analyse_liste_de_contraintes.c new file mode 100644 index 0000000000..1e769bb88f --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_probing_analyse_liste_de_contraintes.c @@ -0,0 +1,633 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Variable probing et node presolve + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define MAJ_BMIN 1 +# define MAJ_BMAX 2 +# define FORCING_BMIN 1 +# define FORCING_BMAX 2 +# define MAX_TERMES_CONTRAINTES_A_ANALYSER 10 +# define SEUIL_NOMBRE_DE_CONTRAINTES_POUR_MAX_TERMES 100000 + +void PNE_ProbingControleFaisabiliteSiMajBminOuBmax( PROBLEME_PNE * , char , char , double , char , double , char , double , int ); +void ControleBmin( PROBLEME_PNE * , int , double ); +void ControleBmax( PROBLEME_PNE * , int , double ); + +/*----------------------------------------------------------------------------------------------------*/ + +void PNE_ProbingControleFaisabiliteSiMajBminOuBmax( PROBLEME_PNE * Pne, char SensContrainte, + char BorneMiseAJour, double B, + char BminValide, double Bmin, + char BmaxValide, double Bmax, int Cnt ) +{ +if ( BminValide == OUI_PNE && BmaxValide == OUI_PNE ) { + if ( Bmin > Bmax + SEUIL_DADMISSIBILITE ) { + Pne->ProbingOuNodePresolve->Faisabilite = NON_PNE; + return; + } +} + +if ( BorneMiseAJour == MAJ_BMIN ) { + if ( Bmin > B + SEUIL_DADMISSIBILITE ) { + Pne->ProbingOuNodePresolve->Faisabilite = NON_PNE; + return; + } +} +else if ( BorneMiseAJour == MAJ_BMAX ) { + if ( SensContrainte == '=' ) { + if ( Bmax < B - SEUIL_DADMISSIBILITE ) { + Pne->ProbingOuNodePresolve->Faisabilite = NON_PNE; + return; + } + } + else { /* Contrainte < */ + if ( Bmax < B - SEUIL_DADMISSIBILITE ) { + if ( Pne->ProbingOuNodePresolve->VariableInstanciee < 0 ) return; + /* On va essayer une coupe de probing sur la contrainte */ + if ( Pne->ProbingOuNodePresolve->FlagCntCoupesDeProbing[Cnt] == 0 ) { + Pne->ProbingOuNodePresolve->NumCntCoupesDeProbing[Pne->ProbingOuNodePresolve->NbCntCoupesDeProbing] = Cnt; + Pne->ProbingOuNodePresolve->NbCntCoupesDeProbing++; + Pne->ProbingOuNodePresolve->FlagCntCoupesDeProbing[Cnt] = 1; + } + } + } +} +return; +} + +/*----------------------------------------------------------------------------------------------------*/ +void ControleBmin( PROBLEME_PNE * Pne, int Cnt, double Bmin ) +{ int il; int ilMax; double S; double * A; int * Mdeb; int * NbTerm; int * Nuvar; int Var; char BrnInfConnue; +char * BorneSupConnue; char * BorneInfConnue; double * ValeurDeBorneSup; double * ValeurDeBorneInf; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +A = Pne->ATrav; +Nuvar = Pne->NuvarTrav; +BorneSupConnue = Pne->ProbingOuNodePresolve->BorneSupConnue; +BorneInfConnue = Pne->ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneSup = Pne->ProbingOuNodePresolve->ValeurDeBorneSup; +ValeurDeBorneInf = Pne->ProbingOuNodePresolve->ValeurDeBorneInf; +S = 0; +il = Mdeb[Cnt]; +ilMax =il + NbTerm[Cnt]; +while ( il < ilMax) { + Var = Nuvar[il]; + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) { + S += A[il] * ValeurDeBorneInf[Var]; + } + else { + if ( A[il] > 0.0 ) S += A[il] * ValeurDeBorneInf[Var]; + else S += A[il] * ValeurDeBorneSup[Var]; + } + il++; +} +if ( fabs( S - Bmin ) > 1.e-8 && 0 ) { + printf("S %e Bmin %e Cnt %d NbFoisContrainteModifiee %d\n",S,Bmin,Cnt,Pne->ProbingOuNodePresolve->NbFoisContrainteModifiee[Cnt]); + Pne->ProbingOuNodePresolve->Bmin[Cnt] = S; + /*exit(0);*/ +} +return; +} +/*----------------------------------------------------------------------------------------------------*/ +void ControleBmax( PROBLEME_PNE * Pne, int Cnt, double Bmax ) +{ int il; int ilMax; double S; double * A; int * Mdeb; int * NbTerm; int * Nuvar; int Var; char BrnInfConnue; +char * BorneSupConnue; char * BorneInfConnue; double * ValeurDeBorneSup; double * ValeurDeBorneInf; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +A = Pne->ATrav; +Nuvar = Pne->NuvarTrav; +BorneSupConnue = Pne->ProbingOuNodePresolve->BorneSupConnue; +BorneInfConnue = Pne->ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneSup = Pne->ProbingOuNodePresolve->ValeurDeBorneSup; +ValeurDeBorneInf = Pne->ProbingOuNodePresolve->ValeurDeBorneInf; +S = 0; +il = Mdeb[Cnt]; +ilMax =il + NbTerm[Cnt]; +while ( il < ilMax) { + Var = Nuvar[il]; + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) { + S += A[il] * ValeurDeBorneInf[Var]; + } + else { + if ( A[il] > 0.0 ) S += A[il] * ValeurDeBorneSup[Var]; + else S += A[il] * ValeurDeBorneInf[Var]; + } + il++; +} +if ( fabs( S - Bmax ) > 1.e-8 && 0 ) { + printf("S %e Bmax %e Cnt %d NbFoisContrainteModifiee %d\n",S,Bmax,Cnt,Pne->ProbingOuNodePresolve->NbFoisContrainteModifiee[Cnt]); + Pne->ProbingOuNodePresolve->Bmax[Cnt] = S; + /*exit(0);*/ +} +return; +} + +/*----------------------------------------------------------------------------------------------------*/ + +void PNE_ProbingMajBminBmax( PROBLEME_PNE * Pne, int Var, double ValeurDeVar, char BorneMiseAJour ) +{ +int ic; int * Cdeb; int * Csui; int * NumContrainte; int Cnt; double * A; long double Ai; +char * BminValide; char * BmaxValide; double * Bmin; double * Bmax; long double ValeurDeBorneInf; +long double ValeurDeBorneSup; char * SensContrainte; long double X; long double ValDeVar; +double * B; int * NumeroDeContrainteModifiee; int * NbFoisContrainteModifiee; +char MajCnt; PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; +BminValide = ProbingOuNodePresolve->BminValide; +BmaxValide = ProbingOuNodePresolve->BmaxValide; +Bmin = ProbingOuNodePresolve->Bmin; +Bmax = ProbingOuNodePresolve->Bmax; +ValeurDeBorneInf = (long double) ProbingOuNodePresolve->ValeurDeBorneInf[Var]; +ValeurDeBorneSup = (long double) ProbingOuNodePresolve->ValeurDeBorneSup[Var]; +NumeroDeContrainteModifiee = ProbingOuNodePresolve->NumeroDeContrainteModifiee; +NbFoisContrainteModifiee = ProbingOuNodePresolve->NbFoisContrainteModifiee; +ValDeVar = (long double) ValeurDeVar; + +ic = Cdeb[Var]; +while ( ic >= 0 ) { + Ai = (long double) A[ic]; + Cnt = NumContrainte[ic]; + if ( BminValide[Cnt] == OUI_PNE ) { + MajCnt = NON_PNE; + if ( BorneMiseAJour == MODIF_BORNE_INF ) { + /* C'est une modification de borne inf : peut etre concentre en 1 seul test */ + if ( Ai > 0 ) { + /*ControleBmin( Pne, Cnt, Bmin[Cnt] );*/ + X = (long double) Bmin[Cnt]; + X += Ai * (-ValeurDeBorneInf +ValDeVar); + Bmin[Cnt] = (double) X; + MajCnt = OUI_PNE; + } + } + else if ( BorneMiseAJour == MODIF_BORNE_SUP ) { + /* C'est une modification de borne sup */ + if ( Ai < 0 ) { + /*ControleBmin( Pne, Cnt, Bmin[Cnt] );*/ + X = (long double) Bmin[Cnt]; + X += Ai * (-ValeurDeBorneSup +ValDeVar); + Bmin[Cnt] = (double) X; + MajCnt = OUI_PNE; + } + } + else { + /*ControleBmin( Pne, Cnt, Bmin[Cnt] );*/ + X = (long double) Bmin[Cnt]; + if ( Ai >= 0.0 ) X += Ai * (-ValeurDeBorneInf +ValDeVar); + else X += Ai * (-ValeurDeBorneSup +ValDeVar); + Bmin[Cnt] = (double) X; + MajCnt = OUI_PNE; + } + if ( MajCnt == OUI_PNE ) { + if ( NbFoisContrainteModifiee[Cnt] == 0 ) { + NumeroDeContrainteModifiee[ProbingOuNodePresolve->NbContraintesModifiees] = Cnt; + ProbingOuNodePresolve->NbContraintesModifiees++; + } + NbFoisContrainteModifiee[Cnt]++; + PNE_ProbingControleFaisabiliteSiMajBminOuBmax( Pne, SensContrainte[Cnt], MAJ_BMIN, B[Cnt], BminValide[Cnt], + Bmin[Cnt], BmaxValide[Cnt], Bmax[Cnt], Cnt ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + } + } + if ( BmaxValide[Cnt] == OUI_PNE ) { + MajCnt = NON_PNE; + if ( BorneMiseAJour == MODIF_BORNE_INF ) { + /* C'est une modification de borne inf */ + if ( Ai < 0 ) { + /*ControleBmax( Pne, Cnt, Bmax[Cnt] );*/ + X = (long double) Bmax[Cnt]; + X += Ai * (-ValeurDeBorneInf +ValDeVar); + Bmax[Cnt] = (double) X; + MajCnt = OUI_PNE; + } + } + else if ( BorneMiseAJour == MODIF_BORNE_SUP ) { + /* C'est une modification de borne sup */ + if ( Ai > 0 ) { + /*ControleBmax( Pne, Cnt, Bmax[Cnt] );*/ + X = (long double) Bmax[Cnt]; + X += Ai * (-ValeurDeBorneSup +ValDeVar); + Bmax[Cnt] = (double) X; + MajCnt = OUI_PNE; + } + } + else { + /*ControleBmax( Pne, Cnt, Bmax[Cnt] );*/ + X = (long double) Bmax[Cnt]; + if ( Ai >= 0.0 ) X += Ai * (-ValeurDeBorneSup +ValDeVar); + else X += Ai * (-ValeurDeBorneInf +ValDeVar); + Bmax[Cnt] = (double) X; + MajCnt = OUI_PNE; + } + if ( MajCnt == OUI_PNE ) { + if ( NbFoisContrainteModifiee[Cnt] == 0 ) { + NumeroDeContrainteModifiee[ProbingOuNodePresolve->NbContraintesModifiees] = Cnt; + ProbingOuNodePresolve->NbContraintesModifiees++; + } + NbFoisContrainteModifiee[Cnt]++; + PNE_ProbingControleFaisabiliteSiMajBminOuBmax( Pne, SensContrainte[Cnt], MAJ_BMAX, B[Cnt], BminValide[Cnt], + Bmin[Cnt], BmaxValide[Cnt], Bmax[Cnt], Cnt ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + } + } + ic = Csui[ic]; +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Si on fixe la variable Var a la valeur ValeurDeVar, on met a jour la liste + des contraintes a analyser (celles qui sont modifiees), les seconds membres + et leurs plages de variation */ +void PNE_InitListeDesContraintesAExaminer( PROBLEME_PNE * Pne, int Var, double ValeurDeVar, + char BorneMiseAJour ) +{ +int ic; int * Cdeb; int * Csui; int * NumContrainte; int Cnt; int NombreDeContraintesAAnalyser; +int * NumeroDeContrainteAAnalyser; char SensDeVariation; PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; +char * SensContrainte; double * A; char * BmaxValide; double * Bmax; double * B; char * ContrainteAAnalyser; +int NombreDeContraintes; int IndexLibreContraintesAAnalyser; int * NbTerm; + +PNE_ProbingMajBminBmax( Pne, Var, ValeurDeVar, BorneMiseAJour ); +if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + +if ( Pne->ProbingOuNodePresolve->VariableInstanciee < 0 ) return; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; + +NombreDeContraintesAAnalyser = ProbingOuNodePresolve->NombreDeContraintesAAnalyser; +NumeroDeContrainteAAnalyser = ProbingOuNodePresolve->NumeroDeContrainteAAnalyser; +ContrainteAAnalyser = ProbingOuNodePresolve->ContrainteAAnalyser; +IndexLibreContraintesAAnalyser = ProbingOuNodePresolve->IndexLibreContraintesAAnalyser; + +/* ValeurDeVar est le nouvelle valeur de la variable */ +SensDeVariation = '+'; /* On initialise le sens a "la variable augmente" */ +if ( ValeurDeVar < ProbingOuNodePresolve->ValeurDeBorneSup[Var] ) { + /* La variable decroit */ + SensDeVariation = '-'; +} + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +NbTerm = Pne->NbTermTrav; +SensContrainte = Pne->SensContrainteTrav; +A = Pne->ATrav; + +BmaxValide = ProbingOuNodePresolve->BmaxValide; +Bmax = ProbingOuNodePresolve->Bmax; +B = Pne->BTrav; + +ic = Cdeb[Var]; +while ( ic >= 0 ) { + Cnt = NumContrainte[ic]; + if ( NombreDeContraintes > SEUIL_NOMBRE_DE_CONTRAINTES_POUR_MAX_TERMES ) { + if ( NbTerm[Cnt] > MAX_TERMES_CONTRAINTES_A_ANALYSER ) goto NextIc; + } + if ( SensContrainte[Cnt] == '<' ) { + if ( BmaxValide[Cnt] == OUI_PNE ) { + if ( Bmax[Cnt] <= B[Cnt] + SEUIL_DADMISSIBILITE ) goto NextIc; + } + if ( A[ic] >= 0 ) { + if ( SensDeVariation == '-' ) goto NextIc; + } + else { + /* A est negatif */ + if ( SensDeVariation == '+' ) goto NextIc; + } + } + + if ( ContrainteAAnalyser[Cnt] == NON_PNE ) { + if ( NombreDeContraintesAAnalyser < NombreDeContraintes ) { + /* On l'ajoute a la liste */ + NumeroDeContrainteAAnalyser[NombreDeContraintesAAnalyser] = Cnt; + NombreDeContraintesAAnalyser++; + } + else { + /* Pour eviter les debordements de tables */ + if ( IndexLibreContraintesAAnalyser < NombreDeContraintes ) { + NumeroDeContrainteAAnalyser[IndexLibreContraintesAAnalyser] = Cnt; + IndexLibreContraintesAAnalyser++; + } + } + ContrainteAAnalyser[Cnt] = OUI_PNE; + } + + NextIc: + ic = Csui[ic]; +} + +ProbingOuNodePresolve->NombreDeContraintesAAnalyser = NombreDeContraintesAAnalyser; +ProbingOuNodePresolve->IndexLibreContraintesAAnalyser = IndexLibreContraintesAAnalyser; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_VariableProbingAppliquerLeConflictGraph( PROBLEME_PNE * Pne, int Var, double ValeurDeVar, + char BorneMiseAJour, char UneVariableAEteFixee ) +{ +int Edge; int Noeud; int Complement; int Nv; int Pivot; double * ValeurDeBorneSup; double * ValeurDeBorneInf; +char * BorneInfConnue; char * BorneSupConnue; int * First; int * Adjacent; int * Next; + +ValeurDeBorneInf = Pne->ProbingOuNodePresolve->ValeurDeBorneInf; +ValeurDeBorneSup = Pne->ProbingOuNodePresolve->ValeurDeBorneSup; +BorneInfConnue = Pne->ProbingOuNodePresolve->BorneInfConnue; +BorneSupConnue = Pne->ProbingOuNodePresolve->BorneSupConnue; + +PNE_InitListeDesContraintesAExaminer( Pne, Var, ValeurDeVar, BorneMiseAJour ); +if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + +PNE_MajIndicateursDeBornes( Pne, ValeurDeBorneInf, ValeurDeBorneSup, BorneInfConnue, BorneSupConnue, + ValeurDeVar, Var, UneVariableAEteFixee, BorneMiseAJour ); + +if ( Pne->TypeDeVariableTrav[Var] != ENTIER ) return; + +if ( Pne->ConflictGraph == NULL ) return; +Pivot = Pne->ConflictGraph->Pivot; + +BorneMiseAJour = NON_PNE; + +if ( ValeurDeVar == 1.0 ) { Noeud = Var; Complement = Pivot + Var; } +else { Noeud = Pivot + Var; Complement = Var; } + +First = Pne->ConflictGraph->First; +Adjacent = Pne->ConflictGraph->Adjacent; +Next = Pne->ConflictGraph->Next; + +Edge = First[Noeud]; +while ( Edge >= 0 ) { + Nv = Adjacent[Edge]; + /* Attention a ne pas prendre le complement */ + if ( Nv == Complement ) goto NextEdge; + if ( Nv < Pivot ) { + Var = Nv; + /* On ne doit pas avoir U[Var] = 1.0 */ + if ( ValeurDeBorneInf[Var] > 0.0001 ) { Pne->ProbingOuNodePresolve->Faisabilite = NON_PNE; return; } + if ( ValeurDeBorneInf[Var] == ValeurDeBorneSup[Var] ) goto NextEdge; + /* On place la variable dans la liste des implications */ + /* */ + ValeurDeVar = 0.0; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + /* */ + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, ValeurDeVar, BorneMiseAJour, UneVariableAEteFixee ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + } + else { + /* La valeur borne inf est interdite pour la variable */ + /* On doit donc fixer la variable a Umax et fixer les voisins de ce noeud */ + Var = Nv - Pivot; + /* On ne doit pas avoir U[Var] = 0.0 */ + if ( ValeurDeBorneSup[Var] < 0.9999 ) { Pne->ProbingOuNodePresolve->Faisabilite = NON_PNE; return; } + if ( ValeurDeBorneInf[Var] == ValeurDeBorneSup[Var] ) goto NextEdge; + /* On place la variable dans la liste des implications */ + /* */ + ValeurDeVar = 1.0; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + /* */ + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, ValeurDeVar, BorneMiseAJour, UneVariableAEteFixee ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + } + NextEdge: + Edge = Next[Edge]; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_AnalyseListeDeContraintes( PROBLEME_PNE * Pne ) +{ +int i; int Cnt; char XsValide; char XiValide; double Ai; +int il; int ilMax;int Var; char BorneMiseAJour; char UneVariableAEteFixee; +int * NumeroDeContrainteAAnalyser; int * Mdeb; int * NbTerm; double * A; int * Nuvar; +double Xi; double Xs; int NombreDeContraintesAAnalyser; int * TypeDeVariable; char * BorneInfConnue; +char * BorneSupConnue; char BrnInfConnue; double * ValeurDeBorneSup; double * ValeurDeBorneInf; +double BminNew; double BmaxNew; double S; char * SensContrainte; double NouvelleValeur; +char * BminValide; char * BmaxValide; double * Bmin; double * Bmax; double * B; int Nb; +char Flag; long double Xi0; long double Xs0; int NbParcours; int SeuilNbTermesMatrice; +char SensCnt; char BmnValide; char BmxValide; double Bmn; double Bmx; double BCnt; char ForcingContraint; +PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; char * ContrainteAAnalyser; + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; + +NbParcours = ProbingOuNodePresolve->NbParcours; +SeuilNbTermesMatrice = ProbingOuNodePresolve->SeuilNbTermesMatrice; +NombreDeContraintesAAnalyser = ProbingOuNodePresolve->NombreDeContraintesAAnalyser; +NumeroDeContrainteAAnalyser = ProbingOuNodePresolve->NumeroDeContrainteAAnalyser; +ContrainteAAnalyser = ProbingOuNodePresolve->ContrainteAAnalyser; +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +BorneSupConnue = ProbingOuNodePresolve->BorneSupConnue; +ValeurDeBorneSup = ProbingOuNodePresolve->ValeurDeBorneSup; +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; +BminValide = ProbingOuNodePresolve->BminValide; +BmaxValide = ProbingOuNodePresolve->BmaxValide; +Bmin = ProbingOuNodePresolve->Bmin; +Bmax = ProbingOuNodePresolve->Bmax; + +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +TypeDeVariable = Pne->TypeDeVariableTrav; + +/* Remarque: NombreDeContraintesAAnalyser peut varier en cours d'analyse parce qu'on peut etre amene a en ajouter. + C'est la raison pour laquelle il faut utiliser ProbingOuNodePresolve->NombreDeContraintesAAnalyser et + pas seulement NombreDeContraintesAAnalyser */ + +AnalyserListeDeContraintes: + +ProbingOuNodePresolve->IndexLibreContraintesAAnalyser = 0; + +for ( i = 0 ; i < ProbingOuNodePresolve->NombreDeContraintesAAnalyser ; i++ ) { + if ( NbParcours > SeuilNbTermesMatrice ) { + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Probing stopped after checking %d elements of the matrix (max is %d)\n",NbParcours,SeuilNbTermesMatrice); + } + Pne->ArreterCliquesEtProbing = OUI_PNE; + } + + Cnt = NumeroDeContrainteAAnalyser[i]; + /* On met tout de suite a non ContrainteAAnalyser */ + ContrainteAAnalyser[Cnt] = NON_PNE; + + /* Que si au moins une des 2 bornes de la contrainte est connue */ + /*if ( BminValide[Cnt] != OUI_PNE && BmaxValide[Cnt] != OUI_PNE ) continue;*/ + SensCnt = SensContrainte[Cnt]; + BmnValide = BminValide[Cnt]; + BmxValide = BmaxValide[Cnt]; + Bmn = Bmin[Cnt]; + Bmx = Bmax[Cnt]; + BCnt = B[Cnt]; + /* Deja fait dans le tri des contraintes a analyser */ + /* + if ( SensCnt == '<' ) { + if ( BmxValide == OUI_PNE ) { + if ( Bmx <= BCnt + SEUIL_DADMISSIBILITE ) continue; + } + } + */ + + ForcingContraint = PNE_DeterminerForcingConstraint( Pne, ProbingOuNodePresolve, Cnt, SensCnt, BmnValide, BmxValide, Bmn, Bmx, BCnt ); + if ( ForcingContraint == OUI_PNE ) continue; + + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + NbParcours += NbTerm[Cnt]; + Nb = 0; + Flag = 0; + while ( il < ilMax ) { + Ai = A[il]; + if ( Ai == 0.0 ) goto NextIl; + Var = Nuvar[il]; + BrnInfConnue = BorneInfConnue[Var]; + /* Dans le cas ou la variable a ete fixee, BorneInfConnue et BorneSupConnue ont la meme valeur */ + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) goto NextIl; + XsValide = NON_PNE; + XiValide = NON_PNE; + Nb++; + Xs = ValeurDeBorneSup[Var]; + Xi = ValeurDeBorneInf[Var]; + Xs0 = Xs; + Xi0 = Xi; + + UneVariableAEteFixee = NON_PNE; + BorneMiseAJour = NON_PNE; + + if ( SensCnt == '=' ) { + /* On regarde le min et le max */ + if ( BmnValide == OUI_PNE ) { + BminNew = Bmn; + if ( Ai > 0.0 ) BminNew -= Ai * Xi0; /* On avait pris le min */ + else BminNew -= Ai * Xs0; /* On avait pris le max */ + S = BCnt - BminNew; + if ( Ai > 0 ) { Xs = S / Ai; XsValide = OUI_PNE; } + else { Xi = -S / fabs( Ai ); XiValide = OUI_PNE; } + } + if ( BmxValide == OUI_PNE ) { + BmaxNew = Bmx; + if ( Ai > 0.0 ) BmaxNew -= Ai * Xs0; /* On avait pris le max */ + else BmaxNew -= Ai * Xi0; /* On avait pris le min */ + S = BCnt - BmaxNew; + if ( Ai > 0 ) { Xi = S / Ai; XiValide = OUI_PNE; } + else { Xs = -S / fabs( Ai ); XsValide = OUI_PNE; } + } + } + else { /* SensContrainte est '<' */ + /* On peut calculer un majorant */ + if ( BmnValide == OUI_PNE ) { + BminNew = Bmn; + if ( Ai > 0.0 ) BminNew -= Ai * Xi0; /* On avait pris le min */ + else BminNew -= Ai * Xs0; /* On avait pris le max */ + S = BCnt - BminNew; + if ( Ai > 0 ) { Xs = S / Ai; XsValide = OUI_PNE; } + else { Xi = -S / fabs( Ai ); XiValide = OUI_PNE; } + } + } + + /* Que si Xi ou Xs sont valides et si une des 2 bornes est plus petite ou plus grande */ + if ( XiValide != OUI_PNE && XsValide != OUI_PNE ) goto NextIl; + if ( Xi <= Xi0 && Xs >= Xs0 ) goto NextIl; + + PNE_ModifierLaBorneDUneVariable( Pne, Var, SensCnt, XsValide, (double) Xs, XiValide, (double) Xi, &NouvelleValeur, + &BorneMiseAJour, &UneVariableAEteFixee, + &(Pne->ProbingOuNodePresolve->Faisabilite) ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + + /* Si la variable a ete fixee on met a jour la liste des contraintes a examiner au prochain coup */ + if ( UneVariableAEteFixee != NON_PNE || BorneMiseAJour != NON_PNE ) { + Flag = 1; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + } + + NextIl: + il++; + } + + if ( Nb == 1 && Flag == 0 ) { + PNE_CalculXiXsContrainteAUneSeuleVariable( Pne, &Var, Cnt, Mdeb[Cnt], ilMax, A, Nuvar, BorneInfConnue, ValeurDeBorneInf, + &XiValide, &XsValide, &Xi, &Xs ); + if ( Var >= 0 ) { + UneVariableAEteFixee = NON_PNE; + BorneMiseAJour = NON_PNE; + PNE_ModifierLaBorneDUneVariable( Pne, Var, SensCnt, XsValide, (double) Xs, XiValide, (double) Xi, &NouvelleValeur, + &BorneMiseAJour, &UneVariableAEteFixee, + &(Pne->ProbingOuNodePresolve->Faisabilite) ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + + /* Si la variable a ete fixee on met a jour la liste des contraintes a examiner au prochain coup */ + if ( UneVariableAEteFixee != NON_PNE || BorneMiseAJour != NON_PNE ) { + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + } + } + } + +} + +if ( Pne->ProbingOuNodePresolve->Faisabilite == OUI_PNE ) { + if ( Pne->ArreterCliquesEtProbing == NON_PNE ) { + if ( ProbingOuNodePresolve->IndexLibreContraintesAAnalyser != 0 ) { + ProbingOuNodePresolve->NombreDeContraintesAAnalyser = ProbingOuNodePresolve->IndexLibreContraintesAAnalyser; + goto AnalyserListeDeContraintes; + } + } +} + +return; + +} + +/*----------------------------------------------------------------------------*/ + + diff --git a/src/ext/Sirius_Solver/pne/pne_probing_bornes_variables.c b/src/ext/Sirius_Solver/pne/pne_probing_bornes_variables.c new file mode 100644 index 0000000000..57e85473c9 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_probing_bornes_variables.c @@ -0,0 +1,499 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Detection des contraintes de borne variable pendant le + variable probing. + Soient y la variable binaire instanciee et x la variable + continue. On genere des contraintes de type/ + x <= xmax + (xmaxNew-xmax) * y si la borne change pour y = 1 + x <= xmaxNew + (xmax-xmaxNew) * y si la borne change pour y = 0 + x >= xmin + (xminNew-xmin) * y si la borne change pour y = 1 + x >= xminNew + (xmin-xminNew) * y si la borne change pour y = 0 + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define VERBOSE_CONTRAINTES_DE_BORNE NON_PNE + +# define MAX_CONTRAINTES_DE_BORNE_VARIABLE 50000 +# define EGALITE 0 +# define BORNE_SUP 1 +# define BORNE_INF 2 +# define MARGE 1 /*10*/ +# define MARGE_SUR_NOUVELLE_BORNE 0.e-9 /* Il vaut mieux mettre 0 car si le B vaut 0 ca fait un Epsilon qui perturbe le calcul */ +# define SEUIL_DE_REDUCTION_DE_PLAGE 0.1 /*0.5*/ + +# define SIZE_ALLOC_CONTRAINTES 1000 /* Nombre de contraintes allouees */ +# define SIZE_ALLOC_TERMES_CONTRAINTES (SIZE_ALLOC_CONTRAINTES*2) + +# if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + +void PNE_ProbingAllocContraintesDeBorneVariable( PROBLEME_PNE * ); +void PNE_AugmenterNombreDeContraintesDeBorneVariable( PROBLEME_PNE * ); +void PNE_AugmenterLaTailleDesContraintesDeBorneVariable( PROBLEME_PNE * ); +void PNE_ProbingEtablirContraineDeBornes( PROBLEME_PNE * , int , int , double , double , double , char ); + +/*----------------------------------------------------------------------------*/ +/* On cherche simplement a savoir s'il y a une contrainte de borne variable + sur la variable continue */ +void PNE_ProbingInitDetectionDesBornesVariables( PROBLEME_PNE * Pne ) +{ +int Cnt; int il; int ilMax; int Var; int NbBin; int NombreDeContraintes; int NbCont; +int VarCont; double CoeffCont; int * Mdeb; int * NbTerm; int NombreDeVariables; +int * Nuvar; int * TypeDeVariable; double * A; int * CntDeBorneSupVariable; +int * CntDeBorneInfVariable; char * SensContrainte; int * TypeDeBorne; double * Umin; +double * Umax; double * B; + +# if PROBING_JUSTE_APRES_LE_PRESOLVE == NON_PNE + return; +# endif + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; + +if ( Pne->CntDeBorneSupVariable == NULL ) { + Pne->CntDeBorneSupVariable = (int *) malloc( NombreDeVariables * sizeof( int ) ); + if ( Pne->CntDeBorneSupVariable == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_ProbingDetectionDesBornesVariables \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} +if ( Pne->CntDeBorneInfVariable == NULL ) { + Pne->CntDeBorneInfVariable = (int *) malloc( NombreDeVariables * sizeof( int ) ); + if ( Pne->CntDeBorneInfVariable == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_ProbingDetectionDesBornesVariables \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} + +CntDeBorneSupVariable = Pne->CntDeBorneSupVariable; +CntDeBorneInfVariable = Pne->CntDeBorneInfVariable; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { CntDeBorneSupVariable[Var] = -1; CntDeBorneInfVariable[Var] = -1; } + +SensContrainte = Pne->SensContrainteTrav; +NbTerm = Pne->NbTermTrav; +B = Pne->BTrav; +Mdeb = Pne->MdebTrav; +Nuvar = Pne->NuvarTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +Umin = Pne->UminTrav; +Umax = Pne->UmaxTrav; +A = Pne->ATrav; + +/* Marquage des variables continues soumises a une borne sup ou inf variable */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( SensContrainte[Cnt] != '<' ) continue; + if ( NbTerm[Cnt] != 2 ) continue; + NbCont = 0; + CoeffCont = 0.0; + NbBin = 0; + VarCont = -1; + il = Mdeb[Cnt]; + ilMax = il + 2; + while ( il < ilMax ) { + Var = Nuvar[il]; + if ( TypeDeBorne[Var] != VARIABLE_FIXE ) { + if ( TypeDeVariable[Var] == ENTIER ) { + NbBin++; + if ( NbBin > 1 ) break; + } + else { + NbCont++; + VarCont = Var; + CoeffCont = A[il]; + if ( NbCont > 1 ) break; + } + } + il++; + } + if ( NbCont == 1 && NbBin == 1 && VarCont != -1 ) { + /* C'est une contrainte de borne variable */ + if ( CoeffCont > 0.0 ) CntDeBorneSupVariable[VarCont] = Cnt; + else CntDeBorneInfVariable[VarCont] = Cnt; + } +} + +return; +} +/*----------------------------------------------------------------------------*/ +void PNE_ProbingCloseDetectionDesBornesVariables( PROBLEME_PNE * Pne ) +{ +# if PROBING_JUSTE_APRES_LE_PRESOLVE == NON_PNE + return; +# endif +free( Pne->CntDeBorneSupVariable ); +free( Pne->CntDeBorneInfVariable ); +Pne->CntDeBorneSupVariable = NULL; +Pne->CntDeBorneInfVariable = NULL; +return; +} + +/*----------------------------------------------------------------------------*/ +void PNE_ProbingAllocContraintesDeBorneVariable( PROBLEME_PNE * Pne ) +{ +CONTRAITES_DE_BORNE_VARIABLE * ContraintesDeBorneVariable; +ContraintesDeBorneVariable = (CONTRAITES_DE_BORNE_VARIABLE *) malloc( sizeof( CONTRAITES_DE_BORNE_VARIABLE ) ); +if ( ContraintesDeBorneVariable == NULL ) return; + +ContraintesDeBorneVariable->SecondMembre = (double *) malloc( SIZE_ALLOC_CONTRAINTES * sizeof( double ) ); +if ( ContraintesDeBorneVariable->SecondMembre == NULL ) { + return; +} +ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool = (char *) malloc( SIZE_ALLOC_CONTRAINTES * sizeof( char ) ); +if ( ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool == NULL ) { + free( ContraintesDeBorneVariable->SecondMembre ); + return; +} +ContraintesDeBorneVariable->First = (int *) malloc( SIZE_ALLOC_CONTRAINTES * sizeof( int ) ); +if ( ContraintesDeBorneVariable->First == NULL ) { + free( ContraintesDeBorneVariable->SecondMembre ); + free( ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool ); + return; +} +ContraintesDeBorneVariable->NombreDeContraintesDeBorneAlloue = SIZE_ALLOC_CONTRAINTES; + +ContraintesDeBorneVariable->Colonne = (int *) malloc( SIZE_ALLOC_TERMES_CONTRAINTES * sizeof( int ) ); +if ( ContraintesDeBorneVariable->Colonne == NULL ) { + free( ContraintesDeBorneVariable->SecondMembre ); + free( ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool ); + free( ContraintesDeBorneVariable->First ); + return; +} +ContraintesDeBorneVariable->Coefficient = (double *) malloc( SIZE_ALLOC_TERMES_CONTRAINTES * sizeof( double ) ); +if ( ContraintesDeBorneVariable->Coefficient == NULL ) { + free( ContraintesDeBorneVariable->SecondMembre ); + free( ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool ); + free( ContraintesDeBorneVariable->First ); + free( ContraintesDeBorneVariable->Colonne ); + return; +} +ContraintesDeBorneVariable->TailleContraintesDeBorneAllouee = SIZE_ALLOC_TERMES_CONTRAINTES; +ContraintesDeBorneVariable->IndexLibre = 0; +ContraintesDeBorneVariable->NombreDeContraintesDeBorne = 0; +ContraintesDeBorneVariable->Full = NON_PNE; +Pne->ContraintesDeBorneVariable = ContraintesDeBorneVariable; +return; +} +/*----------------------------------------------------------------------------*/ +void PNE_AugmenterNombreDeContraintesDeBorneVariable( PROBLEME_PNE * Pne ) +{ +CONTRAITES_DE_BORNE_VARIABLE * ContraintesDeBorneVariable; int Size; double * SecondMembre; +char * LaContrainteDeBorneVariableEstDansLePool; int * First; + +ContraintesDeBorneVariable = Pne->ContraintesDeBorneVariable; +Size = ContraintesDeBorneVariable->NombreDeContraintesDeBorne + SIZE_ALLOC_CONTRAINTES; +SecondMembre = (double *) realloc( ContraintesDeBorneVariable->SecondMembre, Size * sizeof( double ) ); +if ( SecondMembre == NULL ) { + ContraintesDeBorneVariable->Full = OUI_PNE; + return; +} +LaContrainteDeBorneVariableEstDansLePool = (char *) realloc( ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool, Size * sizeof( char ) ); +if ( LaContrainteDeBorneVariableEstDansLePool == NULL ) { + free( SecondMembre ); + ContraintesDeBorneVariable->Full = OUI_PNE; + return; +} +First = (int *) realloc( ContraintesDeBorneVariable->First, Size * sizeof( int ) ); +if ( First == NULL ) { + free( SecondMembre ); + free( LaContrainteDeBorneVariableEstDansLePool ); + ContraintesDeBorneVariable->Full = OUI_PNE; + return; +} +ContraintesDeBorneVariable->NombreDeContraintesDeBorneAlloue = Size; +ContraintesDeBorneVariable->SecondMembre = SecondMembre; +ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool = LaContrainteDeBorneVariableEstDansLePool; +ContraintesDeBorneVariable->First = First; +return; +} +/*----------------------------------------------------------------------------*/ +void PNE_AugmenterLaTailleDesContraintesDeBorneVariable( PROBLEME_PNE * Pne ) +{ +CONTRAITES_DE_BORNE_VARIABLE * ContraintesDeBorneVariable; int Size; int * Colonne; double * Coefficient; + +ContraintesDeBorneVariable = Pne->ContraintesDeBorneVariable; +Size = ContraintesDeBorneVariable->TailleContraintesDeBorneAllouee + SIZE_ALLOC_TERMES_CONTRAINTES; + +Colonne = (int *) realloc( ContraintesDeBorneVariable->Colonne, Size * sizeof( int ) ); +if ( Colonne == NULL ) { + ContraintesDeBorneVariable->Full = OUI_PNE; + return; +} +Coefficient = (double *) realloc( ContraintesDeBorneVariable->Coefficient, Size * sizeof( double ) ); +if ( Coefficient == NULL ) { + free( Colonne ); + ContraintesDeBorneVariable->Full = OUI_PNE; + return; +} +ContraintesDeBorneVariable->TailleContraintesDeBorneAllouee = Size; +ContraintesDeBorneVariable->Colonne = Colonne; +ContraintesDeBorneVariable->Coefficient = Coefficient; +return; +} +/*----------------------------------------------------------------------------*/ +void PNE_ProbingEtablirContraineDeBornes( PROBLEME_PNE * Pne, int Var, int VariableInstanciee, + double a0, double a, double b, char Borne ) +{ +CONTRAITES_DE_BORNE_VARIABLE * ContraintesDeBorneVariable; int il; int Cnt; +/* On regarde si la variable entiere servait deja a construite une contrainte de borne */ +if ( Borne == BORNE_SUP ) Cnt = Pne->CntDeBorneSupVariable[Var]; +else if ( Borne == BORNE_INF ) Cnt = Pne->CntDeBorneInfVariable[Var]; +else Cnt = -1; +if ( Cnt >= 0 ) { + il = Pne->MdebTrav[Cnt]; + if ( Pne->NuvarTrav[il] == VariableInstanciee || Pne->NuvarTrav[il+1] == VariableInstanciee ) return; +} +if ( Pne->ContraintesDeBorneVariable == NULL ) { + PNE_ProbingAllocContraintesDeBorneVariable( Pne ); + if ( Pne->ContraintesDeBorneVariable == NULL ) return; /* Saturation memoire */ +} + +ContraintesDeBorneVariable = Pne->ContraintesDeBorneVariable; + +/* Place suffisante pour les contraintes */ +if ( ContraintesDeBorneVariable->NombreDeContraintesDeBorne >= ContraintesDeBorneVariable->NombreDeContraintesDeBorneAlloue ) { + PNE_AugmenterNombreDeContraintesDeBorneVariable( Pne ); + if ( Pne->ContraintesDeBorneVariable == NULL ) return; + if ( ContraintesDeBorneVariable->Full == OUI_PNE ) return; +} +/* Place suffisante pour les termes */ +if ( ContraintesDeBorneVariable->IndexLibre + 2 >= ContraintesDeBorneVariable->TailleContraintesDeBorneAllouee ) { + PNE_AugmenterLaTailleDesContraintesDeBorneVariable( Pne ); + if ( Pne->ContraintesDeBorneVariable == NULL ) return; + if ( ContraintesDeBorneVariable->Full == OUI_PNE ) return; +} +il = ContraintesDeBorneVariable->IndexLibre; +ContraintesDeBorneVariable->First[ContraintesDeBorneVariable->NombreDeContraintesDeBorne] = il; +/* La variable continue en premier */ +ContraintesDeBorneVariable->Coefficient[il] = a0; +ContraintesDeBorneVariable->Colonne[il] = Var; +il++; +ContraintesDeBorneVariable->Coefficient[il] = a; +ContraintesDeBorneVariable->Colonne[il] = VariableInstanciee; +il++; +ContraintesDeBorneVariable->IndexLibre = il; +ContraintesDeBorneVariable->SecondMembre[ContraintesDeBorneVariable->NombreDeContraintesDeBorne] = b; +ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool[ContraintesDeBorneVariable->NombreDeContraintesDeBorne] = NON_PNE; +ContraintesDeBorneVariable->NombreDeContraintesDeBorne += 1; +return; +} +/*----------------------------------------------------------------------------*/ + +void PNE_ProbingConstruireContraintesDeBornes( PROBLEME_PNE * Pne, PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve, + double * Xmin0, double * Xmax0 ) +{ +int NombreDeVariables; int Var; int VariableInstanciee; double ValeurDeLaVariableInstanciee; +char * BorneInfConnue; int * TypeDeBorne; int * TypeDeVariable;double * ValeurDeBorneInf; +double * ValeurDeBorneSup; double a; double b; double a0; char Borne; char CreerUneContrainte; +double PlageInitiale; double PlageFinale; double Alpha; double PlusGrandTerme; double PlusPetitTerme; +double BorneSupCandidate; double BorneInfCandidate; char ContrainteCree; + +# if PROBING_JUSTE_APRES_LE_PRESOLVE == NON_PNE + return; +# endif + +if ( ProbingOuNodePresolve->VariableInstanciee < 0 ) return; + +if ( Pne->ContraintesDeBorneVariable != NULL ) { + if ( Pne->ContraintesDeBorneVariable->NombreDeContraintesDeBorne >= MAX_CONTRAINTES_DE_BORNE_VARIABLE ) return; +} + +VariableInstanciee = ProbingOuNodePresolve->VariableInstanciee; +ValeurDeLaVariableInstanciee = ProbingOuNodePresolve->ValeurDeLaVariableInstanciee; + +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; +ValeurDeBorneSup = ProbingOuNodePresolve->ValeurDeBorneSup; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; + +PlusGrandTerme = Pne->PlusGrandTerme; +PlusPetitTerme = Pne->PlusPetitTerme; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeVariable[Var] != REEL ) continue; + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) continue; + /* + printf("Variable continue %d xmin %e xmax %e\n",Var,ValeurDeBorneInf[Var],ValeurDeBorneSup[Var]); + */ + /* Recherche d'une egalite */ + if ( TypeDeBorne[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( ValeurDeBorneSup[Var] == ValeurDeBorneInf[Var] ) { + if ( ValeurDeBorneSup[Var] != Xmax0[Var] && ValeurDeBorneSup[Var] != Xmin0[Var] ) { + ContrainteCree = OUI_PNE; + Alpha = ValeurDeBorneSup[Var]; + Borne = EGALITE; + /* On cree 2 contraintes pour construire l'egalite a la valeur Alpha */ + /* Cas y = 1: + x <= xmax - (xmax-Alpha) * y i.e x + (xmax-Alpha) * y <= xmax + x >= xmin + (Alpha - xmin) * y i.e. -x + (Alpha - xmin) * y <= -xmin + Cas y = 0: + x - (xmax-Alpha) * y <= Alpha + -x - (Alpha - xmin) * y <= -Alpha */ + + a0 = 1; + if ( ValeurDeLaVariableInstanciee == 1 ) { a = Xmax0[Var] - Alpha; b = Xmax0[Var]; } + else if ( ValeurDeLaVariableInstanciee == 0 ) { a = -(Xmax0[Var] - Alpha); b = Alpha; } + else { + printf("Bug dans PNE_ProbingConstruireContraintesDeBornes ValeurDeLaVariableInstanciee %e\n",ValeurDeLaVariableInstanciee); + continue; + } + + if ( fabs( a ) >= PlusPetitTerme && fabs( a ) <= PlusGrandTerme ) { + Borne = EGALITE; + PNE_ProbingEtablirContraineDeBornes( Pne, Var, VariableInstanciee, a0, a, b, Borne ); + if ( Pne->ContraintesDeBorneVariable != NULL ) { + if ( Pne->ContraintesDeBorneVariable->NombreDeContraintesDeBorne >= MAX_CONTRAINTES_DE_BORNE_VARIABLE ) return; + } + } + else ContrainteCree = NON_PNE; + + a0 = -1; + if ( ValeurDeLaVariableInstanciee == 1 ) { a = Alpha - Xmin0[Var]; b = -Xmin0[Var]; } + else if ( ValeurDeLaVariableInstanciee == 0 ) { a = -(Alpha - Xmin0[Var]); b = -Alpha; } + else { + printf("Bug dans PNE_ProbingConstruireContraintesDeBornes ValeurDeLaVariableInstanciee %e\n",ValeurDeLaVariableInstanciee); + continue; + } + if ( fabs( a ) >= PlusPetitTerme && fabs( a ) <= PlusGrandTerme ) { + Borne = EGALITE; + PNE_ProbingEtablirContraineDeBornes( Pne, Var, VariableInstanciee, a0, a, b, Borne ); + if ( Pne->ContraintesDeBorneVariable != NULL ) { + if ( Pne->ContraintesDeBorneVariable->NombreDeContraintesDeBorne >= MAX_CONTRAINTES_DE_BORNE_VARIABLE ) return; + } + } + else ContrainteCree = NON_PNE; + + if ( ContrainteCree == OUI_PNE ) { + # if VERBOSE_CONTRAINTES_DE_BORNE == OUI_PNE + printf("Contrainte pour fixer la variable %d a %e (xmax: %e xmin: %e) si la variable entier %d passe a %e\n", + Var,Alpha,Xmax0[Var],Xmin0[Var],VariableInstanciee,ValeurDeLaVariableInstanciee); + # endif + continue; + } + + } + } + } + /* Recherche d'une borne sup */ + if ( TypeDeBorne[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorne[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + CreerUneContrainte = NON_PNE; + BorneSupCandidate = ValeurDeBorneSup[Var] + MARGE_SUR_NOUVELLE_BORNE; + if ( BorneSupCandidate < Xmax0[Var] - MARGE ) CreerUneContrainte = OUI_PNE; + if ( CreerUneContrainte == NON_PNE && TypeDeBorne[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + PlageInitiale = Xmax0[Var] - Xmin0[Var]; + PlageFinale = BorneSupCandidate - Xmin0[Var]; + if ( PlageFinale - PlageInitiale > SEUIL_DE_REDUCTION_DE_PLAGE * PlageInitiale ) CreerUneContrainte = OUI_PNE; + } + if ( CreerUneContrainte == OUI_PNE ) { + a0 = 1; + if ( ValeurDeLaVariableInstanciee == 1 ) { + b = Xmax0[Var]; + a = -(BorneSupCandidate - Xmax0[Var]); + } + else if ( ValeurDeLaVariableInstanciee == 0 ) { + b = BorneSupCandidate; + a = -(Xmax0[Var] - BorneSupCandidate); + } + else { + printf("Bug dans PNE_ProbingConstruireContraintesDeBornes ValeurDeLaVariableInstanciee %e\n",ValeurDeLaVariableInstanciee); + continue; + } + /* Pour ne pas trop detruire le conditionnement */ + if ( fabs( a ) < PlusPetitTerme || fabs( a ) > PlusGrandTerme ) CreerUneContrainte = NON_PNE; + if ( CreerUneContrainte == OUI_PNE ) { + # if VERBOSE_CONTRAINTES_DE_BORNE == OUI_PNE + printf("Contrainte de borne sup variable sur %d xmax: %e -> %e (xmin = %e) variable instancies %d a %e\n", + Var,Xmax0[Var],BorneSupCandidate,Xmin0[Var],VariableInstanciee,ValeurDeLaVariableInstanciee); + # endif + Borne = BORNE_SUP; + PNE_ProbingEtablirContraineDeBornes( Pne, Var, VariableInstanciee, a0, a, b, Borne ); + if ( Pne->ContraintesDeBorneVariable != NULL ) { + if ( Pne->ContraintesDeBorneVariable->NombreDeContraintesDeBorne >= MAX_CONTRAINTES_DE_BORNE_VARIABLE ) return; + } + } + } + } + /* Recherche d'une borne inf */ + if ( TypeDeBorne[Var] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorne[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + CreerUneContrainte = NON_PNE; + BorneInfCandidate = ValeurDeBorneInf[Var] - MARGE_SUR_NOUVELLE_BORNE; + if ( BorneInfCandidate > Xmin0[Var] + MARGE ) CreerUneContrainte = OUI_PNE; + if ( CreerUneContrainte == NON_PNE && TypeDeBorne[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + PlageInitiale = Xmax0[Var] - Xmin0[Var]; + PlageFinale = Xmax0[Var] - BorneInfCandidate; + if ( PlageFinale - PlageInitiale > SEUIL_DE_REDUCTION_DE_PLAGE * PlageInitiale ) CreerUneContrainte = OUI_PNE; + } + if ( CreerUneContrainte == OUI_PNE ) { + /* On regarde si la variable entiere servait deja a construite une contrainte de borne */ + a0 = -1; + if ( ValeurDeLaVariableInstanciee == 1 ) { + b = -Xmin0[Var]; + a = BorneInfCandidate - Xmin0[Var]; + } + else if ( ValeurDeLaVariableInstanciee == 0 ) { + b = -BorneInfCandidate; + a = Xmin0[Var] - BorneInfCandidate; + } + else { + printf("Bug dans PNE_ProbingConstruireContraintesDeBornes ValeurDeLaVariableInstanciee %e\n",ValeurDeLaVariableInstanciee); + continue; + } + /* Pour ne pas trop detruire le conditionnement */ + if ( fabs( a ) < PlusPetitTerme || fabs( a ) > PlusGrandTerme ) CreerUneContrainte = NON_PNE; + if ( CreerUneContrainte == OUI_PNE ) { + # if VERBOSE_CONTRAINTES_DE_BORNE == OUI_PNE + printf("Contrainte de borne inf variable sur %d xmin: %e -> %e (xmax = %e) variable instancies %d a %e\n", + Var,Xmin0[Var],BorneInfCandidate,Xmax0[Var],VariableInstanciee,ValeurDeLaVariableInstanciee); + # endif + Borne = BORNE_INF; + PNE_ProbingEtablirContraineDeBornes( Pne, Var, VariableInstanciee, a0, a, b, Borne ); + if ( Pne->ContraintesDeBorneVariable != NULL ) { + if ( Pne->ContraintesDeBorneVariable->NombreDeContraintesDeBorne >= MAX_CONTRAINTES_DE_BORNE_VARIABLE ) return; + } + } + } + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +# endif diff --git a/src/ext/Sirius_Solver/pne/pne_probing_modifier_matrice_des_contraintes.c b/src/ext/Sirius_Solver/pne/pne_probing_modifier_matrice_des_contraintes.c new file mode 100644 index 0000000000..2773b4d5eb --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_probing_modifier_matrice_des_contraintes.c @@ -0,0 +1,210 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On modifie la matrice des contraintes dans le cas ou le + probing a conduit a creer des coupes de probing. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_ProbingModifierLaMatriceDesContraintes( PROBLEME_PNE * Pne, PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve ) +{ +int il; int Cnt; int NumCoupe; int il0; int il0Max; int NombreDeContraintes; int Nb; +int * Mdeb0; int * NbTerm0; int * Nuvar0; int * Mdeb; int * NbTerm; int * Nuvar; int * First; +int * NbElements; int * Colonne; int * NumeroDeCoupeDeProbing; double Amn; double Amx; int ilMax; +double * B0; double * A0; double * B; double * A; double * SecondMembre; double * Coefficient; +char * Sens0; char * SensContrainte; COUPES_DE_PROBING * CoupesDeProbing; double a; +int NbCmod; + +CoupesDeProbing = Pne->CoupesDeProbing; +if ( CoupesDeProbing == NULL ) return; +if ( CoupesDeProbing->NombreDeCoupesDeProbing <= 0 ) return; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +Mdeb0 = Pne->MdebTrav; +NbTerm0 = Pne->NbTermTrav; +B0 = Pne->BTrav; +Sens0 = Pne->SensContrainteTrav; +Nuvar0 = Pne->NuvarTrav; +A0 = Pne->ATrav; + +if ( CoupesDeProbing->NombreDeCoupesDeProbing <= 0 ) return; + +First = CoupesDeProbing->First; +NbElements = CoupesDeProbing->NbElements; +SecondMembre = CoupesDeProbing->SecondMembre; +Colonne = CoupesDeProbing->Colonne; +Coefficient = CoupesDeProbing->Coefficient; + +NumeroDeCoupeDeProbing = ProbingOuNodePresolve->NumeroDeCoupeDeProbing; + +Mdeb = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +NbTerm = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +B = (double *) malloc( NombreDeContraintes * sizeof( double ) ); +SensContrainte = (char *) malloc( NombreDeContraintes * sizeof( char ) ); + +/* Determination de la nouvelle taille de la matrice des contraintes */ +il = 0; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( NumeroDeCoupeDeProbing[Cnt] < 0 ) il += NbTerm0[Cnt]; + else il += NbElements[NumeroDeCoupeDeProbing[Cnt]]; + il += MARGE_EN_FIN_DE_CONTRAINTE; +} + +Nuvar = (int *) malloc( il * sizeof( int ) ); +A = (double *) malloc( il * sizeof( double ) ); + +Pne->TailleAlloueePourLaMatriceDesContraintes = il; + +if ( Mdeb == NULL || NbTerm == NULL || B == NULL || + SensContrainte == NULL || Nuvar == NULL || A == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_ProbingModifierLaMatriceDesContraintes \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} + +/* Reconstruction de la matrice des contraintes */ +NbCmod = 0; +il = 0; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + Mdeb[Cnt] = il; + SensContrainte[Cnt] = Sens0[Cnt]; + Nb = 0; + if ( NumeroDeCoupeDeProbing[Cnt] < 0 ) { + B[Cnt] = B0[Cnt]; + il0 = Mdeb0[Cnt]; + il0Max = il0 + NbTerm0[Cnt]; + while ( il0 < il0Max) { + if ( A0[il0] != 0.0 ) { + A [il] = A0[il0]; + Nuvar[il] = Nuvar0[il0]; + Nb++; + il++; + } + il0++; + } + } + else { + /* On remplace la contrainte par la coupe de probing */ + NumCoupe = NumeroDeCoupeDeProbing[Cnt]; + NbCmod++; + B[Cnt] = SecondMembre[NumCoupe]; + il0 = First[NumCoupe]; + if ( il0 < 0 ) { + printf("Bug dans PNE_ProbingModifierLaMatriceDesContraintes\n"); + exit(0); + } + il0Max = il0 + NbElements[NumCoupe]; + while ( il0 < il0Max ) { + if ( Coefficient[il0] != 0.0 ) { + A [il] = Coefficient[il0]; + Nuvar[il] = Colonne[il0]; + Nb++; + il++; + } + il0++; + } + } + + for ( il0 = 0 ; il0 < MARGE_EN_FIN_DE_CONTRAINTE ; il0++ ) { + A[il] = 0.0; + il++; + } + + NbTerm[Cnt] = Nb; + +} + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + if ( NbCmod > 0 ) printf("Contraints matrix was modified %d time(s) due to probing constraints\n",NbCmod); +} + +Pne->ChainageTransposeeExploitable = NON_PNE; + +Amn = LINFINI_PNE; +Amx = -LINFINI_PNE; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + a = fabs ( A[il] ); + if ( a > 0 ) { + if ( a < Amn ) Amn = a; + else if ( a > Amx ) Amx = a; + } + il++; + } +} +Pne->PlusGrandTerme = Amx; +Pne->PlusPetitTerme = Amn; + +Pne->MdebTrav = Mdeb; +Pne->NbTermTrav = NbTerm; +Pne->BTrav = B; +Pne->SensContrainteTrav = SensContrainte; +Pne->NuvarTrav = Nuvar; +Pne->ATrav = A; + +free( Mdeb0 ); +free( NbTerm0 ); +free( B0 ); +free( Sens0 ); +free( Nuvar0 ); +free( A0 ); + +free( Pne->CsuiTrav ); +free( Pne->NumContrainteTrav ); +Pne->CsuiTrav = (int *) malloc( Pne->TailleAlloueePourLaMatriceDesContraintes * sizeof( int ) ); +Pne->NumContrainteTrav = (int *) malloc( Pne->TailleAlloueePourLaMatriceDesContraintes * sizeof( int ) ); + +/* Liberation des coupes de probing */ +if ( CoupesDeProbing != NULL ) { + free( CoupesDeProbing->SecondMembre ); + CoupesDeProbing->SecondMembre = NULL; + free( CoupesDeProbing->First ); + CoupesDeProbing->First = NULL; + free( CoupesDeProbing->NbElements ); + CoupesDeProbing->NbElements = NULL; + free( CoupesDeProbing->Colonne ); + CoupesDeProbing->Colonne = NULL; + free( CoupesDeProbing->Coefficient ); + CoupesDeProbing->Coefficient = NULL; + free( CoupesDeProbing->LaCoupDeProbingEstDansLePool ); + CoupesDeProbing->LaCoupDeProbingEstDansLePool = NULL; + free( Pne->CoupesDeProbing ); + Pne->CoupesDeProbing = NULL; +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_probing_nodepresolve_alloc.c b/src/ext/Sirius_Solver/pne/pne_probing_nodepresolve_alloc.c new file mode 100644 index 0000000000..38e81ef667 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_probing_nodepresolve_alloc.c @@ -0,0 +1,194 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On etudie les domaines de variation des variables entieres + dans le but d'en fixer. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_ProbingNodePresolveAlloc( PROBLEME_PNE * Pne, char * CodeRet ) +{ +int il; int NombreDeVariables; int NombreDeContraintes; char * Buffer; + +PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; + +*CodeRet = OUI_PNE; + +ProbingOuNodePresolve = (PROBING_OU_NODE_PRESOLVE *) malloc( sizeof( PROBING_OU_NODE_PRESOLVE ) ); +if ( ProbingOuNodePresolve == NULL ) { + *CodeRet = NON_PNE; + return; +} +Pne->ProbingOuNodePresolve = ProbingOuNodePresolve; +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +il = 0; + +/* Zone de travail */ +il += NombreDeVariables * sizeof( char ); /* BorneInfConnue */ +il += NombreDeVariables * sizeof( char ); /* BorneSupConnue */ +il += NombreDeVariables * sizeof( double ); /* ValeurDeBorneInf */ +il += NombreDeVariables * sizeof( double ); /* ValeurDeBorneSup */ +il += NombreDeContraintes * sizeof( double ); /* Bmin */ +il += NombreDeContraintes * sizeof( double ); /* Bmax */ +/* Zone de sauvegarde */ +il += NombreDeVariables * sizeof( char ); /* BorneInfConnueSv */ +il += NombreDeVariables * sizeof( char ); /* BorneSupConnueSv */ +il += NombreDeVariables * sizeof( double ); /* ValeurDeBorneInfSv */ +il += NombreDeVariables * sizeof( double ); /* ValeurDeBorneSupSv */ +il += NombreDeContraintes * sizeof( double ); /* BminSv */ +il += NombreDeContraintes * sizeof( double ); /* BmaxSv */ + +il += NombreDeVariables * sizeof( int );/* NumeroDeVariableModifiee */ +il += NombreDeVariables * sizeof( char );/* VariableModifiee */ + +il += NombreDeContraintes * sizeof( int );/* NumeroDeContrainteModifiee */ +il += NombreDeContraintes * sizeof( int );/* NbFoisContrainteModifiee */ + +il += NombreDeContraintes * sizeof( int ); /* NumeroDeContrainteAAnalyser */ +il += NombreDeContraintes * sizeof( char ); /* ContrainteAAnalyser */ + +/*il += NombreDeContraintes * sizeof( int );*/ /* IndexContrainteAAnalyser */ +/*il += NombreDeContraintes * sizeof( int );*/ /* Next_NumeroDeContrainteAAnalyser */ +/*il += NombreDeContraintes * sizeof( int );*/ /* Next_IndexContrainteAAnalyser */ + +il += NombreDeContraintes * sizeof( char ); /* BminValide */ +il += NombreDeContraintes * sizeof( char ); /* BmaxValide */ + +il += NombreDeVariables * sizeof( int ); /* NumeroDesVariablesFixees */ + +il += NombreDeContraintes * sizeof( int ); /* NumeroDeCoupeDeProbing */ + +il += NombreDeContraintes * sizeof( int ); /* NumCntCoupesDeProbing */ +il += NombreDeContraintes * sizeof( char ); /* FlagCntCoupesDeProbing */ + +il += NombreDeVariables * sizeof( int ); /* NumVarAInstancier */ +il += NombreDeVariables * sizeof( char ); /* FlagVarAInstancier */ + +Buffer = (char *) malloc( il ); +if ( Buffer == NULL ) { + free( Pne->ProbingOuNodePresolve ); + Pne->ProbingOuNodePresolve = NULL; + *CodeRet = NON_PNE; + return; +} +ProbingOuNodePresolve->Buffer = Buffer; + +il = 0; +/* Zone de travail */ +ProbingOuNodePresolve->BorneInfConnue = (char *) (&Buffer[il]); +il += NombreDeVariables * sizeof( char ); +ProbingOuNodePresolve->BorneSupConnue = (char *) (&Buffer[il]); +il += NombreDeVariables * sizeof( char ); +ProbingOuNodePresolve->ValeurDeBorneInf = (double *) (&Buffer[il]); +il += NombreDeVariables * sizeof( double ); +ProbingOuNodePresolve->ValeurDeBorneSup = (double *) (&Buffer[il]); +il += NombreDeVariables * sizeof( double ); +ProbingOuNodePresolve->Bmin = (double *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( double ); +ProbingOuNodePresolve->Bmax = (double *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( double ); + +/* Zone de sauvegarde */ +ProbingOuNodePresolve->BorneInfConnueSv = (char *) (&Buffer[il]); +il += NombreDeVariables * sizeof( char ); +ProbingOuNodePresolve->BorneSupConnueSv = (char *) (&Buffer[il]); +il += NombreDeVariables * sizeof( char ); +ProbingOuNodePresolve->ValeurDeBorneInfSv = (double *) (&Buffer[il]); +il += NombreDeVariables * sizeof( double ); +ProbingOuNodePresolve->ValeurDeBorneSupSv = (double *) (&Buffer[il]); +il += NombreDeVariables * sizeof( double ); +ProbingOuNodePresolve->BminSv = (double *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( double ); +ProbingOuNodePresolve->BmaxSv = (double *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( double ); + +ProbingOuNodePresolve->NumeroDeVariableModifiee = (int *) (&Buffer[il]); +il += NombreDeVariables * sizeof( int ); +ProbingOuNodePresolve->VariableModifiee = (char *) (&Buffer[il]); +il += NombreDeVariables * sizeof( char ); +ProbingOuNodePresolve->NumeroDeContrainteModifiee = (int *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( int ); +ProbingOuNodePresolve->NbFoisContrainteModifiee = (int *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( int ); + +ProbingOuNodePresolve->NumeroDeContrainteAAnalyser = (int *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( int ); +ProbingOuNodePresolve->ContrainteAAnalyser = (char *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( char ); + +/* +ProbingOuNodePresolve->IndexContrainteAAnalyser = (int *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( int ); +ProbingOuNodePresolve->Next_NumeroDeContrainteAAnalyser = (int *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( int ); +ProbingOuNodePresolve->Next_IndexContrainteAAnalyser = (int *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( int ); +*/ + +ProbingOuNodePresolve->BminValide = (char *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( char ); +ProbingOuNodePresolve->BmaxValide = (char *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( char ); + +ProbingOuNodePresolve->NumeroDesVariablesFixees = (int *) (&Buffer[il]); +il += NombreDeVariables * sizeof( int ); + +ProbingOuNodePresolve->NumeroDeCoupeDeProbing = (int *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( int ); + +ProbingOuNodePresolve->NumCntCoupesDeProbing = (int *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( int ); +ProbingOuNodePresolve->FlagCntCoupesDeProbing = (char *) (&Buffer[il]); +il += NombreDeContraintes * sizeof( char ); + +ProbingOuNodePresolve->NumVarAInstancier = (int *) (&Buffer[il]); +il += NombreDeVariables * sizeof( int ); +ProbingOuNodePresolve->FlagVarAInstancier = (char *) (&Buffer[il]); +il += NombreDeVariables * sizeof( char ); + +memset( (char *) ProbingOuNodePresolve->BminValide, VALIDITE_A_DETERMINER, NombreDeContraintes * sizeof( char ) ); +memset( (char *) ProbingOuNodePresolve->BmaxValide, VALIDITE_A_DETERMINER, NombreDeContraintes * sizeof( char ) ); + +Pne->ProbingOuNodePresolve->Faisabilite = OUI_PNE; + +ProbingOuNodePresolve->NbCntCoupesDeProbing = 0; +memset( (char *) ProbingOuNodePresolve->FlagCntCoupesDeProbing, 0, NombreDeContraintes * sizeof( char ) ); + +return; +} + +/*----------------------------------------------------------------------------*/ + diff --git a/src/ext/Sirius_Solver/pne/pne_probing_nodepresolve_utilitaires.c b/src/ext/Sirius_Solver/pne/pne_probing_nodepresolve_utilitaires.c new file mode 100644 index 0000000000..5c2d8d9155 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_probing_nodepresolve_utilitaires.c @@ -0,0 +1,887 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On etudie les domaines de variation des variables entieres + dans le but d'en fixer. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define VERBOSE_FIXATIONS_DE_VARIABLES NON_PNE +# define ZERO 1.e-10 + +# define EPSILON_FORCING_CONSTRAINT 1.e-8 /*1.e-7*/ +# define FORCING_BMIN 1 +# define FORCING_BMAX 2 +# define PAS_DE_FORCING 128 + +/*----------------------------------------------------------------------------*/ + +void PNE_CalculMinEtMaxDesContraintes( PROBLEME_PNE * Pne, int * Faisabilite ) +{ +double A; int il; int ilMax; int Var; char MinValide; char MaxValide; int * MdebTrav; +int * NbTermTrav; int * NuvarTrav; double * ATrav; double Smin; int Nb; +double Smax; int NombreDeContraintesTrav; double * Bmin; double * Bmax; char * BminValide; +char * BmaxValide; double * ValeurDeBorneInf; double * ValeurDeBorneSup; char * BorneSupConnue; +char * BorneInfConnue; int Cnt; char BrnInfConnue; char BrnSupConnue; double * B; +char * SensContrainte; int ilDeb; + +*Faisabilite = OUI_PNE; +BminValide = Pne->ProbingOuNodePresolve->BminValide; +Bmin = Pne->ProbingOuNodePresolve->Bmin; +BmaxValide = Pne->ProbingOuNodePresolve->BmaxValide; +Bmax = Pne->ProbingOuNodePresolve->Bmax; +BorneSupConnue = Pne->ProbingOuNodePresolve->BorneSupConnue; +BorneInfConnue = Pne->ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInf = Pne->ProbingOuNodePresolve->ValeurDeBorneInf; +ValeurDeBorneSup = Pne->ProbingOuNodePresolve->ValeurDeBorneSup; + +Smin = 0.0; +Smax = 0.0; +MinValide = OUI_PNE; +MaxValide = OUI_PNE; + +NombreDeContraintesTrav = Pne->NombreDeContraintesTrav; +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +ATrav = Pne->ATrav; +NuvarTrav = Pne->NuvarTrav; +B = Pne->BTrav; +SensContrainte = Pne->SensContrainteTrav; + +for ( Cnt = 0 ; Cnt < NombreDeContraintesTrav ; Cnt++ ) { + MinValide = OUI_PNE; + MaxValide = OUI_PNE; + Smin = 0.0; + Smax = 0.0; + Nb = 0; + ilDeb = MdebTrav[Cnt]; + ilMax = ilDeb + NbTermTrav[Cnt]; + il = ilDeb; + while ( il < ilMax ) { + Var = NuvarTrav[il]; + A = ATrav[il]; + if ( A == 0.0 ) goto NextElement; + BrnInfConnue = BorneInfConnue[Var]; + BrnSupConnue = BorneSupConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) { + Smin += A * ValeurDeBorneInf[Var]; + Smax += A * ValeurDeBorneInf[Var]; + goto NextElement; + } + Nb++; + if ( A > 0.0 ) { + /* Calcul de min */ + if ( BrnInfConnue == OUI_PNE && MinValide != NON_PNE ) Smin += A * ValeurDeBorneInf[Var]; + else { + MinValide = NON_PNE; + if ( MaxValide == NON_PNE ) goto ConclusionValiditeBminBmax; + } + /* Calcul de max */ + if ( BrnSupConnue == OUI_PNE && MaxValide != NON_PNE ) Smax += A * ValeurDeBorneSup[Var]; + else { + MaxValide = NON_PNE; + if ( MinValide == NON_PNE ) goto ConclusionValiditeBminBmax; + } + } + else { + /* Calcul de min */ + if ( BrnSupConnue == OUI_PNE && MinValide != NON_PNE ) Smin += A * ValeurDeBorneSup[Var]; + else { + MinValide = NON_PNE; + if ( MaxValide == NON_PNE ) goto ConclusionValiditeBminBmax; + } + /* Calcul de max */ + if ( BrnInfConnue == OUI_PNE && MaxValide != NON_PNE ) Smax += A * ValeurDeBorneInf[Var]; + else { + MaxValide = NON_PNE; + if ( MinValide == NON_PNE ) goto ConclusionValiditeBminBmax; + } + } + NextElement: + il++; + } + ConclusionValiditeBminBmax: + + Bmin[Cnt] = Smin; + Bmax[Cnt] = Smax; + BminValide[Cnt] = MinValide; + BmaxValide[Cnt] = MaxValide; + + if ( Nb == 0 ) { + if ( SensContrainte[Cnt] == '<' ) { + /* On verifie que la contrainte est satisfaite */ + if ( Smin > B[Cnt] + SEUIL_DADMISSIBILITE && MinValide == OUI_PNE ) { + *Faisabilite = NON_PNE; + return; + } + } + else { + /* Contrainte d'egalite */ + if ( ( fabs( Smax - Smin ) > SEUIL_DADMISSIBILITE && MaxValide == OUI_PNE && MinValide == OUI_PNE ) || + ( fabs( Smax - B[Cnt] ) > SEUIL_DADMISSIBILITE && MaxValide == OUI_PNE ) ) { + *Faisabilite = NON_PNE; + return; + } + } + } + else { + if ( SensContrainte[Cnt] == '<' ) { + if ( MinValide == OUI_PNE && Smin > B[Cnt] + SEUIL_DADMISSIBILITE ) { + *Faisabilite = NON_PNE; + return; + } + } + else { + /* Contrainte d'egalite */ + if ( MaxValide == OUI_PNE && Smax < B[Cnt] - SEUIL_DADMISSIBILITE ) { + *Faisabilite = NON_PNE; + return; + } + if ( MinValide == OUI_PNE && Smin > B[Cnt] + SEUIL_DADMISSIBILITE ) { + *Faisabilite = NON_PNE; + return; + } + } + } + +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +char PNE_DeterminerForcingConstraint( PROBLEME_PNE * Pne, PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve, + int Cnt, char SensCnt, char BmnValide, char BmxValide, + double Bmn, double Bmx, double BCnt ) +{ +char TypeDeForcing; int il; int ilMax; int Var; int * Mdeb; int * NbTerm; int * Nuvar; +double * A; double Ai; char * BorneInfConnue; char * BorneSupConnue; char BrnInfConnue; +double * ValeurDeBorneInf; double * ValeurDeBorneSup; char BorneMiseAJour; +char UneVariableAEteFixee; double NouvelleValeur; int * TypeDeVariable; char CodeRet; + +TypeDeForcing = PAS_DE_FORCING; +if ( BmnValide == OUI_PNE ) { + if ( fabs( Bmn - BCnt ) < EPSILON_FORCING_CONSTRAINT ) { + /* + if ( SensCnt == '<' ) printf("Forcing constraint pendant le variable probing sur contrainte d'inegalite %d\n",Cnt); + else printf("Forcing constraint pendant le variable probing sur contrainte d'egalite %d\n",Cnt); + printf("Bmin %e B %e sens %c\n",Bmn,BCnt,SensCnt); + */ + TypeDeForcing = FORCING_BMIN; + } +} +else if ( BmxValide == OUI_PNE ) { + if ( SensCnt == '=' ) { + if ( fabs( Bmx - BCnt ) < EPSILON_FORCING_CONSTRAINT ) { + /* + printf("Forcing constraint pendant le variable probing sur contrainte d'egalite %d\n",Cnt); + printf("Bmax %e B %e sens %c\n",Bmx,BCnt,SensCnt); + */ + TypeDeForcing = FORCING_BMAX; + } + } +} +if ( TypeDeForcing != FORCING_BMIN && TypeDeForcing != FORCING_BMAX ) return( NON_PNE ); + +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +BorneSupConnue = ProbingOuNodePresolve->BorneSupConnue; +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; +ValeurDeBorneSup = ProbingOuNodePresolve->ValeurDeBorneSup; +BorneMiseAJour = NON_PNE; + +CodeRet = NON_PNE; +il = Mdeb[Cnt]; +ilMax = il + NbTerm[Cnt]; +while ( il < ilMax ) { + Var = Nuvar[il]; + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) goto NextIlDoForcing; + Ai = A[il]; + if ( Ai == 0.0 ) goto NextIlDoForcing; + + UneVariableAEteFixee = NON_PNE; + + if ( TypeDeForcing == FORCING_BMIN ) { + if ( Ai > 0.0 ) { + /*printf("Forcing constraint contrainte %d variables %d a fixer au min %e\n",Cnt,Var,ValeurDeBorneInf[Var]);*/ + NouvelleValeur = ValeurDeBorneInf[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + } + else { + /*printf("Forcing constraint contrainte %d variables %d a fixer au max %e\n",Cnt,Var,ValeurDeBorneSup[Var]);*/ + NouvelleValeur = ValeurDeBorneSup[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + } + } + else { /* TypeForcing = FORCING_BMAX */ + if ( Ai > 0.0 ) { + /*printf("Forcing constraint contrainte %d variables %d a fixer au max %e\n",Cnt,Var,ValeurDeBorneSup[Var]);*/ + NouvelleValeur = ValeurDeBorneSup[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + } + else { + /*printf("Forcing constraint contrainte %d variables %d a fixer au min %e\n",Cnt,Var,ValeurDeBorneInf[Var]);*/ + NouvelleValeur = ValeurDeBorneInf[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + } + } + /* Si la variable a ete fixee on met a jour la liste des contraintes a examiner au prochain coup */ + if ( UneVariableAEteFixee != NON_PNE ) { + CodeRet = OUI_PNE; + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return( NON_PNE ); + } + + NextIlDoForcing: + il++; +} + +return( CodeRet ); +} + +/*----------------------------------------------------------------------------*/ + +void PNE_InitBorneInfBorneSupDesVariables( PROBLEME_PNE * Pne ) +{ +int NombreDeVariablesTrav; int Var; int TypeBorne; +int * TypeDeBorneTrav; double * UminTrav; double * UmaxTrav; double * UTrav; +char * BorneSupConnue; char * BorneInfConnue; double * ValeurDeBorneInf; +double * ValeurDeBorneSup; + +BorneSupConnue = Pne->ProbingOuNodePresolve->BorneSupConnue; +BorneInfConnue = Pne->ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInf = Pne->ProbingOuNodePresolve->ValeurDeBorneInf; +ValeurDeBorneSup = Pne->ProbingOuNodePresolve->ValeurDeBorneSup; + +NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +UTrav = Pne->UTrav; +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; + +for ( Var = 0 ; Var < NombreDeVariablesTrav ; Var++ ) { + BorneInfConnue[Var] = NON_PNE; + BorneSupConnue[Var] = NON_PNE; + ValeurDeBorneInf[Var] = -LINFINI_PNE; + ValeurDeBorneSup[Var] = LINFINI_PNE; + TypeBorne = TypeDeBorneTrav[Var]; + if ( TypeBorne == VARIABLE_FIXE ) { + BorneInfConnue[Var] = FIXE_AU_DEPART; + BorneSupConnue[Var] = FIXE_AU_DEPART; + ValeurDeBorneInf[Var] = UTrav[Var]; + ValeurDeBorneSup[Var] = UTrav[Var]; + continue; + } + if ( UminTrav[Var] == UmaxTrav[Var] ) { + BorneInfConnue[Var] = FIXE_AU_DEPART; + BorneSupConnue[Var] = FIXE_AU_DEPART; + ValeurDeBorneInf[Var] = UminTrav[Var]; + ValeurDeBorneSup[Var] = UminTrav[Var]; + continue; + } + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) { + BorneSupConnue[Var] = OUI_PNE; + ValeurDeBorneSup[Var] = UmaxTrav[Var]; + } + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) { + BorneInfConnue[Var] = OUI_PNE; + ValeurDeBorneInf[Var] = UminTrav[Var]; + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CalculMinContrainte( PROBLEME_PNE * Pne, double Bmin, double A, int Var, double * Min ) +{ +if ( A > 0.0 ) { + /* On avait pris Umin */ + Bmin -= A * Pne->ProbingOuNodePresolve->ValeurDeBorneInf[Var]; +} +else { + /* On avait pris Umax */ + Bmin -= A * Pne->ProbingOuNodePresolve->ValeurDeBorneSup[Var]; +} +*Min = Bmin; +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CalculMaxContrainte( PROBLEME_PNE * Pne, double Bmax, double A, int Var, double * Max ) +{ +if ( A > 0.0 ) { + /* On avait pris Umax */ + Bmax -= A * Pne->ProbingOuNodePresolve->ValeurDeBorneSup[Var]; +} +else { + /* On avait pris Umin */ + Bmax -= A * Pne->ProbingOuNodePresolve->ValeurDeBorneInf[Var]; +} +*Max = Bmax; +return; +} + +/*----------------------------------------------------------------------------*/ +/* Remarque: dans le calcul des bornes, on ajuste Bmin Bmax avec les bornes de +la variable. */ + +void PNE_CalculXiXs( PROBLEME_PNE * Pne, double Ai, int Var, int Cnt, + char * XiValide, char * XsValide, double * Xi , double * Xs ) +{ +double BminNew; double BmaxNew; double S; char * BminValide; double * Bmin; +char * BmaxValide; double * Bmax; double * B; + +BminValide = Pne->ProbingOuNodePresolve->BminValide; +Bmin = Pne->ProbingOuNodePresolve->Bmin; +BmaxValide = Pne->ProbingOuNodePresolve->BmaxValide; +Bmax = Pne->ProbingOuNodePresolve->Bmax; +B = Pne->BTrav; + +if ( Pne->SensContrainteTrav[Cnt] == '=' ) { + /* On regarde le min et le max */ + if ( BminValide[Cnt] == OUI_PNE ) { + /*PNE_CalculMinContrainte( Pne, Bmin[Cnt], Ai, Var, &BminNew );*/ + BminNew = Bmin[Cnt]; + if ( Ai > 0.0 ) BminNew -= Ai * Pne->ProbingOuNodePresolve->ValeurDeBorneInf[Var]; /* On avait pris Umin */ + else BminNew -= Ai * Pne->ProbingOuNodePresolve->ValeurDeBorneSup[Var]; /* On avait pris Umax */ + S = B[Cnt] - BminNew; + if ( Ai > 0 ) { *Xs = S / Ai; *XsValide = OUI_PNE; } + else { *Xi = -S / fabs( Ai ); *XiValide = OUI_PNE; } + } + if ( BmaxValide[Cnt] == OUI_PNE ) { + /*PNE_CalculMaxContrainte( Pne, Bmax[Cnt], Ai, Var, &BmaxNew );*/ + BmaxNew = Bmax[Cnt]; + if ( Ai > 0.0 ) BmaxNew -= Ai * Pne->ProbingOuNodePresolve->ValeurDeBorneSup[Var]; /* On avait pris Umax */ + else BmaxNew -= Ai * Pne->ProbingOuNodePresolve->ValeurDeBorneInf[Var]; /* On avait pris Umin */ + S = B[Cnt] - BmaxNew; + if ( Ai > 0 ) { *Xi = S / Ai; *XiValide = OUI_PNE; } + else { *Xs = -S / fabs( Ai ); *XsValide = OUI_PNE; } + } +} +else if ( Pne->SensContrainteTrav[Cnt] == '<' ) { + /* On peut calculer un majorant */ + if ( BminValide[Cnt] == OUI_PNE ) { + /*PNE_CalculMinContrainte( Pne, Bmin[Cnt], Ai, Var, &BminNew );*/ + BminNew = Bmin[Cnt]; + if ( Ai > 0.0 ) BminNew -= Ai * Pne->ProbingOuNodePresolve->ValeurDeBorneInf[Var]; /* On avait pris Umin */ + else BminNew -= Ai * Pne->ProbingOuNodePresolve->ValeurDeBorneSup[Var]; /* On avait pris Umax */ + S = B[Cnt] - BminNew; + if ( Ai > 0 ) { *Xs = S / Ai; *XsValide = OUI_PNE; } + else { *Xi = -S / fabs( Ai ); *XiValide = OUI_PNE; } + } +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_CalculXiXsContrainteAUneSeuleVariable( PROBLEME_PNE * Pne, int * VarSelect, int Cnt, + int ilDeb, int ilMax, double * A, int * Nuvar, + char * BorneInfConnue, double * ValeurDeBorneInf, + char * XiValide, char * XsValide, + double * Xi, double * Xs ) +{ +int il; int Nb; int Var; double S; double Ai; char BrnInfConnue; + +*XsValide = NON_PNE; +*XiValide = NON_PNE; +S = 0; +il = ilDeb; +ilMax = ilMax; +Nb = 0; +*VarSelect = -1; +Ai = 1.0; +while ( il < ilMax ) { + if ( A[il] == 0.0 ) goto NextIl; + Var = Nuvar[il]; + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) { + S += A[il] * ValeurDeBorneInf[Var]; + goto NextIl; + } + Nb++; + *VarSelect = Var; + Ai = A[il]; + NextIl: + il++; +} +if ( Nb != 1 ) { + printf("Probleme dans PNE_CalculXiXsContrainteAUneSeuleVariable sur la contrainte %d :\n",Cnt); + printf(" La contrainte est sensee contenir une seule variable non fixee or elles sont deja toutes fixees\n"); + *VarSelect = -1; + return; +} +S = Pne->BTrav[Cnt] - S; +if ( Pne->SensContrainteTrav[Cnt] == '=' ) { + *XiValide = OUI_PNE; + *XsValide = OUI_PNE; + *Xi = S / Ai; + *Xs = *Xi; +} +else { + if ( Ai > 0 ) { *Xs = S / Ai; *XsValide = OUI_PNE; } + else { *Xi = -S / fabs( Ai ); *XiValide = OUI_PNE; } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_MajIndicateursDeBornes( PROBLEME_PNE * Pne, + double * ValeurDeBorneInf, double * ValeurDeBorneSup, + char * BorneInfConnue, char * BorneSupConnue, + double NouvelleValeur, int Var, char UneVariableAEteFixee, + char BorneMiseAJour ) +{ +PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; + +if ( ProbingOuNodePresolve->VariableModifiee[Var] == NON_PNE ) { + ProbingOuNodePresolve->NumeroDeVariableModifiee[ProbingOuNodePresolve->NbVariablesModifiees] = Var; + ProbingOuNodePresolve->NbVariablesModifiees++; + ProbingOuNodePresolve->VariableModifiee[Var] = OUI_PNE; +} + +if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) { + /* Pour les variables entieres on incremente le compteur sauf si la variable est fixe au depart car alors + cela correspond a une arete existante et si on le prenait en compte on creerait un arete contradictoire ! */ + if ( UneVariableAEteFixee != FIXE_AU_DEPART ) { + ProbingOuNodePresolve->NumeroDesVariablesFixees[ProbingOuNodePresolve->NombreDeVariablesFixees] = Var; + ProbingOuNodePresolve->NombreDeVariablesFixees += 1; + } +} + +if ( UneVariableAEteFixee == FIXATION_SUR_BORNE_INF ) { + ValeurDeBorneSup[Var] = NouvelleValeur; + BorneInfConnue[Var] = FIXATION_SUR_BORNE_INF; + BorneSupConnue[Var] = FIXATION_SUR_BORNE_INF; +} +else if ( UneVariableAEteFixee == FIXATION_SUR_BORNE_SUP ) { + ValeurDeBorneInf[Var] = NouvelleValeur; + BorneInfConnue[Var] = FIXATION_SUR_BORNE_SUP; + BorneSupConnue[Var] = FIXATION_SUR_BORNE_SUP; +} +else if ( UneVariableAEteFixee == FIXATION_A_UNE_VALEUR ) { + ValeurDeBorneInf[Var] = NouvelleValeur; + ValeurDeBorneSup[Var] = NouvelleValeur; + BorneInfConnue[Var] = FIXATION_A_UNE_VALEUR; + BorneSupConnue[Var] = FIXATION_A_UNE_VALEUR; + if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) { + printf("Bug dans PNE_MajIndicateursDeBornes, une variable entiere ne prend jamais le qualificatif: FIXATION_A_UNE_VALEUR\n"); + } +} +else if ( UneVariableAEteFixee == FIXE_AU_DEPART ) { + ValeurDeBorneInf[Var] = NouvelleValeur; + ValeurDeBorneSup[Var] = NouvelleValeur; + BorneInfConnue[Var] = FIXE_AU_DEPART; + BorneSupConnue[Var] = FIXE_AU_DEPART; +} +else if ( BorneMiseAJour == MODIF_BORNE_INF ) { + ValeurDeBorneInf[Var] = NouvelleValeur; + BorneInfConnue[Var] = OUI_PNE; + if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) { + printf("Bug dans PNE_MajIndicateursDeBornes, une variable entiere ne prend jamais le qualificatif: MODIF_BORNE_INF\n"); + } +} +else if ( BorneMiseAJour == MODIF_BORNE_SUP ) { + ValeurDeBorneSup[Var] = NouvelleValeur; + BorneSupConnue[Var] = OUI_PNE; + if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) { + printf("Bug dans PNE_MajIndicateursDeBornes, une variable entiere ne prend jamais le qualificatif: MODIF_BORNE_SUP\n"); + } +} +else { + printf("Bug dans PNE_MajIndicateursDeBornes, indicateur UneVariableAEteFixee ou BorneMiseAJour incorrects\n"); +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_ModifierLaBorneDUneVariable( PROBLEME_PNE * Pne, int Var, char SensContrainte, + char XsValide, double Xs, char XiValide, double Xi, + double * NouvelleValeur, char * BorneMiseAJour, + char * VariableFixee, int * Faisabilite ) +{ +int TypeDeVariable; char BorneInfConnue; double Marge; double ValeurDeBorneInf; +char BorneSupConnue; double ValeurDeBorneSup; double MargeBorneVariableContinue; char Sens; + +/* Remarque: NombreDeVariablesFixees ne concerne que les variables entieres */ + +Sens = SensContrainte; /* Pour ne pas avoir de warning a la compilation */ + +BorneInfConnue = Pne->ProbingOuNodePresolve->BorneInfConnue[Var]; +ValeurDeBorneInf = Pne->ProbingOuNodePresolve->ValeurDeBorneInf[Var]; +BorneSupConnue = Pne->ProbingOuNodePresolve->BorneSupConnue[Var]; +ValeurDeBorneSup = Pne->ProbingOuNodePresolve->ValeurDeBorneSup[Var]; + +TypeDeVariable = Pne->TypeDeVariableTrav[Var]; + +Marge = MARGE_INITIALE; +if ( TypeDeVariable == ENTIER ) Marge = VALEUR_DE_FRACTIONNALITE_NULLE * 10.; +MargeBorneVariableContinue = 0.1; + +/* Si c'est une variable entiere elle ne peut pas etre entre les 2 bornes */ +if ( XsValide == OUI_PNE ) { + /* Attention il ne faut pas avoir Xs < Umin */ + if ( BorneInfConnue == OUI_PNE && Xs < ValeurDeBorneInf - Marge ) { + *Faisabilite = NON_PNE; + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("Non realisable variable %d Xs %e ValeurDeBorneInf %e XsValide %d\n",Var,Xs,ValeurDeBorneInf,XsValide); + # endif + return; + } +} +if ( XiValide == OUI_PNE ) { + /* Attention il ne faut pas avoir Xi > Umax */ + if ( BorneSupConnue == OUI_PNE && Xi > ValeurDeBorneSup + Marge ) { + *Faisabilite = NON_PNE; + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("Non realisable variable %d Xi %e ValeurDeBorneSup %e XiValide %d\n",Var,Xi,ValeurDeBorneSup,XiValide); + # endif + return; + } +} +/* Tentative de fixation a une valeur */ +if ( XsValide == OUI_PNE && XiValide == OUI_PNE ) { + if ( fabs( Xs - Xi ) < ZERO_NP_PROB ) { + Xi = 0.5 * ( Xs + Xi ); + if ( Xi < ValeurDeBorneInf - Marge || Xi > ValeurDeBorneSup + Marge ) { + /* Par precaution mais normalement ca ne passe pas les 2 tests qui precedent */ + *Faisabilite = NON_PNE; + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("Non realisable Xi %e ValeurDeBorneInf %e ValeurDeBorneSup %e\n",Xi,ValeurDeBorneInf,ValeurDeBorneSup); + # endif + return; + } + if ( TypeDeVariable == ENTIER ) { + /* Variable entiere: la valeur ne doit pas se trouver entre min et max */ + if ( fabs( ValeurDeBorneInf - Xi ) > Marge && fabs( ValeurDeBorneSup - Xi ) > Marge ) { + *Faisabilite = NON_PNE; + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("Non realisable Xi %e ValeurDeBorneSup %e\n",Xi,ValeurDeBorneSup); + # endif + return; + } + if ( fabs( Xi - ValeurDeBorneInf ) < fabs( ValeurDeBorneSup - Xi ) ) { + /* Fixation de la variable entiere a Xmin */ + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("Fixation de la variable entiere %d a %e sur contrainte d'egalite Xi %e\n",Var,ValeurDeBorneInf,Xi); + # endif + *NouvelleValeur = ValeurDeBorneInf; + *VariableFixee = FIXATION_SUR_BORNE_INF; + return; + } + else { + /* Fixation de la variable entiere a Xmax */ + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("Fixation de la variable entiere %d a %e sur contrainte d'egalite Xi %e\n",Var,ValeurDeBorneSup,Xi); + # endif + *NouvelleValeur = ValeurDeBorneSup; + *VariableFixee = FIXATION_SUR_BORNE_SUP; + return; + } + } + else { + /* Variable continue */ + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("Fixation de la variable continue %d a %e ValeurDeBorneInf %e ValeurDeBorneSup %e par contrainte d'egalite\n",Var,Xi, + ValeurDeBorneInf,ValeurDeBorneSup); + # endif + if ( Xi < ValeurDeBorneInf ) Xi = ValeurDeBorneInf; + if ( Xi > ValeurDeBorneSup ) Xi = ValeurDeBorneSup; + /* Fixation de la variable a une valeur */ + *NouvelleValeur = Xi; + *VariableFixee = FIXATION_A_UNE_VALEUR; + return; + } + return; + } +} + +/* Xi et Xs sont differents ou bien une seule des 2 valeurs est valide */ + +/* Remarque: on ne peut jamais mettre a jour a la fois Xi et Xs donc ca reste a faire */ + +if ( XsValide == OUI_PNE ) { + if ( TypeDeVariable == ENTIER ) { + /* Variable entiere */ + if ( Xs < ValeurDeBorneSup - Marge ) { + /* On fixe la variable a Xmin */ + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("Fixation de la variable entiere %d a %e sur contrainte d'inegalite Xs %e\n",Var,ValeurDeBorneInf,Xs); + # endif + *NouvelleValeur = ValeurDeBorneInf; + *VariableFixee = FIXATION_SUR_BORNE_INF; + return; + } + } + else { + /* Variable continue */ + /* Tentative de fixation */ + if ( fabs( Xs - ValeurDeBorneInf ) < ZERO_NP_PROB ) { + Xi = 0.5 * ( Xs + ValeurDeBorneInf ); + if ( Xi < ValeurDeBorneInf ) Xi = ValeurDeBorneInf; + if ( Xi > ValeurDeBorneSup ) Xi = ValeurDeBorneSup; + /* Fixation de la variable a une valeur */ + *NouvelleValeur = Xi; + *VariableFixee = FIXATION_A_UNE_VALEUR; + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("Fixation d'une variable continue sur une borne %d %e Umin %e Umax %e\n",Var,Xi,Pne->UminTrav[Var],Pne->UmaxTrav[Var]); + # endif + return; + } + /* Tentative d'amelioration de borne sup */ + if ( Xs < ValeurDeBorneSup - MargeBorneVariableContinue ) { + /* Precaution */ + if ( Xs < ValeurDeBorneInf + MargeBorneVariableContinue ) return; + /* On abaisse la borne sup */ + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("On abaisse la borne sup de la variable continue %d de %e a %e (borne inf = %e connue %d)\n", + Var,ValeurDeBorneSup,Xs,ValeurDeBorneInf,BorneInfConnue); + # endif + *NouvelleValeur = Xs; + *BorneMiseAJour = MODIF_BORNE_SUP; + return; + } + } +} +if ( XiValide == OUI_PNE ) { + if ( TypeDeVariable == ENTIER ) { + if ( Xi > ValeurDeBorneInf + Marge ) { + /* On fixe la variable a Xmax */ + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("Fixation de la variable entiere %d a %e sur contrainte d'inegalite Xi %e\n",Var,ValeurDeBorneSup,Xi); + # endif + *NouvelleValeur = ValeurDeBorneSup; + *VariableFixee = FIXATION_SUR_BORNE_SUP; + return; + } + } + else { + /* Variable continue */ + /* Tentative de fixation */ + if ( fabs( ValeurDeBorneSup - Xi ) < ZERO_NP_PROB ) { + Xi = 0.5 * ( ValeurDeBorneSup + Xi ); + if ( Xi < ValeurDeBorneInf ) Xi = ValeurDeBorneInf; + if ( Xi > ValeurDeBorneSup ) Xi = ValeurDeBorneSup; + /* Fixation de la variable a une valeur */ + *NouvelleValeur = Xi; + *VariableFixee = FIXATION_A_UNE_VALEUR; + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("Fixation d'une variable continue sur une borne %d %e Umin %e Umax %e\n",Var,Xi,Pne->UminTrav[Var],Pne->UmaxTrav[Var]); + # endif + return; + } + /* Tentative d'amelioration de borne inf */ + if ( Xi > ValeurDeBorneInf + MargeBorneVariableContinue ) { + /* Precaution */ + if ( Xi > ValeurDeBorneSup - MargeBorneVariableContinue ) return; + /* On remonte la borne inf */ + # if VERBOSE_FIXATIONS_DE_VARIABLES == OUI_PNE + printf("On remonte la borne inf de la variable continue %d de %e a %e (borne sup = %e connue %d)\n", + Var,ValeurDeBorneInf,Xi,ValeurDeBorneSup,BorneSupConnue); + # endif + *NouvelleValeur = Xi; + *BorneMiseAJour = MODIF_BORNE_INF; + return; + } + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Tentative de fixation sur critere */ +/* Si une variable n'est pas seule dans sa contrainte on regarde si on peut la fixer pour desaturer + une contrainte d'inegalite. Si elle intervient dans d'autres egalites ou des inegalites avec un + coeff de signe different mais qu'elle est seule (les autres sont fixees alors on peut la fixer) */ + +void PNE_ProbingNodePresolveFixerVariablesSurCritere( PROBLEME_PNE * Pne, char * DesVariablesOntEteFixees ) +{ +int Var; int * TypeDeVariable; int NombreDeVariables; double * L; +int * Cdeb; int * Csui; double * A; double Ai; int Cnt; char * SensContrainte; +int * NumContrainte; int ic; double SigneCoeff; int NombreDeContraintes; +char * BorneSupConnue; double * ValeurDeBorneSup; double NouvelleValeur; char BorneMiseAJour; +char * BorneInfConnue; double * ValeurDeBorneInf; +double * B; double * Bmax; char * BmaxValide; char UneVariableAEteFixee; +char BrnInfConnue; PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; CONFLICT_GRAPH * ConflictGraph; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +NombreDeVariables = Pne->NombreDeVariablesTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +L = Pne->LTrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +A = Pne->ATrav; +SensContrainte = Pne->SensContrainteTrav; +NumContrainte = Pne->NumContrainteTrav; +B = Pne->BTrav; + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; +ConflictGraph = Pne->ConflictGraph; + +BorneSupConnue = ProbingOuNodePresolve->BorneSupConnue; +ValeurDeBorneSup = ProbingOuNodePresolve->ValeurDeBorneSup; +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; +Bmax = ProbingOuNodePresolve->Bmax; +BmaxValide = ProbingOuNodePresolve->BmaxValide; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + + if ( TypeDeVariable[Var] != ENTIER ) continue; + + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) continue; + + NouvelleValeur = -1; + BorneMiseAJour = NON_PNE; + UneVariableAEteFixee = NON_PNE; + + SigneCoeff = '?'; + ic = Cdeb[Var]; + while ( ic >= 0 ) { + Ai = A[ic]; + if ( Ai == 0.0 ) goto NextIc_1; + Cnt = NumContrainte[ic]; + + if ( SensContrainte[Cnt] == '<' ) { + /* Contrainte toujours satisafaite ? */ + if ( Bmax[Cnt] <= B[Cnt] && BmaxValide[Cnt] == OUI_PNE ) goto NextIc_1; + } + + if ( SensContrainte[Cnt] == '=' ) { + SigneCoeff = 'X'; + goto NextVar; + } + if ( Ai > 0.0 ) { + if ( SigneCoeff == '?' ) SigneCoeff = '+'; + else if ( SigneCoeff == '-' ) { + SigneCoeff = 'X'; + goto NextVar; + } + } + else { + if ( SigneCoeff == '?' ) SigneCoeff = '-'; + else if ( SigneCoeff == '+' ) { + SigneCoeff = 'X'; + goto NextVar; + } + } + NextIc_1: + ic = Csui[ic]; + } + NextVar: + if ( SigneCoeff == 'X' ) continue; + if ( SigneCoeff == '+' ) { + if ( L[Var] >= 0.0 ) { + /* On fixe a Umin */ + if ( BorneInfConnue[Var] == OUI_PNE ) { + *DesVariablesOntEteFixees = OUI_PNE; + /* + printf("Fixation de la variable %d a %e\n",Var,ValeurDeBorneInf[Var]); + */ + NouvelleValeur = ValeurDeBorneInf[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + } + } + } + else if ( SigneCoeff == '-' ) { + if ( L[Var] <= 0.0 ) { + /* On fixe a Umax */ + if ( BorneSupConnue[Var] == OUI_PNE ) { + *DesVariablesOntEteFixees = OUI_PNE; + /* + printf("Fixation de la variable %d a %e\n",Var,ValeurDeBorneSup[Var]); + */ + NouvelleValeur = ValeurDeBorneSup[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + } + } + } + else if ( SigneCoeff == '?' ) { + /*printf("Fixation de la variable %d car elle n'apparait pas dans les contraintes\n",Var);*/ + /* La variable n'apparait pas dans les contraintes */ + if ( L[Var] >= 0.0 ) { + /* On fixe a Umin */ + if ( BorneInfConnue[Var] == OUI_PNE ) { + *DesVariablesOntEteFixees = OUI_PNE; + /* + printf("Fixation de la variable %d a %e\n",Var,ValeurDeBorneInf[Var]); + */ + NouvelleValeur = ValeurDeBorneInf[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + } + } + else { + if ( BorneSupConnue[Var] == OUI_PNE ) { + *DesVariablesOntEteFixees = OUI_PNE; + /* + printf("Fixation de la variable %d a %e\n",Var,ValeurDeBorneSup[Var]); + */ + NouvelleValeur = ValeurDeBorneSup[Var]; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + } + } + if ( UneVariableAEteFixee != NON_PNE || BorneMiseAJour != NON_PNE ) { + /* + PNE_MajIndicateursDeBornes( Pne, ValeurDeBorneInf, ValeurDeBorneSup, BorneInfConnue, BorneSupConnue, + NouvelleValeur, Var, UneVariableAEteFixee, BorneMiseAJour ); + */ + + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + if ( Pne->ProbingOuNodePresolve->Faisabilite == NON_PNE ) return; + + } + } +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_probing_variables_a_instancier.c b/src/ext/Sirius_Solver/pne/pne_probing_variables_a_instancier.c new file mode 100644 index 0000000000..48355885df --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_probing_variables_a_instancier.c @@ -0,0 +1,217 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Construction de la liste des variables a instancier + dans le variable probing. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +int PNE_PartitionVarInstTriRapide( int * , int * , int , int ); +void PNE_VarInstTriRapide( int * , int * , int , int ); + +/*----------------------------------------------------------------------------*/ + +int PNE_PartitionVarInstTriRapide( int * NumVarAInstancier, int * NbContraintesDeVar, int Deb, int Fin ) +{ +int Compt; double Pivot; int i; int Var; +Compt = Deb; +Pivot = NbContraintesDeVar[NumVarAInstancier[Deb]]; +/* Ordre decroissant */ +for ( i = Deb + 1 ; i <= Fin ; i++) { + if ( NbContraintesDeVar[NumVarAInstancier[i]] > Pivot) { + Compt++; + Var = NumVarAInstancier[Compt]; + NumVarAInstancier[Compt] = NumVarAInstancier[i]; + NumVarAInstancier[i] = Var; + } +} +Var = NumVarAInstancier[Compt]; +NumVarAInstancier[Compt] = NumVarAInstancier[Deb]; +NumVarAInstancier[Deb] = Var; +return(Compt); +} + +/*----------------------------------------------------------------------------*/ + +void PNE_VarInstTriRapide( int * NumVarAInstancier, int * NbContraintesDeVar, int Debut, int Fin ) +{ +int Pivot; +if ( Debut < Fin ) { + Pivot = PNE_PartitionVarInstTriRapide( NumVarAInstancier, NbContraintesDeVar, Debut, Fin ); + PNE_VarInstTriRapide( NumVarAInstancier, NbContraintesDeVar, Debut , Pivot-1 ); + PNE_VarInstTriRapide( NumVarAInstancier, NbContraintesDeVar, Pivot+1, Fin ); +} +return; +} + +/*----------------------------------------------------------------------------*/ +/* On construit la liste des variables a tester en prenant toutes les variables + entieres et en les classant dans l'ordre decroissant du nombre de contraintes + dans lequel elles interviennent */ +void PNE_ProbingInitVariablesAInstancierApresLePresolve( PROBLEME_PNE * Pne, PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve ) +{ +int Var; int NombreDeVariables; int * TypeDeBorne; int * TypeDeVariable; double * Umin; +double * Umax; char * FlagVarAInstancier; int NbVarAInstancier; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +Umin = Pne->UminTrav; +Umax = Pne->UmaxTrav; + +FlagVarAInstancier = ProbingOuNodePresolve->FlagVarAInstancier; + +NbVarAInstancier = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + FlagVarAInstancier[Var] = 0; + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) continue; + if ( TypeDeVariable[Var] != ENTIER ) continue; + if ( Umin[Var] == Umax[Var] ) continue; + FlagVarAInstancier[Var] = 1; + NbVarAInstancier++; +} +ProbingOuNodePresolve->NbVarAInstancier = NbVarAInstancier; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* On construit la liste des variables a tester en prenant les variables + entieres dont la valeur est fractionnaire et en les classant dans l'ordre + decroissant du nombre de contraintes dans lequel elles interviennent */ +void PNE_ProbingInitVariablesAInstancier( PROBLEME_PNE * Pne, PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve ) +{ +int Var; int NombreDeVariables; char * FlagVarAInstancier; int NbVarAInstancier; int * SuivFrac; + +NombreDeVariables = Pne->NombreDeVariablesTrav; + +FlagVarAInstancier = ProbingOuNodePresolve->FlagVarAInstancier; +memset( (char *) FlagVarAInstancier, 0 , NombreDeVariables * sizeof( char ) ); + +NbVarAInstancier = 0; +SuivFrac = Pne->SuivFrac; +Var = Pne->PremFrac; +while ( Var >= 0 ) { + FlagVarAInstancier[Var] = 1; + NbVarAInstancier++; + Var = SuivFrac[Var]; +} + +ProbingOuNodePresolve->NbVarAInstancier = NbVarAInstancier; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_ProbingMajVariablesAInstancier( PROBLEME_PNE * Pne, PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve ) +{ +int Var; int NombreDeVariables; int * NumVarAInstancier; char * FlagVarAInstancier; int * NbContraintesDeVar; +int NbVarAInstancier; int Nb; int ic; int * Cdeb; int * Csui; int Debut; int Fin; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; + +NumVarAInstancier = ProbingOuNodePresolve->NumVarAInstancier; +FlagVarAInstancier = ProbingOuNodePresolve->FlagVarAInstancier; +NbContraintesDeVar = ProbingOuNodePresolve->NumeroDeVariableModifiee; + +NbVarAInstancier = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( FlagVarAInstancier[Var] == 0 ) continue; + FlagVarAInstancier[Var] = 0; + NumVarAInstancier[NbVarAInstancier] = Var; + NbVarAInstancier++; + /* Decompte du nombre de contraintes */ + Nb = 0; + ic = Cdeb[Var]; + while ( ic >= 0 ) { + Nb++; + ic = Csui[ic]; + } + NbContraintesDeVar[Var] = Nb; +} + +ProbingOuNodePresolve->NbVarAInstancier = NbVarAInstancier; + +/* Classement */ +Debut = 0; +Fin = NbVarAInstancier - 1; +if ( NbVarAInstancier > 1 ) PNE_VarInstTriRapide( NumVarAInstancier, NbContraintesDeVar, Debut, Fin ); + +return; +} + +/*----------------------------------------------------------------------------*/ +/* On initialise le flag pour les variables qui impliquent ValeurDeVar pour Var */ + +void PNE_ProbingMajFlagVariablesAInstancier( PROBLEME_PNE * Pne, int Var, double ValeurDeVar ) +{ + +int Edge; int Noeud; int Complement; int Nv; int Pivot; int * First; int * Adjacent; +int * Next; char * FlagVarAInstancier; + +if ( Var < 0 ) return; + +FlagVarAInstancier = Pne->ProbingOuNodePresolve->FlagVarAInstancier; +Pivot = Pne->ConflictGraph->Pivot; + +if ( ValeurDeVar == 1.0 ) { Noeud = Pivot + Var; Complement = Var; } +else { Noeud = Var; Complement = Pivot + Var; } + +First = Pne->ConflictGraph->First; +Adjacent = Pne->ConflictGraph->Adjacent; +Next = Pne->ConflictGraph->Next; + +Edge = First[Noeud]; +while ( Edge >= 0 ) { + Nv = Adjacent[Edge]; + /* Attention a ne pas prendre le complement */ + if ( Nv == Complement ) goto NextEdge; + if ( Nv < Pivot ) { + Var = Nv; + FlagVarAInstancier[Var] = 1; + } + else { + /* La valeur borne inf est interdite pour la variable */ + /* On doit donc fixer la variable a Umax et fixer les voisins de ce noeud */ + Var = Nv - Pivot; + FlagVarAInstancier[Var] = 1; + } + NextEdge: + Edge = Next[Edge]; +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_rand.c b/src/ext/Sirius_Solver/pne/pne_rand.c new file mode 100644 index 0000000000..8d66cfe928 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_rand.c @@ -0,0 +1,61 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Fonction de tirage d'un nombre pseudo aleatoire entre + 0 et 1 + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" + +# define PI 3.141592653 +# define PNE_RAND_MAX 1. + +/********************************************************************/ + +double PNE_SRand( double Graine ) +{ +double A1; + +A1 = Graine; +return( PNE_Rand( A1 ) ); + +} + +/********************************************************************/ + +double PNE_Rand( double A1 ) +{ + +A1 = A1 + PI; +A1 = pow( A1, 5. ); +A1 = A1 - floor( A1 ); +A1 = A1 * PNE_RAND_MAX; + +if ( A1 > PNE_RAND_MAX ) A1 = PNE_RAND_MAX; +else if ( A1 < 0. ) A1 = 0.; + +return( A1 ); + +} + + diff --git a/src/ext/Sirius_Solver/pne/pne_recherche_symetries.c b/src/ext/Sirius_Solver/pne/pne_recherche_symetries.c new file mode 100644 index 0000000000..e793392b2e --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_recherche_symetries.c @@ -0,0 +1,196 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recherche de symetries. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 1 + +/*----------------------------------------------------------------------------*/ + +void PNE_RechercheSymetries( PROBLEME_PNE * Pne, int VariableInstanciee , int * BasesFilsDisponibles ) + +{ +int NombreDeVariables; int NombreDeContraintes; int * Mdeb; int * NbTerm; +int * Nuvar; double * A; double * CoutLineaire; int Cnt; int il; int Nb; +int Var1; int Var2; int ic; int * Cdeb; int * Csui; int * NumContrainte; +char * SensContrainte; double * B; double * ColonneDeVar1; int NbTermesVar1; +int ilMax; double * ContrainteCnt1; +double * Buffer; int * TypeDeVariable; double * ColonneDeVar2; int * TypeDeBorne; +char * ContrainteActivable; double * Xmin; double * Xmax; double Smax; int NbT; +char YaDesSymetries; + +return; + +printf("RechercheSymetries\n"); + +YaDesSymetries = NON_PNE; +/*Pne->NbVarGauche = 0;*/ + +NombreDeVariables = Pne->NombreDeVariablesTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +CoutLineaire = Pne->LTrav; +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +B = Pne->BTrav; +SensContrainte = Pne->SensContrainteTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; + +Buffer = (double *) malloc( (NombreDeContraintes+NombreDeContraintes+NombreDeVariables+NombreDeContraintes)* sizeof( double ) ); +if ( Buffer == NULL ) return; +memset( (char *) Buffer, 0, (NombreDeContraintes+NombreDeContraintes+NombreDeVariables+NombreDeContraintes)* sizeof( double ) ); +ColonneDeVar1 = Buffer; +ColonneDeVar2 = &Buffer[NombreDeContraintes]; +ContrainteCnt1 = &Buffer[NombreDeContraintes+NombreDeContraintes]; +ContrainteActivable = (char *) &Buffer[NombreDeContraintes+NombreDeContraintes+NombreDeVariables]; +/* Activite des contraintes */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) ContrainteActivable[Cnt] = OUI_PNE; + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) ColonneDeVar1[Cnt] = 0.0; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) ColonneDeVar2[Cnt] = 0.0; + + + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( SensContrainte[Cnt] != '<' ) continue; + Smax = 0; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( A[il] > 0 ) { + if ( TypeDeBorne[Nuvar[il]] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorne[Nuvar[il]] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Smax = A[il] * Xmax[Nuvar[il]]; + } + else { + Smax = LINFINI_PNE; + break; + } + } + else { + if ( TypeDeBorne[Nuvar[il]] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeDeBorne[Nuvar[il]] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Smax = A[il] * Xmin[Nuvar[il]]; + } + else { + Smax = LINFINI_PNE; + break; + } + } + il++; + } + if ( Smax < B[Cnt] ) { + ContrainteActivable[Cnt] = NON_PNE; + } +} + +for ( Var1 = 0 ; Var1 < NombreDeVariables ; Var1++ ) { + if ( Var1 != VariableInstanciee ) continue; + if ( TypeDeVariable[Var1] != ENTIER ) continue; + /* Expand de la colonne de Var1 */ + NbTermesVar1 = 0; + ic = Cdeb[Var1]; + while ( ic >= 0 ) { + if ( ContrainteActivable[NumContrainte[ic]] == OUI_PNE ) { + ColonneDeVar1[NumContrainte[ic]] = A[ic]; + NbTermesVar1++; + } + ic = Csui[ic]; + } + for ( Var2 = 0/*Var1 + 1*/ ; Var2 < NombreDeVariables ; Var2++ ) { + if ( Var2 == Var1 ) continue; + if ( TypeDeVariable[Var2] != ENTIER ) continue; + if ( CoutLineaire[Var1] != CoutLineaire[Var2] ) continue; + + /* Comparaison avec la colonne de Var2: elle doit etre soit identique soit avec 2 termes differents au plus */ + Nb = NbTermesVar1; + NbT = 0; + ic = Cdeb[Var2]; + while ( ic >= 0 ) { + if ( ContrainteActivable[NumContrainte[ic]] == OUI_PNE ) { + NbT++; + if ( NbT > NbTermesVar1 ) { + Nb = 1; + break; + } + if ( ColonneDeVar1[NumContrainte[ic]] == A[ic] ) Nb--; + } + ic = Csui[ic]; + } + + + if ( Nb == 0 ) { + printf("Colonnes %d et %d egales\n",Var1,Var2); + YaDesSymetries = OUI_PNE; + /* + Pne->ValeurAGauche = 0; + Pne->PaquetDeGauche[Pne->NbVarGauche] = Var2; + Pne->NbVarGauche++; + *BasesFilsDisponibles = NON_PNE; + */ + } + + } + + /* On remet tout en ordre pour la variable Var1 */ + ic = Cdeb[Var1]; + while ( ic >= 0 ) { + ColonneDeVar1[NumContrainte[ic]] = 0.0; + ic = Csui[ic]; + } + +} + +free( Buffer ); + +if ( YaDesSymetries == OUI_PNE ) { + /* + Pne->ValeurADroite = 0; + Pne->PaquetDeDroite[Pne->NbVarDroite] = VariableInstanciee; + Pne->NbVarDroite++; + */ +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_recuperer_le_probleme_initial.c b/src/ext/Sirius_Solver/pne/pne_recuperer_le_probleme_initial.c new file mode 100644 index 0000000000..9baec89d61 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_recuperer_le_probleme_initial.c @@ -0,0 +1,42 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +/*----------------------------------------------------------------------------*/ + +void PNE_RecupererLeProblemeInitial( PROBLEME_PNE * Pne ) +{ + +Pne->Coupes.NombreDeContraintes = 0; +Pne->NombreDeCoupesCalculees = 0; + +Pne->ResolutionDuNoeudReussie = OUI_PNE; + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_recuperer_solution_et_critere.c b/src/ext/Sirius_Solver/pne/pne_recuperer_solution_et_critere.c new file mode 100644 index 0000000000..69c14efb8e --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_recuperer_solution_et_critere.c @@ -0,0 +1,337 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recuperation des resultats + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "prs_define.h" + +# define TOLERANCE_SUR_LES_VIOLATIONS_DE_CONTRAINTES 1.e-2 /*1.e-3*/ + +/*----------------------------------------------------------------------------*/ + +void PNE_RecupererLaSolutionEtCalculerLeCritere( PROBLEME_PNE * Pne, + PROBLEME_A_RESOUDRE * Probleme ) +{ +int i; int Var; int VarE; double Critere; int CntE; int Cnt; double S; int il; int ilMax; + +double * UTrav; double * UminEntree; double * UmaxEntree; double * BTrav; double * ATrav; +double * VariablesDualesDesContraintesTrav; double * LTrav; int * TypeDeVariableTrav; +int * TypeDeBorneTrav; char * VariableAInverser; int * CorrespondanceVarEntreeVarNouvelle; +double ToleranceViolation; char * SensContrainteTrav; int * MdebTrav; int * NbTermTrav; +int * NuvarTrav; int * CorrespondanceCntPneCntEntree; int NumeroDeLaContrainteDeCoutMax; +int * NumeroDesContraintesInactives; int * TypeDeBorneE; double * UminE; double * UmaxE; +char * SensE; int * MdebE; int * NbtermE; double * AE; int * NuvarE; int ilE; int ilMaxE; +double CoutE; double C1; double C2; double C3; double C4; double Zborne; double a; double u; +int NombreDeVariablesE; int NombreDeContraintesE; int * TypeDeBorneTravE; +double * UE; double * LE; double * VariablesDualesDesContraintesE; + +NombreDeVariablesE = Probleme->NombreDeVariables; +NombreDeContraintesE = Probleme->NombreDeContraintes; +TypeDeBorneTravE = Probleme->TypeDeBorneDeLaVariable; +UE = Probleme->X; +LE = Probleme->CoutLineaire; +VariablesDualesDesContraintesE = Probleme->VariablesDualesDesContraintes; + +LTrav = Pne->LTrav; +UTrav = Pne->UTrav; +TypeDeVariableTrav = Pne->TypeDeVariableTrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +UminEntree = Pne->UminEntree; +UmaxEntree = Pne->UmaxEntree; +VariableAInverser = Pne->VariableAInverser; +CorrespondanceVarEntreeVarNouvelle = Pne->CorrespondanceVarEntreeVarNouvelle; + +SensContrainteTrav = Pne->SensContrainteTrav; +BTrav = Pne->BTrav; +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +ATrav = Pne->ATrav; +NuvarTrav = Pne->NuvarTrav; +CorrespondanceCntPneCntEntree = Pne->CorrespondanceCntPneCntEntree; +VariablesDualesDesContraintesTrav = Pne->VariablesDualesDesContraintesTrav; + +NumeroDesContraintesInactives = Pne->NumeroDesContraintesInactives; + +if ( Pne->YaUneSolution == SOLUTION_OPTIMALE_TROUVEE ) { + + /* NumeroDeLaContrainteDeCoutMax = -1 s'il n'y a pas de variables entieres */ + NumeroDeLaContrainteDeCoutMax = Pne->NumeroDeLaContrainteDeCoutMax; + + for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + /* En presence de variables entieres, il peut y avoir une contrainte de coutmax. A ce niveau de l'execution + cette contrainte peut etre violee par la solution optimale (alors que ce n'est pas le cas dans le simplexe. + Pourquoi ? Parce que le second membre de cette contrainte est mis a jour a chaque fois que l'on trouve + une solution entiere ameliorante. Or ici on testerait la violation de cette contrainte avec le nouveau + second membre. Comme la solution est ameliorante on la detecterait comme etant violee par la solution + optimale ce qui serait une conclusion fausse. */ + if ( Cnt == NumeroDeLaContrainteDeCoutMax ) continue; + /* Verifier les violations de contraintes */ + S = 0.; + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + S+= ATrav[il] * UTrav[NuvarTrav[il]]; + il++; + } + ToleranceViolation = ( 1. + fabs( BTrav[Cnt] ) ) * 0.01 * TOLERANCE_SUR_LES_VIOLATIONS_DE_CONTRAINTES; + if ( SensContrainteTrav[Cnt] == '=' ) { + if ( fabs( S - BTrav[Cnt] ) > ToleranceViolation ) { + Pne->YaUneSolution = SOLUTION_OPTIMALE_TROUVEE_MAIS_QUELQUES_CONTRAINTES_SONT_VIOLEES; + # if VERBOSE_PNE == 1 + printf("Contrainte d'egalite %d violee: valeur calculee %e second membre %e violation %e\n",Cnt,S, + BTrav[Cnt],fabs( S - BTrav[Cnt] )); + # endif + } + } + else if ( SensContrainteTrav[Cnt] == '<' ) { + if ( S > BTrav[Cnt] + ToleranceViolation ) { + Pne->YaUneSolution = SOLUTION_OPTIMALE_TROUVEE_MAIS_QUELQUES_CONTRAINTES_SONT_VIOLEES; + # if VERBOSE_PNE == 1 + printf("Contrainte %d de type < ou = violee: valeur calculee %e second membre %e violation %e\n",Cnt,S, + BTrav[Cnt],fabs( S - BTrav[Cnt] )); + # endif + } + } + else if ( SensContrainteTrav[Cnt] == '>' ) { + if ( S < BTrav[Cnt] - ToleranceViolation ) { + Pne->YaUneSolution = SOLUTION_OPTIMALE_TROUVEE_MAIS_QUELQUES_CONTRAINTES_SONT_VIOLEES; + # if VERBOSE_PNE == 1 + printf("Contrainte %d de type > ou = violee: valeur calculee %e second membre %e violation %e\n",Cnt,S, + BTrav[Cnt],fabs( S - BTrav[Cnt] )); + # endif + + } + } + } +} + +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( TypeDeVariableTrav[i] == ENTIER ) { + if ( fabs( UTrav[i] - floor( UTrav[i] ) ) <= TOLERANCE_SUR_LES_ENTIERS ) { + UTrav[i] = floor( UTrav[i] ); + } + else UTrav[i] = ceil( UTrav[i] ); + } +} + +/* Restitution du resultat dans le contexte d'appel et calcul du critere */ + +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( TypeDeBorneTrav[i] == VARIABLE_BORNEE_DES_DEUX_COTES || + TypeDeBorneTrav[i] == VARIABLE_BORNEE_INFERIEUREMENT ) + UTrav[i]+= UminEntree[i]; + else if ( TypeDeBorneTrav[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) + UTrav[i]+= UmaxEntree[i]; + + if ( VariableAInverser[i] == OUI_PNE ) UTrav[i] = -UTrav[i]; + +} + +if ( VariablesDualesDesContraintesE != NULL ) { + /* 22/10/2015: suppression de la boucle qui suit et recalcul des variables duales juste apres */ + /* + for ( i = 0 ; i < Pne->NombreDeContraintesInactives ; i++ ) { + CntE = NumeroDesContraintesInactives[i]; + if ( CntE >= 0 && CntE < NombreDeContraintesE ) { + VariablesDualesDesContraintesE[CntE] = 0.0; + } + } + */ + for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + CntE = CorrespondanceCntPneCntEntree[Cnt]; + if ( CntE >= 0 && CntE < NombreDeContraintesE ) { + VariablesDualesDesContraintesE[CntE] = VariablesDualesDesContraintesTrav[Cnt]; + } + } +} + +/* Recuperation des substitutions de variables et des variables colineaire ainsi que + des variables duales */ +PNE_PostSolve( Pne, Probleme ); + +for ( Critere = 0. , VarE = 0 ; VarE < NombreDeVariablesE ; VarE++ ) { + Var = CorrespondanceVarEntreeVarNouvelle[VarE]; + if ( Var >= 0 ) { + UE[VarE] = UTrav[Var]; + } + Critere += LE[VarE] * UE[VarE]; +} + +/* Pour les contraintes inactives dont la variable duale reste non initialisee on se sert des couts des + variables qui la composent */ + +if ( VariablesDualesDesContraintesE != NULL ) { + TypeDeBorneE = Probleme->TypeDeBorneDeLaVariable; + UmaxE = Probleme->Xmax; + UminE = Probleme->Xmin; + SensE = Probleme->Sens; + MdebE = Probleme->IndicesDebutDeLigne; + NbtermE = Probleme->NombreDeTermesDesLignes; + AE = Probleme->CoefficientsDeLaMatriceDesContraintes; + NuvarE = Probleme->IndicesColonnes; + Zborne = 1.e-6; + for ( CntE = 0 ; CntE < NombreDeContraintesE ; CntE++ ) { + if ( VariablesDualesDesContraintesE[CntE] < VALEUR_NON_INITIALISEE ) continue; + VariablesDualesDesContraintesE[CntE] = 0; + if ( SensE[CntE] != '=' ) continue; + /* Contrainte de type = : + C1 = le plus petit cout des variable a coefficient positif qui ne sont pas sur Xmax + C2 = le plus petit cout change de signe des variable a coefficient positif qui ne sont pas sur Xmin + C3 = le plus petit cout des variables a coefficient negatif qui ne sont pas sur Xmax + C4 = le plus petit cout change de signe des variables a coefficient negatif qui ne sont pas su Xmin + Et on affecte le min de C1, C2, C3, C4 + */ + C1 = 2 * VALEUR_NON_INITIALISEE; + C2 = 2 * VALEUR_NON_INITIALISEE; + C3 = 2 * VALEUR_NON_INITIALISEE; + C4 = 2 * VALEUR_NON_INITIALISEE; + S = 0; + ilE = MdebE[CntE]; + ilMaxE = ilE + NbtermE[CntE]; + while ( ilE < ilMaxE ) { + a = AE[ilE]; + if ( a == 0.0 ) goto NextIlE; + VarE = NuvarE[ilE]; + + S += a * UE[VarE]; + + CoutE = LE[VarE]; + if ( TypeDeBorneE[VarE] == VARIABLE_FIXE ) goto NextIlE; + if ( TypeDeBorneE[VarE] == VARIABLE_NON_BORNEE ) { + if ( a > 0 ) { + if ( C1 > CoutE ) C1 = CoutE; + if ( C2 > -CoutE ) C2 = -CoutE; + } + else { + if ( C3 > CoutE ) C3 = CoutE; + if ( C4 > -CoutE ) C4 = -CoutE; + } + } + else if ( TypeDeBorneE[VarE] == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( a > 0 ) { + if ( C1 > CoutE ) C1 = CoutE; + if ( fabs ( UE[VarE] - UminE[VarE] ) > Zborne ) { + if ( C2 > -CoutE ) C2 = -CoutE; + } + } + else { + if ( C3 > CoutE ) C3 = CoutE; + if ( fabs ( UE[VarE] - UminE[VarE] ) > Zborne ) { + if ( C4 > -CoutE ) C4 = -CoutE; + } + } + } + else if ( TypeDeBorneE[VarE] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + if ( a > 0 ) { + if ( fabs ( UE[VarE] - UmaxE[VarE] ) > Zborne ) { + if ( C1 > CoutE ) C1 = CoutE; + } + if ( C2 > -CoutE ) C2 = -CoutE; + } + else { + if ( fabs ( UE[VarE] - UmaxE[VarE] ) > Zborne ) { + if ( C3 > CoutE ) C3 = CoutE; + } + if ( C4 > -CoutE ) C4 = -CoutE; + } + } + else { + if ( a > 0 ) { + if ( fabs ( UE[VarE] - UmaxE[VarE] ) > Zborne ) { + if ( C1 > CoutE ) C1 = CoutE; + } + if ( fabs ( UE[VarE] - UminE[VarE] ) > Zborne ) { + if ( C2 > -CoutE ) C2 = -CoutE; + } + } + else { + if ( fabs ( UE[VarE] - UmaxE[VarE] ) > Zborne ) { + if ( C3 > CoutE ) C3 = CoutE; + } + + if ( fabs ( UE[VarE] - UminE[VarE] ) > Zborne ) { + if ( C4 > -CoutE ) C4 = -CoutE; + } + } + } + NextIlE: + ilE++; + } + u = 4 * VALEUR_NON_INITIALISEE; + if ( u > C1 ) u = C1; + if ( u > C2 ) u = C2; + if ( u > C3 ) u = C3; + if ( u > C4 ) u = C4; + if ( u > VALEUR_NON_INITIALISEE ) u = 0; + + /* Il faut changer le signe pour se remettre dans le contexte d'un simplexe */ + u = -u; + + /* Ici on n'a jamais une contrainte d'egalite */ + if ( Probleme->Sens[CntE] == '<' ) { + if ( S < Probleme->SecondMembre[CntE] + 1.e-7 ) u = 0; + } + else if ( Probleme->Sens[CntE] == '>' ) { + if ( S > Probleme->SecondMembre[CntE] - 1.e-7 ) u = 0; + } + + VariablesDualesDesContraintesE[CntE] = u; + + } +} + +#if VERBOSE_PNE + if ( Pne->YaUneSolution != PAS_DE_SOLUTION_TROUVEE ) { + printf(" Valeur du critere: %lf \n",Critere ); + printf("(attention c'est une valeur interne au solveur, en particulier elle ne tient\n"); + printf(" pas compte de la contribution de variables fixes au critere)\n"); + } +#endif + +/* Controle d'existence de valeurs non initialisees */ +if ( VariablesDualesDesContraintesE != NULL ) { + i = 0; + for ( CntE = 0 ; CntE < NombreDeContraintesE ; CntE++ ) { + if ( VariablesDualesDesContraintesE[CntE] > VALEUR_NON_INITIALISEE ) { + printf("Fin du PostSolve: variable duale de la contrainte %d pas initialisee\n",CntE); + i++; + } + } + if ( i != 0 ) printf("Nombre de variables duales non initialisees %d sur %d\n",i,NombreDeContraintesE); +} + +for ( VarE = 0 ; VarE < NombreDeVariablesE ; VarE++ ) { + if ( UE[VarE] > VALEUR_NON_INITIALISEE ) { + printf("Fin du PostSolve: valeur de la variable %d pas initialisee\n",VarE); + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + diff --git a/src/ext/Sirius_Solver/pne/pne_reduced_cost_fixing.c b/src/ext/Sirius_Solver/pne/pne_reduced_cost_fixing.c new file mode 100644 index 0000000000..23b553daec --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_reduced_cost_fixing.c @@ -0,0 +1,239 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Reduced cost fixing (necessite d'avoir obtenu une premiere + solution entiere) + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +char PNE_ReducedCostFixing( PROBLEME_PNE * Pne, int * PositionDeLaVariable ) +{ +int i; double Delta; double h; char RelancerUnSimplexe; int * TypeDeBorne; +int * TypeDeVariable; double * Umin; double * Umax; double * CoutsReduits; +NOEUD * Noeud; int * NumeroDeLaVariableModifiee; char * TypeDeBorneModifiee; +double *NouvelleValeurDeBorne ; int NombreDeBornesModifiees; int NbModifs; +BB * Bb; char * T; int * TGraph; int Nb; int * Num; int j; int Arret; +int NombreDeVariablesNonFixes; int * NumeroDesVariablesNonFixes; +int NombreDeVariables; int Var; + +RelancerUnSimplexe = NON_PNE; + +# if REDUCED_COST_FIXING_AUX_NOEUD_DANS_ARBRE == NON_PNE + return( RelancerUnSimplexe ); +# endif + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeVariablesNonFixes = Pne->NombreDeVariablesNonFixes; +NumeroDesVariablesNonFixes = Pne->NumeroDesVariablesNonFixes; + +TGraph = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +if ( TGraph == NULL ) return( RelancerUnSimplexe ); +Num = (int *) malloc( Pne->NombreDeVariablesEntieresTrav * sizeof( int ) ); +if ( Num == NULL ) { + free( TGraph ); + return( RelancerUnSimplexe ); +} +Nb = 0; +memset( (char *) TGraph, 0, Pne->NombreDeVariablesTrav * sizeof( int ) ); + +Bb = Pne->ProblemeBbDuSolveur; +Noeud = Bb->NoeudEnExamen; + +T = (char *) malloc( ( Bb->NombreDeVariablesDuProbleme ) * sizeof(char) ); +if ( T == NULL ) return( RelancerUnSimplexe ); + +memset( (char *) T, 0, Bb->NombreDeVariablesDuProbleme * sizeof( char ) ); + +NombreDeBornesModifiees = Noeud->NombreDeBornesModifiees; +NumeroDeLaVariableModifiee = Noeud->NumeroDeLaVariableModifiee; + +for( i = 0 ; i < NombreDeBornesModifiees ; i++ ) { + T[NumeroDeLaVariableModifiee[i]] = 1; +} + +TypeDeBorne = Pne->TypeDeBorneTrav; +Umin = Pne->UminTrav; +Umax = Pne->UmaxTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +CoutsReduits = Pne->CoutsReduits; + +Delta = Pne->CoutOpt - Pne->Critere; +if ( Delta < 0. ) Delta = 0.; /* Car le cout entier est toujours superieur ou egal au cout relaxe */ + +NbModifs = 0; + +/* Premier passage: decompte des modifs de borne */ +for( i = 0 ; i < NombreDeVariablesNonFixes ; i++ ) { + + Var = NumeroDesVariablesNonFixes[i]; + + if ( TypeDeVariable[Var] != ENTIER ) continue; + + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) continue; + if ( fabs( Umax[Var] - Umin[Var] ) < ZERO_VARFIXE ) continue; + if ( fabs( CoutsReduits[Var] ) < ZERO_COUT_REDUIT ) continue; + if ( T[Var] != 0 ) continue; + + h = 0.0; + Nb = 0; + + if( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + /* On regarde ce qu'il se passe si la variable passe a 0 */ + Arret = NON_PNE; + PNE_ReducedCostFixingConflictGraph( Pne, Var, Umin[Var], &h, Delta, CoutsReduits, Umin, Umax, PositionDeLaVariable, &Nb, TGraph, Num, &Arret ); + for ( j = 0 ; j < Nb ; j++ ) TGraph[Num[j]] = 0; + if ( h > Delta ) { + /* Mise a jour des bornes des contraintes */ + NbModifs++; + } + } + else if( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + /* On regarde ce qu'il se passe si la variable passe a 1 */ + Arret = NON_PNE; + PNE_ReducedCostFixingConflictGraph( Pne, Var, Umax[Var], &h, Delta, CoutsReduits, Umin, Umax, PositionDeLaVariable, &Nb, TGraph, Num, &Arret ); + for ( j = 0 ; j < Nb ; j++ ) TGraph[Num[j]] = 0; + if ( h > Delta ) { + /* Mise a jour des bornes des contraintes */ + NbModifs++; + } + } +} + +if ( NbModifs == 0 ) goto FinReducedCostFixing; + +i = NombreDeBornesModifiees + NbModifs; +Noeud->NumeroDeLaVariableModifiee = (int *) realloc( Noeud->NumeroDeLaVariableModifiee, i * sizeof( int ) ); +if ( Noeud->NumeroDeLaVariableModifiee == NULL ) { + free( Noeud->TypeDeBorneModifiee ); + free( Noeud->NouvelleValeurDeBorne ); + Noeud->TypeDeBorneModifiee = NULL; + Noeud->NouvelleValeurDeBorne = NULL; + Noeud->NombreDeBornesModifiees = 0; + goto FinReducedCostFixing; +} +Noeud->TypeDeBorneModifiee = (char *) realloc( Noeud->TypeDeBorneModifiee, i * sizeof( char ) ); +if ( Noeud->TypeDeBorneModifiee == NULL ) { + free( Noeud->NumeroDeLaVariableModifiee ); + free( Noeud->NouvelleValeurDeBorne ); + Noeud->NumeroDeLaVariableModifiee = NULL; + Noeud->NouvelleValeurDeBorne = NULL; + Noeud->NombreDeBornesModifiees = 0; + goto FinReducedCostFixing; +} +Noeud->NouvelleValeurDeBorne = (double *) realloc( Noeud->NouvelleValeurDeBorne, i * sizeof( double ) ); +if ( Noeud->NouvelleValeurDeBorne == NULL ) { + free( Noeud->NumeroDeLaVariableModifiee ); + free( Noeud->TypeDeBorneModifiee ); + Noeud->NumeroDeLaVariableModifiee = NULL; + Noeud->TypeDeBorneModifiee = NULL; + Noeud->NombreDeBornesModifiees = 0; + goto FinReducedCostFixing; +} + +NumeroDeLaVariableModifiee = Noeud->NumeroDeLaVariableModifiee; +TypeDeBorneModifiee = Noeud->TypeDeBorneModifiee; +NouvelleValeurDeBorne = Noeud->NouvelleValeurDeBorne; + +for( i = 0 ; i < NombreDeVariablesNonFixes ; i++ ) { + + Var = NumeroDesVariablesNonFixes[i]; + + /* On ne peut pas modifier les bornes des variables continues si on est amenes calculer des coupes + qui se servent des bornes min et max de ces variables car alors elle ne seront plus valables + pour tout l'arbre */ + /* On pourrait autoriser les modifs de bornes des variables continues a condition de marquer le noeud + et tous ses descendants pour ne pas calculer de coupes dessus */ + + if ( TypeDeVariable[Var] != ENTIER ) continue; + + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) continue; + if ( fabs( Umax[Var] - Umin[Var] ) < ZERO_VARFIXE ) continue; + if ( fabs( CoutsReduits[Var] ) < ZERO_COUT_REDUIT ) continue; + if ( T[Var] != 0 ) continue; + + h = 0.0; + Nb = 0; + + if( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + /* On regarde ce qu'il se passe si la variable passe a 0 */ + Arret = NON_PNE; + PNE_ReducedCostFixingConflictGraph( Pne, Var, Umin[Var], &h, Delta, CoutsReduits, Umin, Umax, PositionDeLaVariable, &Nb, TGraph, Num, &Arret ); + for ( j = 0 ; j < Nb ; j++ ) TGraph[Num[j]] = 0; + if ( h > Delta ) { + /* La variable entiere sera donc fixee a 1 */ + /* Mise a jour de la borne inf */ + Umin[Var] = Umax[Var]; + RelancerUnSimplexe = OUI_PNE; + NumeroDeLaVariableModifiee[NombreDeBornesModifiees] = Var; + TypeDeBorneModifiee[NombreDeBornesModifiees] = BORNE_INF; + NouvelleValeurDeBorne[NombreDeBornesModifiees] = Umin[Var]; + NombreDeBornesModifiees++; + } + } + else if( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + /* On regarde ce qu'il se passe si la variable passe a 1 */ + Arret = NON_PNE; + PNE_ReducedCostFixingConflictGraph( Pne, Var, Umax[Var], &h, Delta, CoutsReduits, Umin, Umax, PositionDeLaVariable, &Nb, TGraph, Num, &Arret ); + for ( j = 0 ; j < Nb ; j++ ) TGraph[Num[j]] = 0; + if ( h > Delta ) { + /* La variable entiere sera donc fixee a 0 */ + /* Mise a jour de la borne sup */ + Umax[Var] = Umin[Var]; + RelancerUnSimplexe = OUI_PNE; + NumeroDeLaVariableModifiee[NombreDeBornesModifiees] = Var; + TypeDeBorneModifiee[NombreDeBornesModifiees] = BORNE_SUP; + NouvelleValeurDeBorne[NombreDeBornesModifiees] = Umax[Var]; + NombreDeBornesModifiees++; + } + } +} + +Noeud->NombreDeBornesModifiees = NombreDeBornesModifiees; + +FinReducedCostFixing: +free( T ); +free( TGraph ); +free( Num ); + +/* +if ( Pne->AffichageDesTraces == OUI_PNE ) { + if ( NbModifs != 0 ) printf("Reduced cost fixing at current node. Variables fixed at one of its bounds: %d\n",NbModifs); +} +*/ + +return( RelancerUnSimplexe ); +} + + diff --git a/src/ext/Sirius_Solver/pne/pne_reduced_cost_fixing_graphe_de_conflit.c b/src/ext/Sirius_Solver/pne/pne_reduced_cost_fixing_graphe_de_conflit.c new file mode 100644 index 0000000000..77562566e8 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_reduced_cost_fixing_graphe_de_conflit.c @@ -0,0 +1,115 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On applique le graphe de conflit quand on simule l'instanciation + d'une variable dans le reduced cost fixing. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_ReducedCostFixingConflictGraph( PROBLEME_PNE * Pne, int VariableFixee, + double ValeurVariableFixee, + double * DeltaCout, double Delta, double * CoutsReduits, + double * Xmin, double * Xmax, + int * PositionDeLaVariable, int * Nb, int * T, int * Num, + int * Arret ) +{ +int Pivot; int Noeud; int Edge; int Complement; int Nv; int * Adjacent; int * Next; +int * First; CONFLICT_GRAPH * ConflictGraph; + +if ( T[VariableFixee] == 1 ) return; + +if ( ValeurVariableFixee == 1 ) { + if( PositionDeLaVariable[VariableFixee] == HORS_BASE_SUR_BORNE_INF ) { + *DeltaCout = *DeltaCout + fabs( CoutsReduits[VariableFixee] * ( Xmax[VariableFixee] - Xmin[VariableFixee] ) ); + } +} +else { + if( PositionDeLaVariable[VariableFixee] == HORS_BASE_SUR_BORNE_SUP ) { + *DeltaCout = *DeltaCout + fabs( CoutsReduits[VariableFixee] * ( Xmax[VariableFixee] - Xmin[VariableFixee] ) ); + } +} + +if ( *DeltaCout > Delta ) { + *DeltaCout = *DeltaCout + 1.e-8; + *Arret = OUI_PNE; + return; +} + +Num[*Nb] = VariableFixee; +*Nb = *Nb + 1; +T[VariableFixee] = 1; + +ConflictGraph = Pne->ConflictGraph; +if ( ConflictGraph == NULL ) return; +Adjacent = ConflictGraph->Adjacent; +Next = ConflictGraph->Next; +First = ConflictGraph->First; +Pivot = ConflictGraph->Pivot; + +Noeud = VariableFixee; +Complement = VariableFixee + Pivot; +if ( ValeurVariableFixee == 0.0 ) { + Noeud = VariableFixee + Pivot; + Complement = VariableFixee; +} + +if ( First[Noeud] < 0 ) return; + +Edge = First[Noeud]; +while ( Edge >= 0 ) { + Nv = Adjacent[Edge]; + if ( Nv == Complement ) goto NextEdge; + if ( Nv < Pivot ) { + /* La valeur 1 de Nv est interdite on doit la passer a 0 et on regarde son impact avec le cout reduit */ + VariableFixee = Nv; + ValeurVariableFixee = Xmin[VariableFixee]; + PNE_ReducedCostFixingConflictGraph( Pne, VariableFixee, ValeurVariableFixee, DeltaCout, Delta, CoutsReduits, Xmin, Xmax, + PositionDeLaVariable, Nb, T, Num, Arret ); + if ( *Arret == OUI_PNE ) break; + } + else { + /* La valeur 0 de Nv est interdite on doit la passer a 1 et on regarde son impact avec le cout reduit */ + VariableFixee = Nv - Pivot; + ValeurVariableFixee = Xmax[VariableFixee]; + PNE_ReducedCostFixingConflictGraph( Pne, VariableFixee, ValeurVariableFixee, DeltaCout, Delta, CoutsReduits, Xmin, Xmax, + PositionDeLaVariable, Nb, T, Num, Arret ); + if ( *Arret == OUI_PNE ) break; + } + NextEdge: + Edge = Next[Edge]; +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_reduced_cost_fixing_noeud_racine.c b/src/ext/Sirius_Solver/pne/pne_reduced_cost_fixing_noeud_racine.c new file mode 100644 index 0000000000..563522f8c2 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_reduced_cost_fixing_noeud_racine.c @@ -0,0 +1,506 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Reduced cost fixing au noeud racine. Appele a chaque fois + qu'on trouve une nouvelle solution entiere pour fixer certaines + variables en fonction de la valeur de leur cout reduit au + noeud racine. + Remarque: si on fixe des variables on pourrait en profiter + pour refaire un probing avec determination de nouvelles + cliques. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 0 +# define TEST_RELANCE_BRANCH_AND_BOUND 0 + +# define MARGE_CONTINUE 10 +# define MARGE_DE_SECURITE 0.05 + +void PNE_ReducedCostFixingAuNoeudRacineRechercheNouvellesIncompatibilites( PROBLEME_PNE * , double , int * , int , double , int , int * , + int * , char * , double * , double * , double * , int * ); + +/*----------------------------------------------------------------------------*/ + +void PNE_ArchivagesPourReducedCostFixingAuNoeudRacine( PROBLEME_PNE * Pne, + int * PositionDeLaVariable, + double * CoutsReduits, + double Critere ) +{ +int i ; double * CoutsReduitsAuNoeudRacine; int * PositionDeLaVariableAuNoeudRacine; +double MxCoutReduit; double * Umin; double * Umax; double X; int * TypeDeBorneTrav; + +if ( Pne->CoutsReduitsAuNoeudRacine == NULL ) { + Pne->CoutsReduitsAuNoeudRacine = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); + if ( Pne->CoutsReduitsAuNoeudRacine == NULL ) return; +} + +if ( Pne->PositionDeLaVariableAuNoeudRacine == NULL ) { + Pne->PositionDeLaVariableAuNoeudRacine = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); + if ( Pne->PositionDeLaVariableAuNoeudRacine == NULL ) { + free( Pne->CoutsReduitsAuNoeudRacine ); + return; + } +} + +CoutsReduitsAuNoeudRacine = Pne->CoutsReduitsAuNoeudRacine; +PositionDeLaVariableAuNoeudRacine = Pne->PositionDeLaVariableAuNoeudRacine; + +Pne->CritereAuNoeudRacine = Critere; + +MxCoutReduit = -1; +Umin = Pne->UminTrav; +Umax = Pne->UmaxTrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + PositionDeLaVariableAuNoeudRacine[i] = PositionDeLaVariable[i]; + CoutsReduitsAuNoeudRacine[i] = CoutsReduits[i]; + X = fabs( CoutsReduits[i] * ( Umax[i] - Umin[i] ) ); + if ( TypeDeBorneTrav[i] != VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( X > MxCoutReduit ) { + MxCoutReduit = X; + } + } +} + +Pne->MxCoutReduitAuNoeudRacineFoisDeltaBornes = MxCoutReduit; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Appele a chaque fois qu'on trouve une solution entiere */ +void PNE_ReducedCostFixingAuNoeudRacine( PROBLEME_PNE * Pne ) +{ +int Var; double Delta; double h; int * TypeDeBorne; int * TypeDeVariable; int Arret; +double * CoutsReduits; int * PositionDeLaVariable; int NbFix; int * T; int Nb; +int * Num; int j; PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; int NombreDeVariables; +double NouvelleValeur; char * SensContrainte; double * B; char * ContrainteActivable; +int Cnt; int NbCntRelax; int NombreDeContraintes; int NbFixBin; int Faisabilite; +char * BorneSupConnue; double * ValeurDeBorneSup; char * BorneInfConnue; double * ValeurDeBorneInf; +char BrnInfConnue; char BorneMiseAJour; char UneVariableAEteFixee; double * Umin; +double * UminSv; double * Umax; double * UmaxSv; char * BminValide; char * BmaxValide; +double * BminSv; double * BmaxSv; double * Bmin; double * Bmax; char Mode; +int NombreDeVariablesNonFixes; int * NumeroDesVariablesNonFixes; int i; int NbBranchesAjoutees; +# if TEST_RELANCE_BRANCH_AND_BOUND == 1 + BB * Bb; +# endif + +# if REDUCED_COST_FIXING_AU_NOEUD_RACINE == NON_PNE + return; +# endif + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; +if ( ProbingOuNodePresolve == NULL ) return; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +NombreDeVariablesNonFixes = Pne->NombreDeVariablesNonFixes; +NumeroDesVariablesNonFixes = Pne->NumeroDesVariablesNonFixes; + +T = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( T == NULL ) return; +Num = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Num == NULL ) { + free( T ); + return; +} +Nb = 0; +memset( (char *) T, 0, NombreDeVariables * sizeof( int ) ); + +TypeDeVariable = Pne->TypeDeVariableTrav; + +/* Attention c'est le type de borne au noeud racine qu'il faut prendre */ +memcpy( (char *) Pne->TypeDeBorneTrav, (char *) Pne->TypeDeBorneTravSv, NombreDeVariables * sizeof( int ) ); +TypeDeBorne = Pne->TypeDeBorneTrav; + +Umin = Pne->UminTrav; +UminSv = Pne->UminTravSv; +Umax = Pne->UmaxTrav; +UmaxSv = Pne->UmaxTravSv; + +/* Attention c'est Umin au noeud racine qu'il faut prendre */ +memcpy( (char *) Umin, (char *) UminSv, NombreDeVariables * sizeof( double ) ); +/* Attention c'est Umax au noeud racine qu'il faut prendre */ +memcpy( (char *) Umax, (char *) UmaxSv, NombreDeVariables * sizeof( double ) ); + +/* Initialisation des bornes inf et sup des variables */ +PNE_InitBorneInfBorneSupDesVariables( Pne ); + +BorneSupConnue = ProbingOuNodePresolve->BorneSupConnue; +ValeurDeBorneSup = ProbingOuNodePresolve->ValeurDeBorneSup; +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; + +CoutsReduits = Pne->CoutsReduitsAuNoeudRacine; +PositionDeLaVariable = Pne->PositionDeLaVariableAuNoeudRacine; + +/* On recupere les bornes des contraintes au noeud racine */ +Bmin = ProbingOuNodePresolve->Bmin; +Bmax = ProbingOuNodePresolve->Bmax; +BminSv = ProbingOuNodePresolve->BminSv; +BmaxSv = ProbingOuNodePresolve->BmaxSv; +memcpy( (char *) Bmin, (char *) BminSv, NombreDeContraintes * sizeof( double ) ); +memcpy( (char *) Bmax, (char *) BmaxSv, NombreDeContraintes * sizeof( double ) ); +BminValide = ProbingOuNodePresolve->BminValide; +BmaxValide = ProbingOuNodePresolve->BmaxValide; + +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; +ContrainteActivable = Pne->ContrainteActivable; + +Delta = Pne->CoutOpt - Pne->CritereAuNoeudRacine; +if ( Delta < 0. ) Delta = 0.; /* Car le cout entier est toujours superieur ou egal au cout relaxe */ + +Mode = PRESOLVE_SIMPLIFIE_POUR_REDUCED_COST_FIXING_AU_NOEUD_RACINE; + +NbFix = 0; +NbFixBin = 0; +NbCntRelax = 0; +NbBranchesAjoutees = 0; + +ProbingOuNodePresolve->Faisabilite = OUI_PNE; +ProbingOuNodePresolve->VariableInstanciee = -1; +ProbingOuNodePresolve->NbVariablesModifiees = 0; +ProbingOuNodePresolve->NbContraintesModifiees = 0; +Faisabilite = OUI_PNE; + +for ( i = 0 ; i < NombreDeVariablesNonFixes ; i++ ) { + + Var = NumeroDesVariablesNonFixes[i]; + + /*if ( TypeDeVariable[Var] != ENTIER ) continue;*/ + + if ( fabs( CoutsReduits[Var] ) < ZERO_COUT_REDUIT ) continue; + + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) continue; + + h = 0.0; + Nb = 0; + + if ( TypeDeVariable[Var] == ENTIER ) { + if( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + /* On regarde ce qu'il se passe si la variable passe a 0 */ + Arret = NON_PNE; + + PNE_ReducedCostFixingConflictGraph( Pne, Var, ValeurDeBorneInf[Var], &h, Delta, CoutsReduits, ValeurDeBorneInf, ValeurDeBorneSup, + PositionDeLaVariable, &Nb, T, Num, &Arret ); + if ( h > Delta ) { + /* La variable entiere est fixee a Umax */ + BorneMiseAJour = NON_PNE; + UneVariableAEteFixee = FIXATION_SUR_BORNE_SUP; + NouvelleValeur = ValeurDeBorneSup[Var]; + /* Applique le graphe de conflit s'il y a lieu, modifie Bmin et Bmax, fixe les variables entieres du graphe + si necessaire */ + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + + NbFix++; + NbFixBin++; + } + else { + /* On regarde les incompatibilites avec les variables qui ne sont pas dans le graphe de conflit */ + PNE_ReducedCostFixingAuNoeudRacineRechercheNouvellesIncompatibilites( Pne, Delta, T, Var, ValeurDeBorneInf[Var], NombreDeVariables, + TypeDeVariable, PositionDeLaVariable, BorneInfConnue, + ValeurDeBorneInf, ValeurDeBorneSup, CoutsReduits, &NbBranchesAjoutees ); + } + for ( j = 0 ; j < Nb ; j++ ) T[Num[j]] = 0; + } + else if( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + /* On regarde ce qu'il se passe si la variable passe a 1 */ + Arret = NON_PNE; + PNE_ReducedCostFixingConflictGraph( Pne, Var, ValeurDeBorneSup[Var], &h, Delta, CoutsReduits, ValeurDeBorneInf, ValeurDeBorneSup, + PositionDeLaVariable, &Nb, T, Num, &Arret ); + if ( h > Delta ) { + /* La variable entiere sest fixee a Umin */ + BorneMiseAJour = NON_PNE; + UneVariableAEteFixee = FIXATION_SUR_BORNE_INF; + NouvelleValeur = ValeurDeBorneInf[Var]; + /* Applique le graphe de conflit s'il y a lieu, modifie Bmin et Bmax, fixe les variables entieres du graphe + si necessaire */ + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + + NbFix++; + NbFixBin++; + } + else { + /* On regarde les incompatibilites avec les variables qui ne sont pas dans le graphe de conflit */ + PNE_ReducedCostFixingAuNoeudRacineRechercheNouvellesIncompatibilites( Pne, Delta, T, Var, ValeurDeBorneSup[Var], NombreDeVariables, + TypeDeVariable, PositionDeLaVariable, BorneInfConnue, + ValeurDeBorneInf, ValeurDeBorneSup, CoutsReduits, &NbBranchesAjoutees ); + } + for ( j = 0 ; j < Nb ; j++ ) T[Num[j]] = 0; + } + } + else if ( TypeDeBorne[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + h = fabs( CoutsReduits[Var] * ( ValeurDeBorneSup[Var] - ValeurDeBorneInf[Var] ) ); + /* Variable continue */ + if( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + /* On regarde ce qu'il se passe si la variable passe a ValeurdeBorneSup */ + if ( h > Delta ) { + NouvelleValeur = ( Delta / fabs( CoutsReduits[Var] ) ) + ValeurDeBorneInf[Var]; + if ( ValeurDeBorneSup[Var] - NouvelleValeur > MARGE_CONTINUE ) { + /* On abaisse la borne sup */ + BorneMiseAJour = MODIF_BORNE_SUP; + UneVariableAEteFixee = NON_PNE; + NouvelleValeur = ( MARGE_DE_SECURITE * ValeurDeBorneSup[Var] ) + ( NouvelleValeur * ( 1 - MARGE_DE_SECURITE ) ); + # if TRACES == 1 + printf("On peut abaisser la borne Sup de la variable %d : %e -> %e abaissement %e CoutsReduits %e\n", + Var,ValeurdeBorneSup[Var],NouvelleValeur,ValeurdeBorneSup[Var]-NouvelleValeur,CoutsReduits[Var]); + # endif + /* Applique le graphe de conflit s'il y a lieu, modifie Bmin et Bmax, fixe les variables entieres du graphe + si necessaire */ + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + + NbFix++; + } + } + } + else if( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + /* On regarde ce qu'il se passe si la variable passe a Xmin */ + if ( h > Delta ) { + NouvelleValeur = ValeurDeBorneSup[Var] - ( Delta / fabs( CoutsReduits[Var] ) ); + if ( NouvelleValeur - ValeurDeBorneInf[Var] > MARGE_CONTINUE ) { + /* On remonte la borne inf */ + BorneMiseAJour = MODIF_BORNE_INF; + UneVariableAEteFixee = NON_PNE; + NouvelleValeur = ( MARGE_DE_SECURITE * ValeurDeBorneInf[Var] ) + ( NouvelleValeur * ( 1 - MARGE_DE_SECURITE ) ); + # if TRACES == 1 + printf("On peut relever la borne Inf de la variable %d : %e -> %e relevement %e Umax %e CoutsReduits %e\n", + Var,ValeurDeBorneInf[Var],NouvelleValeur,NouvelleValeur-ValeurDeBorneInf[Var],ValeurdeBorneSup[Var],CoutsReduits[Var]); + # endif + /* Applique le graphe de conflit s'il y a lieu, modifie Bmin et Bmax, fixe les variables entieres du graphe + si necessaire */ + PNE_VariableProbingAppliquerLeConflictGraph( Pne, Var, NouvelleValeur, BorneMiseAJour, UneVariableAEteFixee ); + + NbFix++; + } + } + } + } +} + +free( T ); +free( Num ); + +/* Pour l'instant on n'utilise pas Faisabilite */ +PNE_PresolveSimplifie( Pne, ContrainteActivable, Mode, &Faisabilite ); +if ( Faisabilite == NON_PNE ) { + /* + if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Alert: PNE_PresolveSimplifie report infeasability after reduced cost fixing. Problem may be infaisible\n"); + } + */ +} + +# if TEST_RELANCE_BRANCH_AND_BOUND == 1 + /* On regarde si on a pu fixer des variables ou abaisser des bornes afin de lancer un presolve plus + complet si c'est prometteur */ + NbFix = 0; + NbFixBin = 0; + for ( i = 0 ; i < NombreDeVariablesNonFixes ; i++ ) { + Var = NumeroDesVariablesNonFixes[i]; + if ( BorneInfConnue[Var] == FIXE_AU_DEPART ) continue; + if ( TypeDeVariable[Var] == ENTIER ) { + if ( ValeurDeBorneInf[Var] > Umin[Var] + 1.e-6 ) { NbFix++; NbFixBin++; } + if ( ValeurDeBorneSup[Var] < Umax[Var] - 1.e-6 ) { NbFix++; NbFixBin++; } + } + else { + if ( ValeurDeBorneInf[Var] > Umin[Var] + 1.e-6 ) NbFix++; + if ( ValeurDeBorneSup[Var] < Umax[Var] - 1.e-6 ) NbFix++; + } + if ( NbFixBin > 0 || NbFix > 10 ) { + Bb = (BB *) Pne->ProblemeBbDuSolveur; + if ( Pne->Controls == NULL ) { + PNE_BranchAndBoundIntermediare( Pne, Bb->ValeurDuMeilleurMinorant ); + break; + } + } + } +# endif + +/* Synthese */ +/* On recupere Umin, Umax */ + +NbFix = 0; +NbFixBin = 0; + +for ( i = 0 ; i < NombreDeVariablesNonFixes ; i++ ) { + + Var = NumeroDesVariablesNonFixes[i]; + + if ( BorneInfConnue[Var] == FIXE_AU_DEPART ) continue; + if ( TypeDeVariable[Var] == ENTIER ) { + if ( ValeurDeBorneInf[Var] > Umin[Var] + 1.e-6 ) { NbFix++; NbFixBin++; } + Umin[Var] = ValeurDeBorneInf[Var]; + UminSv[Var] = ValeurDeBorneInf[Var]; + if ( ValeurDeBorneSup[Var] < Umax[Var] - 1.e-6 ) { NbFix++; NbFixBin++; } + Umax[Var] = ValeurDeBorneSup[Var]; + UmaxSv[Var] = ValeurDeBorneSup[Var]; + } + else { + if ( ValeurDeBorneInf[Var] > Umin[Var] + 1.e-6 ) NbFix++; + if ( ValeurDeBorneSup[Var] < Umax[Var] - 1.e-6 ) NbFix++; + + Umax[Var] = ValeurDeBorneSup[Var]; + UmaxSv[Var] = ValeurDeBorneSup[Var]; + } +} + +/* On recalcule Bmin Bmax */ +PNE_InitBorneInfBorneSupDesVariables( Pne ); +PNE_CalculMinEtMaxDesContraintes( Pne, &Faisabilite ); +/* Et on sauvegarde le resultat comme point de depart pour les noeuds suivants */ +memcpy( (char *) BminSv, (char *) Bmin, NombreDeContraintes * sizeof( double ) ); +memcpy( (char *) BmaxSv, (char *) Bmax, NombreDeContraintes * sizeof( double ) ); + +/* Contraintes inactives */ + +NbCntRelax = 0; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteActivable[Cnt] == NON_PNE ) NbCntRelax++; + else { + if ( SensContrainte[Cnt] == '<' ) { + if ( BmaxValide[Cnt] == OUI_PNE ) { + if ( Bmax[Cnt] < B[Cnt] - 1.e-6 ) { + ContrainteActivable[Cnt] = NON_PNE; + NbCntRelax++; + } + } + } + } +} + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + if ( NbFix != 0 || NbCntRelax != 0 || NbBranchesAjoutees != 0 ) { + printf("Reduced cost fixing at root node: \n"); + if ( NbFix != 0 ) printf(" Bounds tightened: %d of which %d binarie(s)\n",NbFix,NbFixBin); + if ( NbBranchesAjoutees != 0 ) printf(" %d implications added. Conflict graph has %d edges\n",NbBranchesAjoutees,Pne->ConflictGraph->NbEdges); + if ( NbCntRelax != 0 ) printf(" Useless constraints: %d over %d\n",NbCntRelax,NombreDeContraintes); + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_ReducedCostFixingAuNoeudRacineRechercheNouvellesIncompatibilites( PROBLEME_PNE * Pne, double Delta, int * T, + int VarEtudiee, double ValeurDeVariableEtudiee, + int NombreDeVariables, int * TypeDeVariable, + int * PositionDeLaVariable, char * BorneInfConnue, + double * ValeurDeBorneInf, double * ValeurDeBorneSup, + double * CoutsReduits, int * NbEdges ) +{ +int Var; char BrnInfConnue; int PosVariable; double DeltaCout; double h; + +int * Cdeb; int * Csui; int * NumContrainte; int * Mdeb; int * NbTerm; int * Nuvar; int ic; int il; int ilMax; int Cnt; char OnPrend; + +return; /* Ca marche mais ca sert a rien et ca consomme du temps */ + +DeltaCout = fabs( CoutsReduits[VarEtudiee] * ( ValeurDeBorneSup[VarEtudiee] - ValeurDeBorneInf[VarEtudiee] ) ); + +h = fabs( Pne->CoutOpt ) * 0.01; +if ( h < 1 ) h = 1; +if ( h > 1000 ) h = 1000; + +Delta += h; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; + +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; + +for ( Var = VarEtudiee + 1 ; Var < NombreDeVariables ; Var++ ) { + + if ( TypeDeVariable[Var] != ENTIER ) continue; + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) continue; + if ( T[Var] == 1 ) continue; + PosVariable = PositionDeLaVariable[Var]; + if( PosVariable == HORS_BASE_SUR_BORNE_INF || PosVariable == HORS_BASE_SUR_BORNE_SUP ) { + /* On change la variable de borne */ + h = DeltaCout + fabs( CoutsReduits[Var] * ( ValeurDeBorneSup[Var] - ValeurDeBorneInf[Var] ) ); + if ( h > Delta ) { + + /* Si on trouve une contrainte native avec les 2 variables, seulles on ne cree pas l'implication */ + OnPrend = OUI_PNE; + ic = Cdeb[VarEtudiee]; + while ( ic >= 0 && OnPrend == OUI_PNE ) { + Cnt = NumContrainte[ic]; + if ( NbTerm[Cnt] == 2 ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( Nuvar[il] == Var ) { + OnPrend = NON_PNE; + break; + } + il++; + } + } + ic = Csui[ic]; + } + if ( OnPrend == NON_PNE ) continue; + + if( PosVariable == HORS_BASE_SUR_BORNE_INF ) { + /* On ne peut pas la passer a 1 */ + BorneInfConnue[Var] = FIXATION_SUR_BORNE_INF; + } + else { + /* On ne peut pas la passer a 0 */ + BorneInfConnue[Var] = FIXATION_SUR_BORNE_SUP; + } + + Pne->ProbingOuNodePresolve->NumeroDesVariablesFixees[0] = Var; + Pne->ProbingOuNodePresolve->NombreDeVariablesFixees = 1; + + PNE_MajConflictGraph( Pne, VarEtudiee, ValeurDeVariableEtudiee ); + + /* On recupere l'information sur la borne inf */ + *NbEdges = *NbEdges + 1; + BorneInfConnue[Var] = BrnInfConnue; + Pne->ProbingOuNodePresolve->NombreDeVariablesFixees = 0; + + } + } +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_relance_simplexe_au_noeud_racine.c b/src/ext/Sirius_Solver/pne/pne_relance_simplexe_au_noeud_racine.c new file mode 100644 index 0000000000..14b913f9b8 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_relance_simplexe_au_noeud_racine.c @@ -0,0 +1,269 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Relance du simplex au noeud racine en cours de branch and bound. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_constantes_externes.h" +# include "spx_definition_arguments.h" +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +typedef struct{ +int NombreDeCoupes; +double * SecondMembre; +char * PositionDeLaVariableDEcart; +/* Chainage de la matrice des contraintes */ +int * Mdeb; +int * NbTerm; +int * Colonne; +double * A; +} COUPES_SIMPLEXE_NOEUD_RACINE; + +void PNE_LibererCoupesVioleesPourSimplexeAuNoeudRacine( COUPES_SIMPLEXE_NOEUD_RACINE * ); +COUPES_SIMPLEXE_NOEUD_RACINE * PNE_AjouterCoupesVioleesPourSimplexeAuNoeudRacine( PROBLEME_PNE * ); + +/*----------------------------------------------------------------------------*/ +void PNE_LibererCoupesVioleesPourSimplexeAuNoeudRacine( COUPES_SIMPLEXE_NOEUD_RACINE * C ) +{ +free( C->SecondMembre ); free( C->PositionDeLaVariableDEcart ); free( C->Mdeb ); free( C->NbTerm ); +free( C->Colonne );free( C->A );free( C ); +return; +} +/*----------------------------------------------------------------------------*/ +/* On insere les contraintes du pool qui sont violees par la solution courante */ +COUPES_SIMPLEXE_NOEUD_RACINE * PNE_AjouterCoupesVioleesPourSimplexeAuNoeudRacine( PROBLEME_PNE * Pne ) +{ +BB * Bb; NOEUD * NoeudRacine; int NumeroDeCoupe; COUPE ** Coupe; COUPE * Cpe; +double * X; int * IndiceDeLaVariable; double * Coefficient; double S; +char * T; int ilCoupes; int NombreDeCoupes; int il; int NbCoupes; int i; +int * Mdeb; int * NbTerm; double * SecondMembre; char * PositionDeLaVariableDEcart; +int * Colonne; double * A; COUPES_SIMPLEXE_NOEUD_RACINE * CoupesPourLeSimplexe; + +Bb = Pne->ProblemeBbDuSolveur; +if ( Bb == NULL ) return( NULL ); +NoeudRacine = Bb->NoeudRacine; +Coupe = NoeudRacine->CoupesGenereesAuNoeud; +X = Pne->MatriceDesContraintesAuNoeudRacine->X; +NombreDeCoupes = NoeudRacine->NombreDeCoupesGenereesAuNoeud; + +T = (char *) malloc( NombreDeCoupes * sizeof( char ) ); +if ( T == NULL ) return( NULL ); +memset( (char *) T, 0, NombreDeCoupes * sizeof( char ) ); + +ilCoupes = 0; +NbCoupes = 0; +for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < NombreDeCoupes ; NumeroDeCoupe++ ) { + S = 0.; + Cpe = Coupe[NumeroDeCoupe]; + Coefficient = Cpe->Coefficient; + IndiceDeLaVariable = Cpe->IndiceDeLaVariable; + for ( il = 0 ; il < Cpe->NombreDeTermes ; il++ ) S += Coefficient[il] * X[IndiceDeLaVariable[il]]; + if ( S > Cpe->SecondMembre ) { + T[NumeroDeCoupe] = 1; + ilCoupes += Cpe->NombreDeTermes; + NbCoupes++; + } +} + +if ( NbCoupes <= 0 ) { + free( T ); + return( NULL ); +} + +CoupesPourLeSimplexe = malloc( sizeof( COUPES_SIMPLEXE_NOEUD_RACINE ) ); +Mdeb = (int *) malloc( NbCoupes * sizeof( int ) ); +NbTerm = (int *) malloc( NbCoupes * sizeof( int ) ); +SecondMembre = (double *) malloc( NbCoupes * sizeof( double ) ); +PositionDeLaVariableDEcart = (char *) malloc( NbCoupes * sizeof( char ) ); +ilCoupes += 10; +Colonne = (int *) malloc( ilCoupes * sizeof( int ) ); +A = (double *) malloc( ilCoupes * sizeof( double ) ); +if ( A == NULL || Colonne == NULL || PositionDeLaVariableDEcart == NULL || SecondMembre == NULL || + NbTerm == NULL || Mdeb == NULL || CoupesPourLeSimplexe == NULL ) { + free( A ); free( Colonne ); free( PositionDeLaVariableDEcart ); free( SecondMembre ); + free( NbTerm ); free( Mdeb ); free( CoupesPourLeSimplexe ); + free( T ); + return( NULL ); +} + +CoupesPourLeSimplexe->Mdeb = Mdeb; +CoupesPourLeSimplexe->NbTerm = NbTerm; +CoupesPourLeSimplexe->SecondMembre = SecondMembre; +CoupesPourLeSimplexe->PositionDeLaVariableDEcart = PositionDeLaVariableDEcart; +CoupesPourLeSimplexe->Colonne = Colonne; +CoupesPourLeSimplexe->A = A; + +il = 0; +NbCoupes = 0; +for ( NumeroDeCoupe = 0 ; NumeroDeCoupe < NombreDeCoupes ; NumeroDeCoupe++ ) { + if ( T[NumeroDeCoupe] == 0 ) continue; + Cpe = Coupe[NumeroDeCoupe]; + Coefficient = Cpe->Coefficient; + IndiceDeLaVariable = Cpe->IndiceDeLaVariable; + /* On ajoute la coupe */ + Mdeb[NbCoupes] = il; + NbTerm[NbCoupes] = Cpe->NombreDeTermes; + for ( i = 0 ; i < Cpe->NombreDeTermes ; i++ ) { + A [il] = Coefficient[i]; + Colonne[il] = IndiceDeLaVariable[i]; + il++; + } + /* Second membre */ + SecondMembre[NbCoupes] = Cpe->SecondMembre; + PositionDeLaVariableDEcart[NbCoupes] = EN_BASE; + NbCoupes++; + +} +CoupesPourLeSimplexe->NombreDeCoupes = NbCoupes; + +free( T ); + +return( CoupesPourLeSimplexe ); + +} + +/*----------------------------------------------------------------------------*/ + +void PNE_RelanceDuSimplexeAuNoeudRacine( PROBLEME_PNE * Pne, int * ExistenceDUneSolution ) +{ +int NombreMaxDIterations; double Critere; double * L; double * X; int Var; +PROBLEME_SIMPLEXE Probleme; COUPES_SIMPLEXE_NOEUD_RACINE * Coupes; + +*ExistenceDUneSolution = NON_PNE; +if ( Pne->MatriceDesContraintesAuNoeudRacine == NULL ) return; +if ( Pne->ProblemeSpxDuNoeudRacine == NULL ) return; + +Coupes = PNE_AjouterCoupesVioleesPourSimplexeAuNoeudRacine( Pne ); +if ( Coupes == NULL ) return; + +NombreMaxDIterations = -1; +Probleme.Contexte = BRANCH_AND_BOUND_OU_CUT_NOEUD; +Probleme.NombreMaxDIterations = NombreMaxDIterations; +Probleme.DureeMaxDuCalcul = -1.; + +Probleme.CoutLineaire = Pne->LTrav; +Probleme.X = Pne->MatriceDesContraintesAuNoeudRacine->X; +Probleme.Xmin = Pne->UminTravSv; +Probleme.Xmax = Pne->UmaxTravSv; +Probleme.NombreDeVariables = Pne->NombreDeVariablesTrav; +Probleme.TypeDeVariable = Pne->TypeDeBorneTravSv; + +Probleme.NombreDeContraintes = Pne->MatriceDesContraintesAuNoeudRacine->NombreDeContraintes; +Probleme.IndicesDebutDeLigne = Pne->MatriceDesContraintesAuNoeudRacine->IndexDebut; +Probleme.NombreDeTermesDesLignes = Pne->MatriceDesContraintesAuNoeudRacine->NombreDeTermes; +Probleme.IndicesColonnes = Pne->MatriceDesContraintesAuNoeudRacine->Colonne; +Probleme.CoefficientsDeLaMatriceDesContraintes = Pne->MatriceDesContraintesAuNoeudRacine->Coefficient; +Probleme.Sens = Pne->MatriceDesContraintesAuNoeudRacine->Sens; +Probleme.SecondMembre = Pne->MatriceDesContraintesAuNoeudRacine->SecondMembre; + +Probleme.ChoixDeLAlgorithme = SPX_DUAL; + +Probleme.TypeDePricing = PRICING_STEEPEST_EDGE; +Probleme.FaireDuScaling = OUI_SPX; +Probleme.StrategieAntiDegenerescence = AGRESSIF; + +/* On reinit de la base de depart */ +Pne->MatriceDesContraintesAuNoeudRacine->BaseDeDepartFournie = OUI_SPX; +memcpy( (char *) Pne->MatriceDesContraintesAuNoeudRacine->PositionDeLaVariable, + (char *) Pne->MatriceDesContraintesAuNoeudRacine->PositionDeLaVariableSV, + Pne->NombreDeVariablesTrav * sizeof( int ) ); + +Pne->MatriceDesContraintesAuNoeudRacine->NbVarDeBaseComplementaires = Pne->MatriceDesContraintesAuNoeudRacine->NbVarDeBaseComplementairesSV; + +memcpy( (char *) Pne->MatriceDesContraintesAuNoeudRacine->ComplementDeLaBase, + (char *) Pne->MatriceDesContraintesAuNoeudRacine->ComplementDeLaBaseSV, + Pne->MatriceDesContraintesAuNoeudRacine->NbVarDeBaseComplementairesSV * sizeof( int ) ); + +/* */ +Probleme.BaseDeDepartFournie = Pne->MatriceDesContraintesAuNoeudRacine->BaseDeDepartFournie; +Probleme.PositionDeLaVariable = Pne->MatriceDesContraintesAuNoeudRacine->PositionDeLaVariable; +Probleme.NbVarDeBaseComplementaires = Pne->MatriceDesContraintesAuNoeudRacine->NbVarDeBaseComplementaires; +Probleme.ComplementDeLaBase = Pne->MatriceDesContraintesAuNoeudRacine->ComplementDeLaBase; + +Probleme.LibererMemoireALaFin = NON_SPX; + +Probleme.CoutMax = LINFINI_PNE; +Probleme.UtiliserCoutMax = NON_SPX; + +printf("Relance du SIMPLEXE au noeud racine Nomnre De Coupes = %d\n",Coupes->NombreDeCoupes); + +Probleme.NombreDeContraintesCoupes = Coupes->NombreDeCoupes; +Probleme.BCoupes = Coupes->SecondMembre; +Probleme.PositionDeLaVariableDEcartCoupes = Coupes->PositionDeLaVariableDEcart; +Probleme.MdebCoupes = Coupes->Mdeb; +Probleme.NbTermCoupes = Coupes->NbTerm; +Probleme.NuvarCoupes = Coupes->Colonne; +Probleme.ACoupes = Coupes->A; + +Probleme.CoutsMarginauxDesContraintes = NULL; + +Probleme.CoutsReduits = Pne->MatriceDesContraintesAuNoeudRacine->CoutsReduits; + +Probleme.AffichageDesTraces = NON_SPX /*Pne->AffichageDesTraces*/; + +Pne->ProblemeSpxDuNoeudRacine = SPX_Simplexe( &Probleme , Pne->ProblemeSpxDuNoeudRacine ); +*ExistenceDUneSolution = Probleme.ExistenceDUneSolution; + +PNE_LibererCoupesVioleesPourSimplexeAuNoeudRacine( Coupes ); + +if ( *ExistenceDUneSolution == OUI_PNE ) { + Pne->MatriceDesContraintesAuNoeudRacine->NbVarDeBaseComplementaires = Probleme.NbVarDeBaseComplementaires; + Pne->MatriceDesContraintesAuNoeudRacine->BaseDeDepartFournie = OUI_SPX; + Critere = Pne->Z0; + L = Pne->LTrav; + X = Pne->MatriceDesContraintesAuNoeudRacine->X; + for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + Critere += L[Var] * X[Var]; + if ( X[Var] < Pne->UminTravSv[Var] || X[Var] > Pne->UmaxTravSv[Var] ) { + printf("X %e min %e max %e Type borne %d \n",X[Var],Pne->UminTravSv[Var],Pne->UmaxTravSv[Var],Pne->TypeDeBorneTravSv[Var]); + } + } + + printf("RELANCE SIMPLEXE AU NOEUD RACINE Iteration %d\n",((PROBLEME_SPX *) Pne->ProblemeSpxDuNoeudRacine)->Iteration); + + printf("RELANCE SIMPLEXE AU NOEUD RACINE Nouveau critere %e ancien cirter %e\n",Critere,Pne->CritereAuNoeudRacine); + + + PNE_ArchivagesPourReducedCostFixingAuNoeudRacine( Pne, + Pne->MatriceDesContraintesAuNoeudRacine->PositionDeLaVariable, + Pne->MatriceDesContraintesAuNoeudRacine->CoutsReduits, + Critere ); +} +else { + printf("RELANCE SIMPLEXE AU NOEUD RACINE Pas de solution\n"); + Pne->MatriceDesContraintesAuNoeudRacine->BaseDeDepartFournie = NON_SPX; +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_relancer_un_branch_and_bound.c b/src/ext/Sirius_Solver/pne/pne_relancer_un_branch_and_bound.c new file mode 100644 index 0000000000..677d0120d8 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_relancer_un_branch_and_bound.c @@ -0,0 +1,378 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# include "prs_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define TRACES 1 + +MATRICE_DE_CONTRAINTES * PNE_BranchAndBoundIntermediareMatriceDesContraintes( PROBLEME_PNE * , double ); + +/*----------------------------------------------------------------------------*/ + +MATRICE_DE_CONTRAINTES * PNE_BranchAndBoundIntermediareMatriceDesContraintes( PROBLEME_PNE * Pne, double MeilleurMinorant ) +{ +int NombreDeContraintesNatives; int NbTermesNecessaires; int * IndexDebut; int * NombreDeTermes; +int NombreDeVariablesNatives; int il; int NbTermesNatif; int NombreDeContraintes; +int NbContraintesNecessaires; double * SecondMembre; char * Sens; int * Colonne; double * Coefficient; +MATRICE_DE_CONTRAINTES * Contraintes; int Nb; double * L; int Var; int ii; int iiMx; +char * ContrainteActivable; int NbT; int * Mdeb; int * NbTerm; char * SensContrainte; int * Nuvar; +double * B; double * A; int Cnt; + +Contraintes = NULL; +/* Allocation */ +Contraintes = (MATRICE_DE_CONTRAINTES *) malloc( sizeof( MATRICE_DE_CONTRAINTES ) ); +if ( Contraintes == NULL ) return( NULL ); + +NombreDeContraintesNatives = Pne->NombreDeContraintesTrav; +NombreDeVariablesNatives = Pne->NombreDeVariablesTrav; +NbContraintesNecessaires = NombreDeContraintesNatives; + +/* Pour les coupes */ +NbContraintesNecessaires += Pne->Coupes.NombreDeContraintes; + +/* Pour la borne sur le cout */ +NbContraintesNecessaires++; + +/* Pour la borne sur le cout de la solution entiere */ +NbContraintesNecessaires++; + +NbTermesNatif = Pne->TailleAlloueePourLaMatriceDesContraintes; + +NbTermesNecessaires = NbTermesNatif; + +/* Pour les coupes */ +for ( Nb = 0 ; Nb < Pne->Coupes.NombreDeContraintes; Nb++ ) NbTermesNecessaires += Pne->Coupes.NbTerm[Nb]; + +/* Pour la borne sur le cout */ +NbTermesNecessaires += NombreDeVariablesNatives; + +/* Pour la borne sur le cout de la solution entiere */ +NbTermesNecessaires += NombreDeVariablesNatives; + +IndexDebut = (int *) malloc( NbContraintesNecessaires * sizeof( int ) ); +NombreDeTermes = (int *) malloc( NbContraintesNecessaires * sizeof( int ) ); +SecondMembre = (double *) malloc( NbContraintesNecessaires * sizeof( double ) ); +Sens = (char *) malloc( NbContraintesNecessaires * sizeof( char ) ); +Colonne = (int *) malloc( NbTermesNecessaires * sizeof( int ) ); +Coefficient = (double *) malloc( NbTermesNecessaires * sizeof( double ) ); +if ( IndexDebut == NULL || NombreDeTermes == NULL || SecondMembre == NULL || Sens == NULL || Colonne == NULL || Coefficient == NULL ) { + free( IndexDebut ); free( NombreDeTermes ); free( SecondMembre ); free( Sens ); free( Colonne ); free( Coefficient ); + free( Contraintes ); + return( NULL ); +} +Contraintes->IndexDebut = IndexDebut; +Contraintes->NombreDeTermes = NombreDeTermes; +Contraintes->SecondMembre = SecondMembre; +Contraintes->Sens = Sens; +Contraintes->Colonne = Colonne; +Contraintes->Coefficient = Coefficient; + +/* Recopie de la matrice des contraintes natives mais uniquement celle qui sont activables */ +ContrainteActivable = Pne->ContrainteActivable; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; + +il = 0; +NombreDeContraintes = 0; +for ( Cnt = 0 ; Cnt < NombreDeContraintesNatives ; Cnt++ ) { + if ( ContrainteActivable[Cnt] == NON_PNE && 0 ) continue; + IndexDebut[NombreDeContraintes] = il; + NbT = 0; + ii = Mdeb[Cnt]; + iiMx = ii + NbTerm[Cnt]; + while ( ii < iiMx ) { + Colonne[il] = Nuvar[ii]; + Coefficient[il] = A[ii]; + ii++; + il++; + NbT++; + } + if ( NbT > 0 ) { + NombreDeTermes[NombreDeContraintes] = NbT; + Sens[NombreDeContraintes] = SensContrainte[Cnt]; + SecondMembre[NombreDeContraintes] = B[Cnt]; + NombreDeContraintes++; + } +} +/* +printf("Pne->Coupes.NombreDeContraintes = %d\n",Pne->Coupes.NombreDeContraintes); + +for ( Nb = 0 ; Nb < Pne->Coupes.NombreDeContraintes; Nb++ ) { + IndexDebut[NombreDeContraintes] = il; + NombreDeTermes[NombreDeContraintes] = Pne->Coupes.NbTerm[Nb]; + SecondMembre[NombreDeContraintes] = Pne->Coupes.B[Nb]; + Sens[NombreDeContraintes] = '<'; + ii = Pne->Coupes.Mdeb[Nb]; + iiMx = ii + Pne->Coupes.NbTerm[Nb]; + while ( ii < iiMx) { + Coefficient[il] = Pne->Coupes.A[ii]; + Colonne[il] = Pne->Coupes.Nuvar[ii]; + il++; + ii++; + } + NombreDeContraintes++; +} +*/ +/* On se replace au noeud racine et on impose que le cout soit superieur ou egal au meilleur minorant */ +/* +L = Pne->LTrav; +IndexDebut[NombreDeContraintes] = il; +Nb = 0; +for ( Var = 0 ; Var < NombreDeVariablesNatives ; Var++ ) { + if ( L[Var] != 0.0 ) { + Colonne[il] = Var; + Coefficient[il] = L[Var]; + il++; Nb++; + } +} +NombreDeTermes[NombreDeContraintes] = Nb; +SecondMembre[NombreDeContraintes] = MeilleurMinorant - 1.; +Sens[NombreDeContraintes] = '>'; +NombreDeContraintes++; +*/ +/* Pour la borne sur le cout de la solution entiere */ +/* +L = Pne->LTrav; +IndexDebut[NombreDeContraintes] = il; +Nb = 0; +for ( Var = 0 ; Var < NombreDeVariablesNatives ; Var++ ) { + if ( L[Var] != 0.0 ) { + Colonne[il] = Var; + Coefficient[il] = L[Var]; + il++; Nb++; + } +} +NombreDeTermes[NombreDeContraintes] = Nb; +SecondMembre[NombreDeContraintes] = Pne->CoutOpt - Pne->Z0 + 1.; +Sens[NombreDeContraintes] = '<'; +NombreDeContraintes++; +*/ +Contraintes->NombreDeContraintes = NombreDeContraintes; + +return( Contraintes ); +} + +/*----------------------------------------------------------------------------*/ +void PNE_BranchAndBoundIntermediare( PROBLEME_PNE * Pne, double MeilleurMinorant ) +{ +int Var; int NbMaxSol; CONTROLS Controls; PROBLEME_A_RESOUDRE Probleme; double S; +MATRICE_DE_CONTRAINTES * Contraintes; char BrnInfConnue; int * TypeDeBorne; +PROBING_OU_NODE_PRESOLVE * ProbingOuNodePresolve; int NombreDeVariables; +double * Xmin; double * Xmax; double * X; int * TypeDeVariable; char * BorneSupConnue; +char * BorneInfConnue; double * ValeurDeBorneSup; double * ValeurDeBorneInf; +int * TypeDeVariablePne; + +if ( Pne->Controls != NULL ) return; /* C'est gere au niveau de l'appelant */ + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Trying to improve bounds restarting presolve\n"); +} + +ProbingOuNodePresolve = Pne->ProbingOuNodePresolve; + +NombreDeVariables = Pne->NombreDeVariablesTrav; + +BorneSupConnue = ProbingOuNodePresolve->BorneSupConnue; +ValeurDeBorneSup = ProbingOuNodePresolve->ValeurDeBorneSup; +BorneInfConnue = ProbingOuNodePresolve->BorneInfConnue; +ValeurDeBorneInf = ProbingOuNodePresolve->ValeurDeBorneInf; + +TypeDeVariable = (int *) malloc( NombreDeVariables * sizeof( int ) ); +memcpy( (char *) TypeDeVariable, (char *) Pne->TypeDeVariableTrav, NombreDeVariables * sizeof( int ) ); + +X = (double *) malloc( NombreDeVariables * sizeof( double ) ); + +Xmin = (double *) malloc( NombreDeVariables * sizeof( double ) ); +memcpy( (char *) Xmin, (char *) ValeurDeBorneInf, NombreDeVariables * sizeof( double ) ); + +Xmax = (double *) malloc( NombreDeVariables * sizeof( double ) ); +memcpy( (char *) Xmax, (char *) ValeurDeBorneSup, NombreDeVariables * sizeof( double ) ); + +TypeDeBorne = (int *) malloc( NombreDeVariables * sizeof( int ) ); + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + BrnInfConnue = BorneInfConnue[Var]; + if ( BrnInfConnue == FIXE_AU_DEPART || BrnInfConnue == FIXATION_SUR_BORNE_INF || + BrnInfConnue == FIXATION_SUR_BORNE_SUP || BrnInfConnue == FIXATION_A_UNE_VALEUR ) { + X[Var] = ValeurDeBorneInf[Var]; + TypeDeBorne[Var] = VARIABLE_FIXE; + /* A cause de tests dans init pne qui ne tolere pas qu'une variable entiere soit fixee et ait des bornes + min et max identiques */ + if ( TypeDeVariable[Var] == ENTIER ) TypeDeVariable[Var] = REEL; + continue; + } + + if ( BorneInfConnue[Var] != NON_PNE ) { + if ( BorneSupConnue[Var] != NON_PNE ) { + TypeDeBorne[Var] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else { + TypeDeBorne[Var] = VARIABLE_BORNEE_INFERIEUREMENT; + } + } + else { + /* On ne traite pas le cas des variables bornees superieurement */ + TypeDeBorne[Var] = VARIABLE_NON_BORNEE; + Xmin[Var] = -LINFINI_PNE; + Xmax[Var] = LINFINI_PNE; + } +} + +MeilleurMinorant -= Pne->Z0; + +Contraintes = PNE_BranchAndBoundIntermediareMatriceDesContraintes( Pne, MeilleurMinorant ); +if ( Contraintes == NULL ) goto Fin; + +Probleme.NombreDeVariables = NombreDeVariables; +Probleme.TypeDeVariable = TypeDeVariable; +Probleme.TypeDeBorneDeLaVariable = TypeDeBorne; +Probleme.X = X; +Probleme.Xmax = Xmax; +Probleme.Xmin = Xmin; +Probleme.CoutLineaire = Pne->LTrav; +Probleme.NombreDeContraintes = Contraintes->NombreDeContraintes; +Probleme.SecondMembre = Contraintes->SecondMembre; +Probleme.Sens = Contraintes->Sens; +Probleme.IndicesDebutDeLigne = Contraintes->IndexDebut; +Probleme.NombreDeTermesDesLignes = Contraintes->NombreDeTermes; +Probleme.CoefficientsDeLaMatriceDesContraintes = Contraintes->Coefficient; +Probleme.IndicesColonnes = Contraintes->Colonne; +Probleme.VariablesDualesDesContraintes = NULL; +Probleme.SortirLesDonneesDuProbleme = NON_PNE; +Probleme.AlgorithmeDeResolution = SIMPLEXE; /* SIMPLEXE ou POINT_INTERIEUR */ +Probleme.CoupesLiftAndProject = NON_PNE; + +Probleme.AffichageDesTraces = OUI_PNE; + +Probleme.FaireDuPresolve = OUI_PNE; + +Probleme.TempsDExecutionMaximum = 0; + +NbMaxSol = -1; + +Probleme.NombreMaxDeSolutionsEntieres = NbMaxSol; + +Probleme.ToleranceDOptimalite = 1.e-4; /* C'est en % donc 1.e-4 ca fait 1.e-6 */ + +Controls.Pne = Pne; +Controls.PneFils = NULL; +Controls.Presolve = NULL; +Controls.PresolveUniquement = OUI_PNE; +Controls.FaireDuVariableProbing = OUI_PNE; +Controls.RechercherLesCliques = OUI_PNE; + +PNE_SolveurProblemeReduit( &Probleme, &Controls ); + +if ( Controls.PresolveUniquement != OUI_PNE ) { + S = Pne->Z0; + for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + S += X[Var] * Pne->LTrav[Var]; + if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) { + if ( Pne->UTrav[Var] != Pne->UmaxTravSv[Var] && Pne->UTrav[Var] != Pne->UminTravSv[Var] ) { + printf("Var entiere %d UTrav %e UminTravSv %e UmaxTravSv %e\n",Var,Pne->UTrav[Var],Pne->UminTravSv[Var],Pne->UmaxTravSv[Var]); + } + } + } + printf("S %e\n",S); + if ( Probleme.ExistenceDUneSolution == SOLUTION_OPTIMALE_TROUVEE ) printf("Solution optimale trouvee\n"); + else printf("Solution optimale pas trouvee ExistenceDUneSolution = %d\n",Probleme.ExistenceDUneSolution); + + exit(0); + +} +else { + /* On recupere les bornes */ + + if ( Probleme.ExistenceDUneSolution != OUI_PNE ) { + printf("Pas de solution \n"); + } + + TypeDeVariablePne = Pne->TypeDeVariableTrav; + + int Stop; + Stop = 0; + + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( ValeurDeBorneInf[Var] == ValeurDeBorneSup[Var] ) continue; + if ( TypeDeVariablePne[Var] == ENTIER ) { + if ( ValeurDeBorneInf[Var] != ValeurDeBorneSup[Var] ) { + if ( Xmin[Var] == Xmax[Var] ) { + printf("Variable entiere %d fixee par le presolve a %e ValeurDeBorneInf %e ValeurDeBorneSup %e\n", + Var,Xmin[Var],ValeurDeBorneInf[Var],ValeurDeBorneSup[Var]); + ValeurDeBorneInf[Var] = Xmin[Var]; + ValeurDeBorneSup[Var] = Xmin[Var]; + BorneInfConnue[Var] = OUI_PNE; + BorneSupConnue[Var] = OUI_PNE; + } + } + } + else { + if ( Xmin[Var] > ValeurDeBorneInf[Var] + 1.e-5 ) { + printf("Variable continue %d nouveau Xmin %e ancien %e ecart %e\n",Var,Xmin[Var],ValeurDeBorneInf[Var],Xmin[Var]-ValeurDeBorneInf[Var]); + ValeurDeBorneInf[Var] = Xmin[Var]; + BorneInfConnue[Var] = OUI_PNE; + if ( Xmin[Var] > ValeurDeBorneSup[Var] ) { + printf(" BUG Var %d Xmin %e ValeurDeBorneInf %e ValeurDeBorneSup %e\n",Var,Xmin[Var],ValeurDeBorneInf[Var],ValeurDeBorneSup[Var]); + Stop = 1; + } + } + if ( Xmax[Var] < ValeurDeBorneSup[Var] - 1.e-5 ) { + printf("Variable continue %d nouveau Xmax %e ancien %e ecart %e\n",Var,Xmax[Var],ValeurDeBorneSup[Var],ValeurDeBorneSup[Var]-Xmax[Var]); + ValeurDeBorneSup[Var] = Xmax[Var]; + BorneSupConnue[Var] = OUI_PNE; + if ( Xmax[Var] < ValeurDeBorneInf[Var] ) { + printf(" BUG Var %d Xmax %e ValeurDeBorneInf %e ValeurDeBorneSup %e\n",Var,Xmax[Var],ValeurDeBorneInf[Var],ValeurDeBorneSup[Var]); + Stop = 1; + } + } + } + } + + if ( Stop == 1 ) { + printf("Stop %d\n",Stop); + exit(0); + } + + + +} +Fin: + +free( TypeDeVariable ); +free( TypeDeBorne ); +free( X ); +free( Xmin ); +free( Xmax ); + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_round.c b/src/ext/Sirius_Solver/pne/pne_round.c new file mode 100644 index 0000000000..fac3d70b07 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_round.c @@ -0,0 +1,37 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Pour réduire la précision des coefficients utilisés dans les calculs + + AUTEUR: N. Lhuiller + +************************************************************************/ + +# include "pne_sys.h" +# include "pne_fonctions.h" + +/* Pour réduire la précision des coefficients utilisés dans les calculs */ +double PNE_Round(double x, double prec) { + + if (x > 0) + x = floor(x * prec + 0.5) / prec; + else if (x < 0) + x = ceil(x * prec - 0.5) / prec; + + return x; +} diff --git a/src/ext/Sirius_Solver/pne/pne_solve_pb_rlx_pi.c b/src/ext/Sirius_Solver/pne/pne_solve_pb_rlx_pi.c new file mode 100644 index 0000000000..b3f0b4862f --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_solve_pb_rlx_pi.c @@ -0,0 +1,190 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution du probleme relaxe par le point interieur + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "pi_define.h" +# include "pi_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PNE_SolvePbRlxPi( PROBLEME_PNE * Pne, double * Critere, int * Faisabilite ) +{ +int i; int il; int ilMax; double S; int PourJeanYves; + +double * Qtrav; + +/*double * VariablesDualesDesContraintes;*/ + +double ToleranceSurLAdmissibilite ; int ChoixToleranceParDefautSurLAdmissibilite ; +double ToleranceSurLaStationnarite ; int ChoixToleranceParDefautSurLaStationnarite ; +double ToleranceSurLaComplementarite; int ChoixToleranceParDefautSurLaComplementarite; + +PROBLEME_POINT_INTERIEUR Probleme; char * VariableBinaire; + +char LigneLue[128]; char LabelDeLaVariableLue[128]; char ValeurLue[128]; int NbChamps; int LgMax; +FILE * Flot; + +*Faisabilite = OUI_PNE; + +PourJeanYves = 0; + +/* Allocations temporaires */ +VariableBinaire = (char *) malloc( Pne->NombreDeVariablesTrav * sizeof( char ) ); +if ( VariableBinaire == NULL ) { + printf(" Memoire insuffisante. Sous-programme: PNE_SolvePbRlxPi\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( Pne->TypeDeVariableTrav[i] == ENTIER ) VariableBinaire[i] = OUI_PI; + else VariableBinaire[i] = NON_PI; +} + +Qtrav = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); + +free( Pne->VariablesDualesDesContraintesTravEtDesCoupes ); +Pne->VariablesDualesDesContraintesTravEtDesCoupes = NULL; +Pne->VariablesDualesDesContraintesTravEtDesCoupes = (double *) malloc( ( Pne->NombreDeContraintesTrav + Pne->Coupes.NombreDeContraintes ) * sizeof( double ) ); + +if ( Qtrav == NULL || Pne->VariablesDualesDesContraintesTravEtDesCoupes == NULL ) { + printf(" PNE, memoire insuffisante dans le sous programme PNE_SolvePbRlx \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) Qtrav[i] = 0.0; + +/* Temporairement pour Jean-Yves et Aurelie, ouverture d'un fichier de couts quadratique */ +if ( PourJeanYves == 0 ) goto OnOptimise; +Flot = fopen( "A_JEU_DE_DONNEES_QUADR", "r" ); +if( Flot == NULL ) { + printf("Erreur ouverture du fichier contenant les couts quadratiques \n"); + exit(0); +} +LgMax = 128; +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + fgets( LigneLue , LgMax , Flot ); + NbChamps = sscanf( LigneLue , "%s %s" , LabelDeLaVariableLue , ValeurLue ); + if ( NbChamps <= 0 ) break; + Qtrav[i] = atof( ValeurLue ); + /*printf("Cout quadratique de la variable %d nommee %s = %e\n",i,LabelDeLaVariableLue,Qtrav[i]);*/ +} +/* Fin pour Jean-Yves et Aurelie, ouverture d'un fichier de couts quadratique */ + +OnOptimise: +ToleranceSurLAdmissibilite = 1.e-6/*1.e-5*/; +ChoixToleranceParDefautSurLAdmissibilite = NON_PNE; + +ToleranceSurLaStationnarite = 1.e-6; +ChoixToleranceParDefautSurLaStationnarite = NON_PNE; /* Pour prendre la tolerance par defaut du point interieur */ + +ToleranceSurLaComplementarite = 1.e-6; +ChoixToleranceParDefautSurLaComplementarite = NON_PNE; + +/* Appel du point interieur */ +printf("----------------------------------------------------------\n"); +printf("Appel de Pi_Quamin nombre de variables %d contraintes %d\n",Pne->NombreDeVariablesTrav,Pne->NombreDeContraintesTrav); + +Probleme.NombreDeVariables = Pne->NombreDeVariablesTrav; +Probleme.CoutQuadratique = Qtrav; +Probleme.CoutLineaire = Pne->LTrav; +Probleme.X = Pne->UTrav; +Probleme.Xmin = Pne->UminTrav; +Probleme.Xmax = Pne->UmaxTrav; +Probleme.TypeDeVariable = Pne->TypeDeBorneTrav; +Probleme.VariableBinaire = VariableBinaire; +Probleme.NombreDeContraintes = Pne->NombreDeContraintesTrav; +Probleme.IndicesDebutDeLigne = Pne->MdebTrav; +Probleme.NombreDeTermesDesLignes = Pne->NbTermTrav; +Probleme.IndicesColonnes = Pne->NuvarTrav; +Probleme.CoefficientsDeLaMatriceDesContraintes = Pne->ATrav; +Probleme.Sens = Pne->SensContrainteTrav; +Probleme.SecondMembre = Pne->BTrav; +Probleme.NombreMaxDIterations = -1; +Probleme.AffichageDesTraces = OUI_PI; +Probleme.UtiliserLaToleranceDAdmissibiliteParDefaut = ChoixToleranceParDefautSurLAdmissibilite; +Probleme.ToleranceDAdmissibilite = ToleranceSurLAdmissibilite; +Probleme.UtiliserLaToleranceDeStationnariteParDefaut = ChoixToleranceParDefautSurLaStationnarite; +Probleme.ToleranceDeStationnarite = ToleranceSurLaStationnarite; +Probleme.UtiliserLaToleranceDeComplementariteParDefaut = ChoixToleranceParDefautSurLaComplementarite; +Probleme.ToleranceDeComplementarite = ToleranceSurLaComplementarite; +Probleme.CoutsMarginauxDesContraintes = Pne->VariablesDualesDesContraintesTravEtDesCoupes; +Probleme.CoutsMarginauxDesContraintesDeBorneInf = Pne->S1Trav; +Probleme.CoutsMarginauxDesContraintesDeBorneSup = Pne->S2Trav; + +PI_Quamin( &Probleme ); + +if ( Probleme.ExistenceDUneSolution == OUI_PI ) *Faisabilite = OUI_PNE; +else *Faisabilite = NON_PNE; + +/* FIN POINT INTERIEUR */ + +/* Synthese des résultats */ +printf("\n Resultat de la resolution du probleme relaxe \n"); + +for ( *Critere = Pne->Z0 , i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + *Critere+= Pne->LTrav[i] * Pne->UTrav[i]; + *Critere+= Qtrav[i] * Pne->UTrav[i] * Pne->UTrav[i]; +} +printf(" Valeur du critere recalculee en sortie de l'optimisation %lf \n",*Critere); + +for ( i = 0 ; i < Pne->NombreDeContraintesTrav ; i++ ) { + S = 0.; + il = Pne->MdebTrav[i]; + ilMax = Pne->MdebTrav[i] + Pne->NbTermTrav[i]; + while ( il < ilMax ) { + S+= Pne->ATrav[il] * Pne->UTrav[ Pne->NuvarTrav[il] ]; + il++; + } + + if ( Pne->SensContrainteTrav[i] == '=' ) { + if ( fabs( Pne->BTrav[i] - S ) > 1.e-3 ) { + printf(" Contrainte type = numero %d non satisfaite. Second membre %lf calcul %lf ecart %lf\n",i,Pne->BTrav[i],S,Pne->BTrav[i] - S); + *Faisabilite = NON_PNE; + } + } + else if ( Pne->SensContrainteTrav[i] == '<' ) { + if ( S > Pne->BTrav[i] + 1.e-3 ) { + printf(" Contrainte type < numero %d non satisfaite. Second membre %lf calcul %lf ecart %lf\n",i,Pne->BTrav[i],S,Pne->BTrav[i] - S); + *Faisabilite = NON_PNE; + } + } +} + +free( VariableBinaire); +VariableBinaire = NULL; + +free( Qtrav ); +Qtrav = NULL; + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_solve_pb_rlx_spx_dual.c b/src/ext/Sirius_Solver/pne/pne_solve_pb_rlx_spx_dual.c new file mode 100644 index 0000000000..8430851995 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_solve_pb_rlx_spx_dual.c @@ -0,0 +1,267 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution d'un probleme relaxe par le simplexe dual + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_constantes_externes.h" +# include "spx_definition_arguments.h" +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define SEUIL_POUR_PRIORITE_DANS_SPX_AUX_VARIABLES_SORTANTES_ENTIERES 0.75 /* 75% soit 3/4 */ + +/*----------------------------------------------------------------------------*/ + +void PNE_SolvePbRlxSpxDual( PROBLEME_PNE * Pne, + char PremiereResolutionAuNoeudRacine, /* Information en Entree */ + double CoutMax, /* Information en Entree */ + int UtiliserCoutMax, /* Information en Entree: Oui ou non */ + int BaseFournie, /* Information en Entree: Oui ou non */ + int * PositionDeLaVariable, /* Information en Entree et Sortie */ + int * NbVarDeBaseComplementaires, /* Information en Entree et Sortie */ + int * ComplementDeLaBase, /* Information en Entree et Sortie */ + int * Faisabilite + ) +{ +int BaseDeDepartFournie; int LibererMemoireALaFin; int Contexte; int i; double S; +int ExistenceDUneSolution; int ChoixDeLAlgorithme; int NombreMaxDIterations; +time_t HeureDeCalendrierDebut; time_t HeureDeCalendrierCourant; double TempsEcoule; int Nb; +double * VariablesDualesDesContraintesTravEtDesCoupes; int * ContrainteSaturee; +PROBLEME_SIMPLEXE Probleme; BB * Bb; PROBLEME_SPX * Spx; + +#if VERBOSE_PNE + printf("----------------------------------------------------------\n"); + printf("Appel du simplexe dual. Nombre de variables %d contraintes %d\n",Pne->NombreDeVariablesTrav,Pne->NombreDeContraintesTrav); + fflush(stdout); +#endif + +*Faisabilite = OUI_PNE; + +if ( Pne->TailleAlloueeVariablesDualesDesContraintesTravEtDesCoupes < Pne->NombreDeContraintesTrav + Pne->Coupes.NombreDeContraintes ) { + i = Pne->NombreDeContraintesTrav + Pne->Coupes.NombreDeContraintes; + if ( Pne->VariablesDualesDesContraintesTravEtDesCoupes == NULL ) { + Pne->VariablesDualesDesContraintesTravEtDesCoupes = (double *) malloc( i * sizeof( double ) ); + } + else { + Pne->VariablesDualesDesContraintesTravEtDesCoupes = (double *) realloc( Pne->VariablesDualesDesContraintesTravEtDesCoupes, i * sizeof( double ) ); + } + if ( Pne->VariablesDualesDesContraintesTravEtDesCoupes == NULL ) { + printf("PNE, memoire insuffisante dans le sous programme PNE_SolvePbRlxSpxDual \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } + Pne->TailleAlloueeVariablesDualesDesContraintesTravEtDesCoupes = i; +} + +LibererMemoireALaFin = NON_SPX; + +if ( PremiereResolutionAuNoeudRacine == OUI_PNE ) { + if ( Pne->NombreDeVariablesEntieresTrav <= 0 ) { + /* Si pas de variables entieres, alors simplexe seul */ + Contexte = SIMPLEXE_SEUL; + } + else { + /* Premiere resolution du noeud racine dans le cas du branch and bound */ + Contexte = BRANCH_AND_BOUND_OU_CUT; + } +} +else { + /* Resolutions suivantes dans le cas du branch and bound */ + Contexte = BRANCH_AND_BOUND_OU_CUT_NOEUD; +} + +BaseDeDepartFournie = BaseFournie; + +ChoixDeLAlgorithme = SPX_DUAL; + +if ( Contexte != BRANCH_AND_BOUND_OU_CUT_NOEUD ) { + if ( Pne->ProblemeSpxDuSolveur != NULL ) { + SPX_LibererProbleme( (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur ); + Pne->ProblemeSpxDuSolveur = NULL; + } +} + +/* Si on vient d'ajouter des coupes calculees c'est qu'il s'agit de la reoptimisation d'un noeud deja + resolu. Dans ce cas, on impose une limitation du nombre d'iterations. */ +if ( Pne->NombreDeCoupesCalculees > 0 ) { + NombreMaxDIterations = (int) (5. * Pne->NombreDeCoupesCalculees); + if ( NombreMaxDIterations < 1000 ) NombreMaxDIterations = 1000; +} +else { + /* On met un nombre negatif pour que la donnee ne soit pas prise en compte */ + NombreMaxDIterations = -10; +} + +Probleme.Contexte = Contexte; +Probleme.NombreMaxDIterations = NombreMaxDIterations; +Probleme.DureeMaxDuCalcul = -1.; + +Probleme.CoutLineaire = Pne->LTrav; +Probleme.X = Pne->UTrav; +Probleme.Xmin = Pne->UminTrav; +Probleme.Xmax = Pne->UmaxTrav; +Probleme.NombreDeVariables = Pne->NombreDeVariablesTrav; +Probleme.TypeDeVariable = Pne->TypeDeBorneTrav; + +Probleme.NombreDeContraintes = Pne->NombreDeContraintesTrav; +Probleme.IndicesDebutDeLigne = Pne->MdebTrav; +Probleme.NombreDeTermesDesLignes = Pne->NbTermTrav; +Probleme.IndicesColonnes = Pne->NuvarTrav; +Probleme.CoefficientsDeLaMatriceDesContraintes = Pne->ATrav; +Probleme.Sens = Pne->SensContrainteTrav; +Probleme.SecondMembre = Pne->BTrav; + +Probleme.ChoixDeLAlgorithme = ChoixDeLAlgorithme; + +Probleme.TypeDePricing = PRICING_STEEPEST_EDGE /*PRICING_DANTZIG*/; +Probleme.FaireDuScaling = OUI_SPX /*OUI_SPX*/; +Probleme.StrategieAntiDegenerescence = AGRESSIF; + +Probleme.BaseDeDepartFournie = BaseDeDepartFournie; +Probleme.PositionDeLaVariable = PositionDeLaVariable; +Probleme.NbVarDeBaseComplementaires = *NbVarDeBaseComplementaires; +Probleme.ComplementDeLaBase = ComplementDeLaBase; + +Probleme.LibererMemoireALaFin = LibererMemoireALaFin; + + +Probleme.CoutMax = CoutMax; +Probleme.UtiliserCoutMax = UtiliserCoutMax; + +Probleme.NombreDeContraintesCoupes = Pne->Coupes.NombreDeContraintes; +Probleme.BCoupes = Pne->Coupes.B; +Probleme.PositionDeLaVariableDEcartCoupes = Pne->Coupes.PositionDeLaVariableDEcart; +Probleme.MdebCoupes = Pne->Coupes.Mdeb; +Probleme.NbTermCoupes = Pne->Coupes.NbTerm; +Probleme.NuvarCoupes = Pne->Coupes.Nuvar; +Probleme.ACoupes = Pne->Coupes.A; + +Probleme.CoutsMarginauxDesContraintes = Pne->VariablesDualesDesContraintesTravEtDesCoupes; + +Probleme.CoutsReduits = Pne->CoutsReduits; + +Probleme.AffichageDesTraces = Pne->AffichageDesTraces; + +if ( Pne->DureeDuPremierSimplexe <= 0. ) time( &HeureDeCalendrierDebut ); + +Pne->ProblemeSpxDuSolveur = SPX_Simplexe( &Probleme , Pne->ProblemeSpxDuSolveur ); + +/* On renseigne le Simplexe pour qu'il sache qui l'appelle */ +Spx = NULL; +if ( Pne->ProblemeSpxDuSolveur != NULL ) { + Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur; + Spx->ProblemePneDeSpx = (void *) Pne; +} + +if ( Pne->DureeDuPremierSimplexe <= 0. ) { + time( &HeureDeCalendrierCourant ); + TempsEcoule = difftime( HeureDeCalendrierCourant , HeureDeCalendrierDebut ); + Pne->DureeDuPremierSimplexe = TempsEcoule; +} + +ExistenceDUneSolution = Probleme.ExistenceDUneSolution; + +if ( ExistenceDUneSolution == OUI_PNE ) { + + *Faisabilite = OUI_PNE; + *NbVarDeBaseComplementaires = Probleme.NbVarDeBaseComplementaires; + + Bb = (BB *) Pne->ProblemeBbDuSolveur; + if ( Bb != NULL ) { + Bb->NombreDeSimplexes++; + if ( Spx != NULL ) Bb->SommeDuNombreDIterations += Spx->Iteration; + } + + /* Init de l'indicateur ContrainteSaturee */ + /* Si la variable d'ecart est basique on considere que la contrainte n'est pas saturee */ + ContrainteSaturee = Pne->ContrainteSaturee; + /* Decompte du nombre de variables duales nulles */ + Nb = 0; + VariablesDualesDesContraintesTravEtDesCoupes = Pne->VariablesDualesDesContraintesTravEtDesCoupes; + for ( i = 0 ; i < Pne->NombreDeContraintesTrav ; i++ ) { + ContrainteSaturee[i] = OUI_PNE; + if ( VariablesDualesDesContraintesTravEtDesCoupes[i] == 0.0 ) Nb++; + } + for ( i = 0 ; i < *NbVarDeBaseComplementaires ; i++ ) ContrainteSaturee[ComplementDeLaBase[i]] = NON_PNE; + + S = (float) Nb / (float) Pne->NombreDeContraintesTrav; + if ( S > SEUIL_POUR_PRIORITE_DANS_SPX_AUX_VARIABLES_SORTANTES_ENTIERES ) { + Pne->PrioriteDansSpxAuxVariablesSortantesEntieres = OUI_PNE; + } + else Pne->PrioriteDansSpxAuxVariablesSortantesEntieres = NON_PNE; +} +else if ( ExistenceDUneSolution == NON_PNE ) { + *Faisabilite = NON_PNE; +} +else if ( ExistenceDUneSolution == SPX_MATRICE_DE_BASE_SINGULIERE ) { + *Faisabilite = NON_PNE; + /* Si la matrice de base est singuliere et qu'on avait mis des coupes, c'est que les + coupes sont merdiques. On pourrait virer seulement les coupes ajoutee a ce + probleme particulier. Par precaution, on prefere virer toutes les coupes du pool car + experimentalement on constate que bien d'autres coupes peuvent etre merdiques */ + if ( Pne->Coupes.NombreDeContraintes > 0 ) { + /*printf("-> Nettoyage des coupes pour cause d'instabilites numeriques \n");*/ + Bb = (BB *) Pne->ProblemeBbDuSolveur; + BB_LeverLeFlagPourEnleverToutesLesCoupes( Bb ); + } +} +else if ( ExistenceDUneSolution == SPX_ERREUR_INTERNE ) { + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} +else { + printf("Bug dans PNE_SolvePbRlxSpxDual, ExistenceDUneSolution mal renseigne\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +return; +} + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_solve_pb_rlx_spx_primal.c b/src/ext/Sirius_Solver/pne/pne_solve_pb_rlx_spx_primal.c new file mode 100644 index 0000000000..a47289a462 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_solve_pb_rlx_spx_primal.c @@ -0,0 +1,141 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution d'un probleme par le simplexe primal. + Apres essais, le hot-start avec l'algorithme primal est + moins performant et plus compliqué a faire qua'avec + l'algorithme primal. + On s'interdit donc de faire du hot-start avec l'algorithme + primal. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define COMPILER_PNE_SolvePbRlxSpxPrimal NON_PNE + +# if COMPILER_PNE_SolvePbRlxSpxPrimal == OUI_PNE + +/*----------------------------------------------------------------------------*/ + +void PNE_SolvePbRlxSpxPrimal( PROBLEME_PNE * Pne, + double CoutMax, /* Information en Entree */ + int UtiliserCoutMax, /* Information en Entree: Oui ou non */ + int BaseFournie, /* Information en Entree: Oui ou non */ + int IndiceDeLaNouvelleVariableInstanciee, /* Information en Entree */ + int NombreDeVariablesInstanciees, /* Information en Entree */ + int * IndicesDesVariablesInstanciees, /* Information en Entree */ + int * PositionDeLaVariable, /* Information en Entree et Sortie */ + int * NbVarDeBaseComplementaires, /* Information en Entree et Sortie */ + int * ComplementDeLaBase, /* Information en Entree et Sortie */ + double * Critere, + int * Faisabilite + ) +{ + +int i; int BaseDeDepartFournie; int LibererMemoireALaFin; int Contexte ; +int ExistenceDUneSolution ; int ChoixDeLAlgorithme ; int NombreMaxDIterations; + +double * VariablesDualesDesContraintes; + +if ( BaseFournie == OUI_SPX ) { + printf(" PNE_SolvePbRlxSpxPrimal: tentative de hot-start avec l'algortihme primal or on se l'est interdit \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +*Faisabilite = OUI_PNE; + +UtiliserCoutMax = NON_SPX; /* Dans tous les cas, le simplexe primal n'utilise pas le CoutMax */ + +LibererMemoireALaFin = NON_SPX; +Contexte = BRANCH_AND_BOUND_OU_CUT; + +/* Au plus on cree une contraintes supplementaires qui represente l'instanciation de la variable choisie */ + +VariablesDualesDesContraintes = (double *) malloc( ( Pne->NombreDeContraintesTrav + 1 ) * sizeof( double ) ); +if ( VariablesDualesDesContraintes == NULL ) { + printf(" PNE, memoire insuffisante dans le sous programme PNE_SolvePbRlxSpxPrimal \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +BaseDeDepartFournie = BaseFournie; + +printf("----------------------------------------------------------\n"); +printf("Appel du simplexe primal. Nombre de variables %d contraintes %d\n",Pne->NombreDeVariablesTrav,Pne->NombreDeContraintesTrav); + +ChoixDeLAlgorithme = SPX_PRIMAL; +NombreMaxDIterations = -1; + +/* Mettre ici l'appel a la routine du simplexe: SPX_Simplexe ... */ + +free( VariablesDualesDesContraintes ); /* On ne les utilise pas ici */ + +if ( ExistenceDUneSolution == OUI_PNE ) { + *Faisabilite = OUI_PNE; +/* + On recupere la base optimale pour le coup d'apres. + Pour la PositionDeLaVariable, le simplexe renvoie: + * -1 pour les variables fixees en entree + * EN_BASE ou HORS_BASE_SUR_BORNE_INF ou HORS_BASE_SUR_BORNE_SUP + Le simplexe renvoie aussi le complement de base. + On se contente de recalculer le critere. +*/ + printf("Resultat de la resolution du probleme relaxe: \n"); + for ( *Critere = 0. , i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + *Critere+= Pne->LTrav[i] * Pne->UTrav[i]; + } + printf("Valeur du critere recalculee en sortie de l'optimisation %lf \n",*Critere); +} +else if ( ExistenceDUneSolution == NON_PNE ) { + *Faisabilite = NON_PNE; +} +else { + printf("Bug dans PNE_SolvePbRlxSpxPrimal, ExistenceDUneSolution mal renseigne\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +return; +} + +# endif + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pne/pne_solveur.c b/src/ext/Sirius_Solver/pne/pne_solveur.c new file mode 100644 index 0000000000..fcb560c8eb --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_solveur.c @@ -0,0 +1,118 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Solveur de PLNE + + IMPORTANT: + * Inclure le header "pne_constantes_externes.h" dans le module + appelant. Il contient les valeurs des constantes symboliques + telles que OUI_PNE NON_PNE ENTIER REEL etc .. + * Ne jamais utiliser directement les valeurs numeriques des + constantes symboliques mais seulement leurs noms. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ +/* + Point d'entree du solveur de PNE: + -> Inclure le header "pne_constantes_externes.h" dans le module appelant. Il contient les valeurs + des constantes symboliques telles que OUI_PNE NON_PNE ENTIER REEL etc .. + -> Les variables sont numerotée ŕ partir de 0. Exemple: s'il y a 3 variables, + leurs numeros sont 0 1 et 2. + -> En consequence s'il y a N inconnues, les colonnes de la matrice des contraintes + vont de 0 a N-1 inclus. + -> Les contraintes sont numerotée ŕ partir de 0. Exemple: s'il y a 2 contraintes, + leurs numeros sont 0 et 1. + -> En consequence s'il y a M contraintes, les lignes de la matrice des contraintes + vont de 0 a M-1 inclus. +*/ +/*----------------------------------------------------------------------------*/ + +void PNE_Solveur( PROBLEME_A_RESOUDRE * Probleme ) +{ +PROBLEME_PNE * Pne; void * Tas; + +/* Controle anti piratage tres simplifie: on controle l'adresse MAC de la machine */ +/*PNE_ControleMacAdresse( );*/ + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + Probleme->ExistenceDUneSolution = ARRET_CAR_ERREUR_INTERNE; + return; /* On n'utilise pas le malloc proprietaire */ + Tas = MEM_Init(); + Pne = (PROBLEME_PNE *) MEM_Malloc( Tas, sizeof( PROBLEME_PNE ) ); + if ( Pne == NULL ) { + printf("Saturation memoire, impossible d'allouer l'objet PROBLEME_PNE\n"); + Probleme->ExistenceDUneSolution = ARRET_CAR_ERREUR_INTERNE; + return; + } + Pne->Tas = Tas; +# else + Pne = (PROBLEME_PNE *) malloc( sizeof( PROBLEME_PNE ) ); + if ( Pne == NULL ) { + printf("Saturation memoire, impossible d'allouer l'objet PROBLEME_PNE\n"); + Probleme->ExistenceDUneSolution = ARRET_CAR_ERREUR_INTERNE; + return; + } + Tas = NULL; + Pne->Tas = Tas; + Pne->Controls = NULL; +# endif + +Pne->AnomalieDetectee = NON_PNE ; +setjmp( Pne->Env ); +if ( Pne->AnomalieDetectee == OUI_PNE ) { + /* Liberation du probleme */ + PNE_LibereProbleme( Pne ); + Probleme->ExistenceDUneSolution = ARRET_CAR_ERREUR_INTERNE; + fflush(stdout); + return; +} +else { + + if ( Probleme->SortirLesDonneesDuProbleme == OUI_PNE ) { + PNE_EcrireJeuDeDonneesMPS( Pne, Probleme ); + } + + /* Optimisation */ + + Pne->ProblemeSpxDuSolveur = NULL; + Pne->ProblemeBbDuSolveur = NULL; + Pne->ProblemePrsDuSolveur = NULL; + + /* Initialisation du temps */ + time( &(Pne->HeureDeCalendrierDebut) ); + + PNE_SolveurCalculs( Probleme , Pne ); +} + +/* Pour vider le buffer des traces */ +fflush(stdout); + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_solveur_calculs.c b/src/ext/Sirius_Solver/pne/pne_solveur_calculs.c new file mode 100644 index 0000000000..8947deca59 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_solveur_calculs.c @@ -0,0 +1,255 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Solveur de PLNE + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# include "prs_define.h" + +/*----------------------------------------------------------------------------*/ + +void PNE_SolveurCalculs( PROBLEME_A_RESOUDRE * Probleme , PROBLEME_PNE * Pne ) +{ +int i; int NbVarLibres; int NbVarEntieresLibres; int ic; int Nz; + +/* */ +int NombreDeVariables; int * TypeDeVariable; int * TypeDeBorneDeLaVariable; double * X; +double * Xmax; double * Xmin; double * CoutLineaire; int NombreDeContraintes; +double * SecondMembre; char * Sens; int * IndicesDebutDeLigne; int * NombreDeTermesDesLignes; +double * CoefficientsDeLaMatriceDesContraintes; int * IndicesColonnes; int * YaUneSolution; +double * VariablesDualesDesContraintes; +/* */ + +NombreDeVariables = Probleme->NombreDeVariables; +TypeDeVariable = Probleme->TypeDeVariable; +TypeDeBorneDeLaVariable = Probleme->TypeDeBorneDeLaVariable; +X = Probleme->X; +Xmax = Probleme->Xmax; +Xmin = Probleme->Xmin; +CoutLineaire = Probleme->CoutLineaire; +NombreDeContraintes = Probleme->NombreDeContraintes; +SecondMembre = Probleme->SecondMembre; +Sens = Probleme->Sens; +IndicesDebutDeLigne = Probleme->IndicesDebutDeLigne; +NombreDeTermesDesLignes = Probleme->NombreDeTermesDesLignes; +CoefficientsDeLaMatriceDesContraintes = Probleme->CoefficientsDeLaMatriceDesContraintes; +IndicesColonnes = Probleme->IndicesColonnes; +VariablesDualesDesContraintes = Probleme->VariablesDualesDesContraintes; +YaUneSolution = &Probleme->ExistenceDUneSolution; + +Pne->YaUneSolution = OUI_PNE; +Pne->YaUneSolutionEntiere = NON_PNE; + +Pne->SolveurPourLeProblemeRelaxe = Probleme->AlgorithmeDeResolution; +if ( Pne->SolveurPourLeProblemeRelaxe != SIMPLEXE && Pne->SolveurPourLeProblemeRelaxe != POINT_INTERIEUR ) { + printf("Choix de l'algorithme de resolution incorrect. Choisir SIMPLEXE ou POINT_INTERIEUR \n"); + exit(0); +} +if ( Pne->SolveurPourLeProblemeRelaxe == POINT_INTERIEUR ) { + printf("Attention, algorithme choisi: point interieur => toutes les variables sont considerees comme etant continue\n"); +} + +Pne->AffichageDesTraces = Probleme->AffichageDesTraces; +if ( Pne->AffichageDesTraces == OUI_PNE && Pne->Controls == NULL ) { + printf("\n"); + printf(" ----------------------------------------------------------\n"); + printf("| |\n"); + printf("| Starting PNE_Solveur |\n"); + printf("| |\n"); + printf(" ---------------------------------------------------------- \n"); + printf("\n"); +} +Pne->FaireDuPresolve = Probleme->FaireDuPresolve; +Pne->TempsDExecutionMaximum = Probleme->TempsDExecutionMaximum; +Pne->NombreMaxDeSolutionsEntieres = Probleme->NombreMaxDeSolutionsEntieres; +Pne->ToleranceDOptimalite = Probleme->ToleranceDOptimalite; + +/* Allocations du probleme */ +PNE_AllocProbleme( Pne, + NombreDeVariables , TypeDeVariable , TypeDeBorneDeLaVariable, + Xmax , Xmin , NombreDeContraintes , IndicesDebutDeLigne, + NombreDeTermesDesLignes, IndicesColonnes, CoefficientsDeLaMatriceDesContraintes ); + +/* Transfert du probleme dans le struct du solveur et initialisation de parametres de controle */ +PNE_InitialiserLaPne( Pne, Probleme ); +if ( Pne->YaUneSolution != OUI_PNE ) { + /*printf("Absence de solution detectee par le PRESOLVE\n");*/ + goto FinDuBranchAndBound; +} + +if ( Pne->Controls != NULL ) { + if ( Pne->Controls->PresolveUniquement == OUI_PNE ) { + if ( Pne->Controls->Presolve != NULL ) { + PNE_PostSolveSiUniquementPresolve( Pne, Probleme ); + PRS_LiberationStructure( (PRESOLVE *) Pne->Controls->Presolve ); + } + goto LibererLeProbleme; + } +} + +/* Pour la connexion au branch and bound pur */ +for ( Pne->NombreDeVariablesEntieresTrav = 0 , i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( Pne->TypeDeVariableTrav[i] == ENTIER ) { + /* printf("PNE_Solveur variable entiere numero %d \n",i); */ + Pne->NumerosDesVariablesEntieresTrav[Pne->NombreDeVariablesEntieresTrav] = i; + Pne->NombreDeVariablesEntieresTrav++; + } +} + +NbVarEntieresLibres = 0; +NbVarLibres = 0; +for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( Pne->TypeDeBorneTrav[i] != VARIABLE_FIXE ) { + Pne->NumeroDesVariablesNonFixes[NbVarLibres] = i; + NbVarLibres++; + if ( Pne->TypeDeVariableTrav[i] == ENTIER ) NbVarEntieresLibres++; + } +} + +Pne->NombreDeVariablesNonFixes = NbVarLibres; +Pne->NombreDeVariablesEntieresNonFixes = NbVarEntieresLibres; + +if ( Pne->NombreDeVariablesEntieresTrav == NbVarLibres) Pne->YaQueDesVariablesEntieres = OUI_PNE; +else Pne->YaQueDesVariablesEntieres = NON_PNE; + +/* S'il n'y a pas de contrainte on fixe les variables */ +if ( Pne->NombreDeContraintesTrav <= 0 ) { + for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( Pne->TypeDeBorneTrav[i] == VARIABLE_FIXE ) continue; + if ( Pne->LTrav[i] > 0. ) { + if ( Pne->TypeDeBorneTrav[i] == VARIABLE_BORNEE_INFERIEUREMENT || + Pne->TypeDeBorneTrav[i] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + Pne->UTrav[i] = Pne->UminTrav[i]; + } + else { + Pne->YaUneSolution = NON_PNE; + break; + } + } + else { + if ( Pne->TypeDeBorneTrav[i] == VARIABLE_BORNEE_SUPERIEUREMENT || + Pne->TypeDeBorneTrav[i] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + Pne->UTrav[i] = Pne->UmaxTrav[i]; + } + else if ( Pne->LTrav[i] == 0.0 ) { + if ( Pne->TypeDeBorneTrav[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Pne->UTrav[i] = Pne->UminTrav[i]; + } + else if ( Pne->TypeDeBorneTrav[i] == VARIABLE_NON_BORNEE ) { + Pne->UTrav[i] = 0.0; + } + else { + Pne->YaUneSolution = NON_PNE; + break; + } + } + else { + Pne->YaUneSolution = NON_PNE; + break; + } + } + } +} + +if ( Pne->YaUneSolution != OUI_PNE ) goto FinDuBranchAndBound; + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + if ( Pne->FaireDuPresolve == OUI_PNE ) { + printf("End of presolve ->"); + printf(" rows: %6d",Pne->NombreDeContraintesTrav); + printf(" columns(unknowns): %6d",NbVarLibres); + printf(" including %d binaries",NbVarEntieresLibres); + printf("\n"); + } + /* Calcul du nombre de termes non nuls dans la matrice */ + Nz = 0; + for ( i = 0 ; i < Pne->NombreDeVariablesTrav ; i++ ) { + if ( Pne->TypeDeBorneTrav[i] == VARIABLE_FIXE ) continue; + ic = Pne->CdebTrav[i]; + while ( ic >= 0 ) { + if ( Pne->ATrav[ic] != 0.0 ) Nz++; + ic = Pne->CsuiTrav[ic]; + } + } + printf("Non zeros -> %d", Nz); + printf("\n\n"); +} + +if ( NbVarLibres > 0 && Pne->NombreDeContraintesTrav > 0 ) { + Pne->YaUneSolution = BB_BranchAndBound( Pne, + Pne->TempsDExecutionMaximum, + Pne->NombreMaxDeSolutionsEntieres, + Pne->ToleranceDOptimalite, + Pne->NombreDeVariablesTrav, + Pne->NombreDeContraintesTrav, + Pne->NombreDeVariablesEntieresTrav, + Pne->AffichageDesTraces, + Pne->NumerosDesVariablesEntieresTrav ); +} +else Pne->YaUneSolution = OUI; + +if ( Pne->YaUneSolution == OUI ) { + Pne->YaUneSolution = SOLUTION_OPTIMALE_TROUVEE; +} +else if ( Pne->YaUneSolution == ARRET_CAR_TEMPS_MAXIMUM_ATTEINT ) { + Pne->YaUneSolution = ARRET_PAR_LIMITE_DE_TEMPS_AVEC_SOLUTION_ADMISSIBLE_DISPONIBLE; +} +else if ( Pne->YaUneSolution == BB_ERREUR_INTERNE ) { + Pne->YaUneSolution = ARRET_CAR_ERREUR_INTERNE; +} +else { + Pne->YaUneSolution = PAS_DE_SOLUTION_TROUVEE; +} + +FinDuBranchAndBound: + +if ( Pne->YaUneSolution == SOLUTION_OPTIMALE_TROUVEE || + Pne->YaUneSolution == ARRET_PAR_LIMITE_DE_TEMPS_AVEC_SOLUTION_ADMISSIBLE_DISPONIBLE ) { + #if VERBOSE_PNE + printf(" ******************************************** \n"); + if ( Pne->YaUneSolution == OUI ) { + printf(" OPTIMUM ATTEINT \n"); + } + else if ( Pne->YaUneSolution == ARRET_CAR_TEMPS_MAXIMUM_ATTEINT ) { + printf(" SOLUTION ADMISSIBLE TROUVEE \n"); + } + #endif + + PNE_RecupererLaSolutionEtCalculerLeCritere( Pne, Probleme ); + +} + +LibererLeProbleme: + +*YaUneSolution = Pne->YaUneSolution; + +PNE_LibereProbleme( Pne ); + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_solveur_sous_probleme.c b/src/ext/Sirius_Solver/pne/pne_solveur_sous_probleme.c new file mode 100644 index 0000000000..4c383817f8 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_solveur_sous_probleme.c @@ -0,0 +1,101 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Solveur de PLNE appele par le solveur pour resoudre un + sous probleme reduit. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +void PNE_SolveurProblemeReduit( PROBLEME_A_RESOUDRE * Probleme, + CONTROLS * Controls ) +{ +PROBLEME_PNE * Pne; void * Tas; + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + Probleme->ExistenceDUneSolution = ARRET_CAR_ERREUR_INTERNE; + return; /* On n'utilise pas le malloc proprietaire */ + Tas = MEM_Init(); + Pne = (PROBLEME_PNE *) MEM_Malloc( Tas, sizeof( PROBLEME_PNE ) ); + if ( Pne == NULL ) { + printf("Saturation memoire, impossible d'allouer l'objet PROBLEME_PNE\n"); + Probleme->ExistenceDUneSolution = ARRET_CAR_ERREUR_INTERNE; + return; + } + Pne->Tas = Tas; +# else + Pne = (PROBLEME_PNE *) malloc( sizeof( PROBLEME_PNE ) ); + if ( Pne == NULL ) { + printf("Saturation memoire, impossible d'allouer l'objet PROBLEME_PNE\n"); + Probleme->ExistenceDUneSolution = ARRET_CAR_ERREUR_INTERNE; + return; + } + Tas = NULL; + Pne->Tas = Tas; + Pne->Controls = (CONTROLS *) malloc( sizeof( CONTROLS ) ); + if ( Pne->Controls == NULL ) { + printf("Saturation memoire, impossible d'allouer l'objet PROBLEME_PNE\n"); + Probleme->ExistenceDUneSolution = ARRET_CAR_ERREUR_INTERNE; + return; + } +# endif + +Pne->AnomalieDetectee = NON_PNE ; +setjmp( Pne->Env ); +if ( Pne->AnomalieDetectee == OUI_PNE ) { + /* Liberation du probleme */ + PNE_LibereProbleme( Pne ); + Probleme->ExistenceDUneSolution = ARRET_CAR_ERREUR_INTERNE; + fflush(stdout); + return; +} +else { + + if ( Probleme->SortirLesDonneesDuProbleme == OUI_PNE ) { + PNE_EcrireJeuDeDonneesMPS( Pne, Probleme ); + } + + /* Optimisation */ + + Pne->ProblemeSpxDuSolveur = NULL; + Pne->ProblemeBbDuSolveur = NULL; + Pne->ProblemePrsDuSolveur = NULL; + + /* Initialisation du temps */ + time( &(Pne->HeureDeCalendrierDebut) ); + + memcpy( (char *) Pne->Controls, (char *) Controls, sizeof( CONTROLS ) ); + + PNE_SolveurCalculs( Probleme , Pne ); +} + +/* Pour vider le buffer des traces */ +fflush(stdout); + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_standalone.c b/src/ext/Sirius_Solver/pne/pne_standalone.c new file mode 100644 index 0000000000..d1d19643c5 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_standalone.c @@ -0,0 +1,531 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Main de la PNE pour le standalone + + AUTEUR: R. GONZALEZ + +************************************************************************/ +# define TEST_MULTI_THREADING + # undef TEST_MULTI_THREADING + +# ifdef TEST_MULTI_THREADING + # include +# endif + +# define CPLUSPLUS + # undef CPLUSPLUS + +# include "pne_sys.h" +# include +# include + +# ifdef __cplusplus + # include "pne_definition_arguments.h" + # include "pne_constantes_externes.h" + # include "pne_define.h" + extern "C" + { + void PNE_Solveur( PROBLEME_A_RESOUDRE * ); + void PNE_LireJeuDeDonneesMPS( void ); + } +# else + # include "pne_fonctions.h" + # include "pne_constantes_externes.h" + # include "pne_define.h" +# endif + +# include "mps_define.h" +# include "mps_extern_global.h" + +# include "bb_define.h" + +PROBLEME_A_RESOUDRE Probleme; + +/*----------------------------------------------------------------------------*/ +# ifdef TEST_MULTI_THREADING + +void * StandAloneLancerUnThread( void * Arg ) +{ + + Probleme.NombreDeVariables = Mps.NbVar; + Probleme.TypeDeVariable = Mps.TypeDeVariable; + Probleme.TypeDeBorneDeLaVariable = Mps.TypeDeBorneDeLaVariable; + Probleme.X = Mps.U; + Probleme.Xmax = Mps.Umax; + Probleme.Xmin = Mps.Umin; + Probleme.CoutLineaire = Mps.L; + Probleme.NombreDeContraintes = Mps.NbCnt; + Probleme.SecondMembre = Mps.B; + Probleme.Sens = Mps.SensDeLaContrainte; + Probleme.IndicesDebutDeLigne = Mps.Mdeb; + Probleme.NombreDeTermesDesLignes = Mps.NbTerm; + Probleme.CoefficientsDeLaMatriceDesContraintes = Mps.A ; + Probleme.IndicesColonnes = Mps.Nuvar; + Probleme.VariablesDualesDesContraintes = Mps.VariablesDualesDesContraintes; + Probleme.SortirLesDonneesDuProbleme = NON_PNE; + Probleme.AlgorithmeDeResolution = SIMPLEXE; /* SIMPLEXE ou POINT_INTERIEUR */ + Probleme.CoupesLiftAndProject = NON_PNE; + Probleme.AffichageDesTraces = OUI_PNE; + Probleme.FaireDuPresolve = OUI_PNE; + if ( Probleme.FaireDuPresolve == NON_PNE ) printf("Attention pas de presolve\n"); + Probleme.TempsDExecutionMaximum = 3600 * 0 /*3600 * 0*/; + Probleme.NombreMaxDeSolutionsEntieres = -1; + Probleme.ToleranceDOptimalite = 1.e-4; /* C'est en % dont 1.e-4 ca fait 1.e-6 */ + + PNE_Solveur( &Probleme ); + + return( NULL ); +} + +# endif +/*----------------------------------------------------------------------------*/ + +int main( int argc , char ** argv ) { +int i ; int j; int YaUneSolution; double Critere; int Cnt; double S; +int il; int ilMax; int CntMx; double Smx; double EcX; int Mip; double EcMoy; +char AfficherLesValeursDesVariables; char VerifierLesContraintes; char TestMultiThreading; +int Nbn; char * pt; char s[256]; char * pts; char ToleranceDOptimaliteExterne; +double ToleranceExterne; +FILE * FlotDeSortie; +# ifdef TEST_MULTI_THREADING + int Erreur; pthread_t Thread[100]; int NbThread; +# endif + +AfficherLesValeursDesVariables = NON_PNE; +VerifierLesContraintes = NON_PNE; +s[0] = '\0'; +ToleranceDOptimaliteExterne = 0; +ToleranceExterne = 0.01; +for ( i = 1 ; i < argc ; i++ ) { + if ( strcmp( argv[i] , "-help" ) == 0 || strcmp( argv[i] , "-h" ) == 0 ) { + printf("\n"); + printf("Options disponibles:\n"); + printf(" -help ou -h Pour obtenir la liste des options disponibles\n"); + printf(" -printv Pour afficher la valeur des variables en fin d'optimisation\n"); + printf(" -verif Pour verifier que toutes les contraintes sont satisfaites par la solution trouvee\n"); + printf(" -all Pour faire l'equivalent de -printv et -verif\n"); + printf(" -gap=value Tolerance d'optimalite pour la solution entiere (value est donne en pourcentage)\n"); + printf("\n"); + exit(0); + } + if ( strcmp( argv[i] , "-printv" ) == 0 ) { + AfficherLesValeursDesVariables = OUI_PNE; + continue; + } + if ( strcmp( argv[i] , "-verif" ) == 0 || strcmp( argv[i] , "-verfi" ) == 0 ) { + VerifierLesContraintes = OUI_PNE; + continue; + } + if ( strcmp( argv[i] , "-all" ) == 0 ) { + AfficherLesValeursDesVariables = OUI_PNE; + VerifierLesContraintes = OUI_PNE; + continue; + } + if ( strstr( argv[i] , "-gap" ) != NULL ) { + pt = strstr( argv[i] , "-gap" ); + pt = strstr( pt , "=" ); + if ( pt == NULL ) continue; + pt++; + pts = s; + while ( isdigit( *pt ) ) { + *pts = *pt; + pts++; + pt++; + } + /* On cherche la virgule */ + if ( *pt == '.' ) { + *pts = *pt; + pts++; + pt++; + } + while ( isdigit( *pt ) ) { + *pts = *pt; + pts++; + pt++; + } + *pts = '\0'; + + ToleranceDOptimaliteExterne = 1; + ToleranceExterne = atof( s ); + if ( ToleranceExterne < 0.0 ) { + printf("gap parameter must be > or = to 0\n"); + exit(0); + } + continue; + } + printf("Option %s inconnue, taper l'option -help pour connaitre la liste des options disponibles\n",argv[i]); + exit(0); +} + +# ifdef _MSC_VER + FlotDeSortie = NULL; + fopen_s( &FlotDeSortie, "RESULTAT.csv", "w" ); +# else + FlotDeSortie = fopen( "RESULTAT.csv", "w" ); +# endif + +if( FlotDeSortie == NULL ) { + printf("Erreur ouverture du fichier de resultats \n"); + exit(0); +} + +/* Lecture du jeu de donnees */ +/* +printf("Debut de la lecture des donnees \n"); fflush(stdout); +*/ +PNE_LireJeuDeDonneesMPS(); + +/* +printf("Fin de la lecture des donnees \n"); fflush(stdout); +*/ +/* Mip: indicateur positionne a OUI_MPS si on veut optimiser en variables entieres + et positionne a NON_MPS si on veut juste faire un simplexe */ + +Mip = NON_MPS; +if ( Mip == NON_MPS ) { + for ( j = 0 ; j < Mps.NbVar ; j++ ) Mps.TypeDeVariable[j] = REEL; +} + +/* +printf("********** Attention on fait une maximisation i.e Cout = -Cout ******************\n"); +for ( j = 0 ; j < Mps.NbVar ; j++ ) Mps.L[j] = -Mps.L[j]; +*/ + +goto PasDeBruitage; +{ double Cout; double S; double UnSurRAND_MAX; int NbVarEntieres; double Cmin; double Cmax; + UnSurRAND_MAX = 1. / RAND_MAX; + Cout = 1; + for ( j = 0 ; j < Mps.NbVar ; j++ ){ + /*if ( Mps.TypeDeVariable[j] == ENTIER ) {*/ + if ( Mps.L[j] != 0.0 ) { + S = (rand() * UnSurRAND_MAX ) - 0.5 ; + S *= 0.9; + Mps.L[j] += S; + if ( Mps.L[j] != 0 ) printf("Mps.L[%d] = %e\n",j,Mps.L[j]); + } + } +} +PasDeBruitage: + +/* +printf("Verification des bornes des variables\n"); +for ( j = 0 ; j < Mps.NbVar ; j++ ) { + if ( Mps.Umin[j] > Mps.Umax[j] ) {printf("Erreur Umin %lf Umax %lf Var %d\n",Mps.Umin[j],Mps.Umax[j],j); exit(0);} +} +*/ +/* +printf("Appel du solveur de PNE \n"); fflush(stdout); +*/ + +TestMultiThreading = NON_PNE; + +# ifdef TEST_MULTI_THREADING + if ( TestMultiThreading == OUI_PNE ) { + NbThread = 1; + i = 0; + while ( i < 1 ) { + for ( j = 0 ; j < NbThread ; j++ ) { + Erreur = pthread_create( &Thread[j] , NULL , StandAloneLancerUnThread , NULL ); + if ( Erreur != 0 ) { + printf("Erreur a la creation du thread\n"); exit(0); + } + } + for ( j = 0 ; j < NbThread ; j++ ) { + pthread_join( Thread[j] , NULL ); + } + i++; + } + exit(0); + } +# endif + +/* Resolution */ + +for ( j = 0 ; j < 1 ; j++ ) { /* Pour tester les fuites memoire on enchaine les resolutions du meme probleme */ + Probleme.NombreDeVariables = Mps.NbVar; + Probleme.TypeDeVariable = Mps.TypeDeVariable; + Probleme.TypeDeBorneDeLaVariable = Mps.TypeDeBorneDeLaVariable; + Probleme.X = Mps.U; + Probleme.Xmax = Mps.Umax; + Probleme.Xmin = Mps.Umin; + Probleme.CoutLineaire = Mps.L; + Probleme.NombreDeContraintes = Mps.NbCnt; + Probleme.SecondMembre = Mps.B; + Probleme.Sens = Mps.SensDeLaContrainte; + Probleme.IndicesDebutDeLigne = Mps.Mdeb; + Probleme.NombreDeTermesDesLignes = Mps.NbTerm; + Probleme.CoefficientsDeLaMatriceDesContraintes = Mps.A; + Probleme.IndicesColonnes = Mps.Nuvar; + Probleme.VariablesDualesDesContraintes = Mps.VariablesDualesDesContraintes; + Probleme.SortirLesDonneesDuProbleme = NON_PNE; + Probleme.AlgorithmeDeResolution = SIMPLEXE; /* SIMPLEXE ou POINT_INTERIEUR */ + Probleme.CoupesLiftAndProject = NON_PNE; + Probleme.AffichageDesTraces = NON_PNE; + Probleme.FaireDuPresolve = OUI_PNE /* OUI_PNE */; + if ( Probleme.FaireDuPresolve == NON_PNE ) printf("!!!!!!!!!!!!!! Attention pas de presolve !!!!!!!!!\n"); + + Probleme.TempsDExecutionMaximum = 0; + Probleme.NombreMaxDeSolutionsEntieres = -1; + Probleme.ToleranceDOptimalite = 1.e-4; /* C'est en % donc 1.e-4 ca fait 1.e-6 */ + + if ( ToleranceDOptimaliteExterne == 1 ) { + Probleme.ToleranceDOptimalite = ToleranceExterne; + printf("gap for optimality was given by the user: %f (must be postive or zero)\n",ToleranceExterne); + } + + PNE_Solveur( &Probleme ); + + YaUneSolution = Probleme.ExistenceDUneSolution; + +/* +for ( j = 0 ; j < Mps.NbVar ; j++ ){ + if ( Mps.TypeDeVariable[j] == ENTIER ) Mps.L[j] = 0.0; +} +*/ + +Nbn = 0; +printf("Dual variables count %d\n",Mps.NbCnt); +for ( Cnt = 0 ; Cnt < Mps.NbCnt ; Cnt++ ) { + goto ABS; + printf("Sense[%d] %c B = %e dual variable = %e\n",Cnt,Mps.SensDeLaContrainte[Cnt],Mps.B[Cnt], + Mps.VariablesDualesDesContraintes[Cnt]); + ABS: + if ( fabs( Mps.VariablesDualesDesContraintes[Cnt] ) < 1.e-8 ) Nbn++; +} +printf("Zero dual variables count %d over %d\n",Nbn,Mps.NbCnt); + +/*****************/ + + if ( Probleme.AlgorithmeDeResolution == POINT_INTERIEUR ) goto FinTest; + goto FinTest; + /* Test du local branching */ + { int LgL; int Var; double * TA; double K; int Cnt; int il; + + Critere = 0.; + for ( i = 0 ; i < Mps.NbVar ; i++ ) Critere+= Mps.L[i] * Mps.U[i]; + + if ( YaUneSolution == SOLUTION_OPTIMALE_TROUVEE || + YaUneSolution == SOLUTION_OPTIMALE_TROUVEE_MAIS_QUELQUES_CONTRAINTES_SONT_VIOLEES || + YaUneSolution == ARRET_PAR_LIMITE_DE_TEMPS_AVEC_SOLUTION_ADMISSIBLE_DISPONIBLE ) { + printf("\n********** Objective %e **********\n\n",Critere); + } + + LgL = -1; + for ( Cnt = 0 ; Cnt < Mps.NbCnt ; Cnt++ ) { + if ( Mps.Mdeb[Cnt] + Mps.NbTerm[Mps.NbCnt] > LgL ) { + LgL = Mps.Mdeb[Cnt] + Mps.NbTerm[Mps.NbCnt]; + } + } + LgL+= Mps.NbVar; + + Mps.NbCnt++; + Mps.B = (double *) realloc( Mps.B , Mps.NbCnt * sizeof( double ) ); + Mps.SensDeLaContrainte = ( char * ) realloc( Mps.SensDeLaContrainte , Mps.NbCnt * sizeof( char ) ); + Mps.Mdeb = ( int * ) realloc( Mps.Mdeb , Mps.NbCnt * sizeof( int ) ); + Mps.NbTerm = ( int * ) realloc( Mps.NbTerm , Mps.NbCnt * sizeof( int ) ); + + Mps.A = (double *) realloc( Mps.A , LgL * sizeof( double ) ); + Mps.Nuvar = (int *) realloc( Mps.Nuvar , LgL * sizeof( int ) ); + + Mps.VariablesDualesDesContraintes = (double *) realloc( Mps.VariablesDualesDesContraintes , Mps.NbCnt * sizeof( double ) ); + + TA = (double *) malloc( Mps.NbVar * sizeof( double ) ); + K = 1; + Cnt = Mps.NbCnt - 1; + Mps.B[Cnt] = K; + Mps.SensDeLaContrainte[Cnt] = '<'; + for ( Var = 0 ; Var < Mps.NbVar ; Var++ ) { + TA[Var] = 0.0; + if ( Mps.TypeDeVariable[Var] == ENTIER ) { + TA[Var] = 1.; + if ( Mps.U[Var] == 1.0 ) { + Mps.B[Cnt]-= 1; + TA[Var] = -1.; + } + } + } + il = Mps.Mdeb[Cnt - 1] + Mps.NbTerm[Cnt - 1]; + Mps.Mdeb[Cnt] = il; + Mps.NbTerm[Cnt] = 0; + for ( Var = 0 ; Var < Mps.NbVar ; Var++ ) { + if ( TA[Var] != 0.0 ) { + Mps.A[il] = TA[Var]; + Mps.Nuvar[il] = Var; + Mps.NbTerm[Cnt]++; + il++; + } + } + /*printf("Mps.NbTerm[Cnt] %d\n",Mps.NbTerm[Cnt]);*/ + + } + /* Fin Test du local branching */ + FinTest: + continue; + +} + +/* Resultats */ + +if ( YaUneSolution == PAS_DE_SOLUTION_TROUVEE ) printf("No solution found\n"); +if ( YaUneSolution == PROBLEME_INFAISABLE ) printf("Problem is infeasible\n"); +if ( YaUneSolution == PROBLEME_NON_BORNE ) printf("Problem is unbounded\n"); + +if ( YaUneSolution == ARRET_CAR_ERREUR_INTERNE ) printf("Internal error\n"); +if ( YaUneSolution == SOLUTION_OPTIMALE_TROUVEE_MAIS_QUELQUES_CONTRAINTES_SONT_VIOLEES ) +printf("An optimal solution was found but some constraints remain violated\n"); + +if ( YaUneSolution == SOLUTION_OPTIMALE_TROUVEE || + YaUneSolution == ARRET_PAR_LIMITE_DE_TEMPS_AVEC_SOLUTION_ADMISSIBLE_DISPONIBLE || + YaUneSolution == SOLUTION_OPTIMALE_TROUVEE_MAIS_QUELQUES_CONTRAINTES_SONT_VIOLEES ) { + + fprintf( FlotDeSortie , "VARIABLES VALUES;\n" ); + for ( i = 0 ; i < Mps.NbVar ; i++ ) { + fprintf( FlotDeSortie , "%s;%e\n" , Mps.LabelDeLaVariable[i], Mps.U[i] ); + } + fprintf( FlotDeSortie , "DUAL VARIABLES;\n" ); + for ( Cnt = 0 ; Cnt < Mps.NbCnt ; Cnt++ ) { + fprintf( FlotDeSortie , "%s;%e\n" ,Mps.LabelDeLaContrainte[Cnt], Mps.VariablesDualesDesContraintes[Cnt] ); + } + fclose( FlotDeSortie ); + + Critere = 0.; + for ( i = 0 ; i < Mps.NbVar ; i++ ) { + Critere+= Mps.L[i] * Mps.U[i]; + if ( AfficherLesValeursDesVariables == OUI_PNE ) { + printf("Variable number %d name %s value %lf ",i, Mps.LabelDeLaVariable[i], Mps.U[i]); + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_FIXE ) printf(" FIXED variable\n"); + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( Mps.TypeDeVariable[i] == ENTIER ) printf(" min %lf max %lf binary variable\n",Mps.Umin[i], Mps.Umax[i]); + else printf(" min %lf max %lf\n",Mps.Umin[i], Mps.Umax[i]); + } + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_INFERIEUREMENT ) + printf(" min %lf max +INFINI\n",Mps.Umin[i]); + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) + printf(" min -INFINI max %lf\n",Mps.Umax[i]); + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_NON_BORNEE ) + printf(" min -INFINI max +INFINI\n"); + } + } + if ( AfficherLesValeursDesVariables == OUI_PNE ) { + printf("\n********** Binary variables output **********\n\n"); + for ( i = 0 ; i < Mps.NbVar ; i++ ) { + if ( Mps.TypeDeVariable[i] == ENTIER ) { + printf("Variable number %d name %s value %lf\n",i, Mps.LabelDeLaVariable[i], Mps.U[i]); + } + } + } + if ( YaUneSolution == SOLUTION_OPTIMALE_TROUVEE || + YaUneSolution == SOLUTION_OPTIMALE_TROUVEE_MAIS_QUELQUES_CONTRAINTES_SONT_VIOLEES ) { + printf("\n********** Optimal solution found, objective %e **********\n\n",Critere); + } + else if ( YaUneSolution == ARRET_PAR_LIMITE_DE_TEMPS_AVEC_SOLUTION_ADMISSIBLE_DISPONIBLE ) { + printf("\n********** Feasible solution found, objective %e **********\n\n",Critere); + } + + if ( VerifierLesContraintes == OUI_PNE ) { + + for ( i = 0 ; i < Mps.NbVar ; i++ ) { + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( Mps.U[i] < Mps.Umin[i] - 1.e-6 ) { + printf("Variable number %d name %s violated lower bound: lo= %e value= %e violation= %e\n", + i, Mps.LabelDeLaVariable[i],Mps.Umin[i],Mps.U[i],Mps.Umin[i]-Mps.U[i]); + } + else if ( Mps.U[i] > Mps.Umax[i] + 1.e-6 ) { + printf("Variable number %d name %s violated upper bound: up= %e value= %e violation= %e\n", + i, Mps.LabelDeLaVariable[i],Mps.Umax[i],Mps.U[i],Mps.U[i]-Mps.Umax[i]); + } + continue; + } + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( Mps.U[i] < Mps.Umin[i] - 1.e-6 ) { + printf("Variable number %d name %s violated lower bound: lo= %e value= %e violation= %e\n", + i, Mps.LabelDeLaVariable[i],Mps.Umin[i],Mps.U[i],Mps.Umin[i]-Mps.U[i]); + } + continue; + } + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + if ( Mps.U[i] > Mps.Umax[i] + 1.e-6 ) { + printf("Variable number %d name %s violated upper bound: up= %e value= %e violation= %e\n", + i, Mps.LabelDeLaVariable[i],Mps.Umax[i],Mps.U[i],Mps.U[i]-Mps.Umax[i]); + } + continue; + } + } + + Smx = -1.; + EcX = 1.e-6; + CntMx = -1; + EcMoy = 0.; + + for ( Cnt = 0 ; Cnt < Mps.NbCnt ; Cnt++ ) { + S = 0.; + il = Mps.Mdeb[Cnt]; + ilMax = il + Mps.NbTerm[Cnt]; + while ( il < ilMax ) { + i = Mps.Nuvar[il]; + S+= Mps.A[il] * Mps.U[i]; + il++; + } + if ( Mps.SensDeLaContrainte[Cnt] == '=' ) { + EcMoy+= fabs( S - Mps.B[Cnt] ); + if ( fabs( S - Mps.B[Cnt] ) > EcX ) { + EcX = fabs( S - Mps.B[Cnt] ); + Smx = S; + CntMx = Cnt; + printf("Cnt %d sens = : S %e B %e\n",Cnt,S,Mps.B[Cnt]); + } + } + if ( Mps.SensDeLaContrainte[Cnt] == '>' && S < Mps.B[Cnt] ) { + EcMoy+= fabs( S - Mps.B[Cnt] ); + if ( fabs( S - Mps.B[Cnt] ) > EcX ) { + EcX = fabs( S - Mps.B[Cnt] ); + Smx = S; + CntMx = Cnt; + printf("Cnt %d sens > : S %e B %e\n",Cnt,S,Mps.B[Cnt]); + } + } + if ( Mps.SensDeLaContrainte[Cnt] == '<' && S > Mps.B[Cnt] ) { + EcMoy+= fabs( S - Mps.B[Cnt] ); + if ( fabs( S - Mps.B[Cnt] ) > EcX ) { + EcX = fabs( S - Mps.B[Cnt] ); + Smx = S; + CntMx = Cnt; + printf("Cnt %d sens < : S %e B %e\n",Cnt,S,Mps.B[Cnt]); + } + } + /*printf("cnt %ld S %e B %e\n",Cnt,S,Mps.B[Cnt]);*/ + } + if ( CntMx >= 0 ) { + printf("Higher violation:\n"); + if ( Mps.SensDeLaContrainte[CntMx] == '=' ) printf("Cnt num %d - %s -- type = ",CntMx,Mps.LabelDeLaContrainte[CntMx]); + if ( Mps.SensDeLaContrainte[CntMx] == '<' ) printf("Cnt num %d - %s -- type < ",CntMx,Mps.LabelDeLaContrainte[CntMx]); + if ( Mps.SensDeLaContrainte[CntMx] == '>' ) printf("Cnt num %d - %s -- type > ",CntMx,Mps.LabelDeLaContrainte[CntMx]); + printf(" B %e computed %e violation %e\n",Mps.B[CntMx],Smx,fabs(Smx-Mps.B[CntMx])); + } + EcMoy/= Mps.NbCnt; + printf("Violations average value: %e\n",EcMoy); + + } + +} + +printf("\n"); + +exit(0); +} diff --git a/src/ext/Sirius_Solver/pne/pne_strong_branching.c b/src/ext/Sirius_Solver/pne/pne_strong_branching.c new file mode 100644 index 0000000000..2aa4b0a8a7 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_strong_branching.c @@ -0,0 +1,698 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Strong branching pour le choix de la variable a instancier. + Appelé par le branch and bound, ce sous-programme retourne + le numéro de la variable a instancier et la base de depart + qu'il faudra utiliser lorsque l'on évaluera le noeud dans + une étape ultérieure. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define SEUIL_BIG_M 1.e-2 + +void PNE_StrongBranchingTesterLesGUB( PROBLEME_PNE * ); +void PNE_StrongBranchingGraphedeConflit( PROBLEME_PNE * , int , double ); + +/*----------------------------------------------------------------------------*/ + +double PNE_ValeurOptimaleDuProblemeCourantAvantNouvellesCoupes( PROBLEME_PNE * Pne ) +{ +return( Pne->ValeurOptimaleDuProblemeCourantAvantNouvellesCoupes ); +} + +/*----------------------------------------------------------------------------*/ + +void PNE_StrongBranching( PROBLEME_PNE * Pne, + /*int * PositionDeLaVariable,*/ + /* Choix de la variable a instancier */ + double * MinorantEspereAGauche, + double * MinorantEspereADroite, + /* Base correspondante pour l'instanciation a gauche */ + int * PositionDeLaVariableAGauche , + int * NbVarDeBaseComplementairesAGauche, + int * ComplementDeLaBaseAGauche , + /* Base correspondante pour l'instanciation a droite */ + int * PositionDeLaVariableADroite , + int * NbVarDeBaseComplementairesADroite, + int * ComplementDeLaBaseADroite , + /* Indicateur de disponibilite des bases a entier sup et inf */ + int * BasesFilsDisponibles, + /* Si on demande le calcul des coupes, on ne fait pas de strong branching */ + char * CalculerDesCoupes, + /*char NumeroDePasse,*/ + char ChoisirLaVariableAInstancier + ) +{ +int i ; int Count; int Var; int NbSeuil; int il; char ChoixDefinitif ; char ChoixAmeliorant; +double Seuil; int ExistenceDUneSolAGauche ; double r; int ExistenceDUneSolADroite; char TypeDeSolution ; +int * PosVarAGauche; int * ComplBaseAGauche; int * PosVarADroite; double Frac; +int * ComplBaseADroite; double DeltaXAGauche ; double DeltaXADroite; int NbVarComplAGauche; int NbVarComplADroite; +double CritereAGauche; double CritereADroite; double SupEcartDInstanciation; double SupDeNouveauCritere; +double SeuilNouveauCout ; double CritereInfini ; double Marge; double Crit; double MinCritere; +char * PositionDeLaVariableDEcartAGauche; char * PositionDeLaVariableDEcartADroite; char ExistenceSolutionAGauche; +char ExistenceSolutionADroite; char VariableSelectionnee; int SeuilMx; +char ChoixDuTypeDeVariation; char TesterLeBranchementSurLesGub; double CoutReduitInf; double CoutReduitSup; +int NombreDeVariablesTrav; int NombreDeContraintesTrav; double X; int PremFrac; int * SuivFrac; +int * TypeDeBorneTrav; int * TypeDeVariableTrav; double * UTrav; double * UminTrav; double * UmaxTrav; +double * UStrongBranching; double * LTrav; char * VariableBinaireBigM; int VarChoix; double PremiereFractionnalite; +BB * Bb; NOEUD * Noeud; double FracMoy; int Nb; + +CritereInfini = LINFINI_PNE; + +*MinorantEspereAGauche = Pne->Critere; +*MinorantEspereADroite = Pne->Critere; + +if ( Pne->FaireDuStrongBranching != OUI_PNE ) goto PasStrongBranching; + +if ( *CalculerDesCoupes == OUI_PNE ) { + if ( ChoisirLaVariableAInstancier == NON_PNE ) { + goto PasStrongBranching; + } +} + +Bb = Pne->ProblemeBbDuSolveur; +Noeud = Bb->NoeudEnExamen; + +if ( Pne->SolveurPourLeProblemeRelaxe != POINT_INTERIEUR && Pne->NombreDeVariablesAValeurFractionnaire >= 1 ) { + + PremFrac = Pne->PremFrac; + SuivFrac = Pne->SuivFrac; + UTrav = Pne->UTrav; + + VariableBinaireBigM = Pne->VariableBinaireBigM; + if ( Pne->YaDesBigM == OUI_PNE && Pne->YaUneSolutionEntiere == NON_PNE ) { + /* S'il y a des Big M sur des variables entieres on va privilegier l'instanciation de ces variables */ + r = -1.; + VarChoix = -1; + i = PremFrac; + while ( i >= 0 ) { + /* Si la fractionalite d'une variable est tres proche de 0 on regarde si en la multipliant par + son plus grand coeff, on obtient un nombre non negligeable. Si c'est le cas cela signifie + que l'on aura du mal a dire si la variable est a 0 oui a 1 et dans ce cas le mieux est de + l'instancier pour lever le doute. Comme il peut y avoir plusieurs variables dans ce cas, + on prend celle dont le produit s'eloigne le plus de 0 */ + if ( VariableBinaireBigM[i] == OUI_PNE ) { + X = UTrav[i]; + if ( X - floor( X ) < ceil( X ) - X ) X = X - floor( X ); + else X = ceil( X ) - X; + Frac = X; + if ( Frac < TOLERANCE_SUR_LES_ENTIERS ) { + X = Frac * ( SEUIL_DADMISSIBILITE / Pne->SeuilDeFractionnalite[i] ); + if ( X > r ) { + r = X; + VarChoix = i; + } + } + } + i = SuivFrac[i]; + } + if ( VarChoix >= 0 && r > SEUIL_BIG_M ) { + Pne->VariableLaPlusFractionnaire = VarChoix; + /* + printf("Instanciation variable big M %d de valeur %e Ai %e\n",VarChoix,UTrav[VarChoix],SEUIL_DADMISSIBILITE / Pne->SeuilDeFractionnalite[VarChoix]); + */ + goto PasStrongBranching; + } + } + + PosVarAGauche = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); + ComplBaseAGauche = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); + PosVarADroite = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); + ComplBaseADroite = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); + + PositionDeLaVariableDEcartAGauche = (char *) malloc( Pne->Coupes.NombreDeContraintes * sizeof( char ) ); + PositionDeLaVariableDEcartADroite = (char *) malloc( Pne->Coupes.NombreDeContraintes * sizeof( char ) ); + + if ( + PosVarAGauche == NULL || ComplBaseAGauche == NULL || + PosVarADroite == NULL || ComplBaseADroite == NULL || + PositionDeLaVariableDEcartAGauche == NULL || PositionDeLaVariableDEcartADroite == NULL + ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_StrongBranching \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); + } + + #if VERBOSE_PNE + printf(" Phase de Strong Branching \n"); + #endif + + NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; + NombreDeContraintesTrav = Pne->NombreDeContraintesTrav; + TypeDeBorneTrav = Pne->TypeDeBorneTrav; + TypeDeVariableTrav = Pne->TypeDeVariableTrav; + + UminTrav = Pne->UminTrav; + UmaxTrav = Pne->UmaxTrav; + + UStrongBranching = Pne->UStrongBranching ; + LTrav = Pne->LTrav; + + + NbSeuil = (int) floor( 0.5 * Pne->NombreDeVariablesAValeurFractionnaire ); + if ( NbSeuil < 5 ) NbSeuil = 5; + SeuilMx = 50; + if ( Pne->YaUneSolutionEntiere == OUI_PNE ) SeuilMx = 50; + + /* Valeur par defaut: PENTE_DE_LA_VARIATION */ + ChoixDuTypeDeVariation = PENTE_DE_LA_VARIATION; + + Seuil = 1.e-3; + NbSeuil = 0; + + /* Si la fractionnalite chute brutalement d'un rapport r on arrete */ + r = 1.e-2 /*1.e-2*/; + Crit = 0.0; + i = PremFrac; + while ( i >= 0 ) { + X = UTrav[i]; + if ( X - floor( X ) < ceil( X ) - X ) X = X - floor( X ); + else X = ceil( X ) - X; + /* X est la fractionnalite */ + if ( X < r * Crit && X < Seuil ) break; + Crit = X; + NbSeuil++; + i = SuivFrac[i]; + } + + if ( NbSeuil < 4/*2*/ ) NbSeuil = 4/*2*/; + else if ( NbSeuil > SeuilMx ) NbSeuil = SeuilMx; + + /* Si les fractionnalites sont trop disparates, on evite d'utiliser la pente de variation */ + /* Si la fractionnalite moyenne est trop faible on prend VALEUR_ABSOLUE_DE_LA_VARIATION */ + + Nb = 0; + FracMoy = 0.0; + + i = PremFrac; + X = UTrav[i]; + if ( X - floor( X ) < ceil( X ) - X ) X = X - floor( X ); + else X = ceil( X ) - X; + il = i; + + FracMoy += X; + Nb++; + + i = SuivFrac[i]; + Count = 1; + while ( i >= 0 && Count < NbSeuil ) { + + X = UTrav[i]; + if ( X - floor( X ) < ceil( X ) - X ) X = X - floor( X ); + else X = ceil( X ) - X; + FracMoy += X; + Nb++; + + il = i; + i = SuivFrac[i]; + Count++; + } + + Crit = UTrav[il]; + if ( Crit - floor( Crit ) < ceil( Crit ) - Crit ) Crit = Crit - floor( Crit ); + else Crit = ceil( Crit ) - Crit; + if ( X / Crit > 1.e+6 ) { + ChoixDuTypeDeVariation = VALEUR_ABSOLUE_DE_LA_VARIATION; + } + + if ( Nb > 0 ) { + FracMoy /= Nb; + /*printf("FracMoy %e \n",FracMoy);*/ + if ( FracMoy < 1.e-2 ) { + ChoixDuTypeDeVariation = VALEUR_ABSOLUE_DE_LA_VARIATION; + /*printf("FracMoy %e => VALEUR_ABSOLUE_DE_LA_VARIATION\n",FracMoy);*/ + } + } + + #if VERBOSE_PNE + if ( ChoixDuTypeDeVariation == VALEUR_ABSOLUE_DE_LA_VARIATION ) printf("ChoixDuTypeDeVariation = VALEUR_ABSOLUE_DE_LA_VARIATION\n"); + if ( ChoixDuTypeDeVariation == PENTE_DE_LA_VARIATION ) printf("ChoixDuTypeDeVariation = PENTE_DE_LA_VARIATION\n"); + #endif + + /* Test */ + if ( Bb->NombreDeSolutionsEntieresTrouvees > 0 ) { + if ( Bb->EcartBorneInf < 1.e-2 ) ChoixDuTypeDeVariation = PENTE_DE_LA_VARIATION; + } + /* Fin test */ + + SupDeNouveauCritere = -CritereInfini; + SupEcartDInstanciation = 1.e-6; + + MinCritere = CritereInfini; + SeuilNouveauCout = Pne->Critere + ( 0.1 * fabs( Pne->Critere ) ); + Marge = 0.; + Count = 0; + + Pne->NbVarGauche = 0; /* Par precaution */ + Pne->NbVarDroite = 0; /* Par precaution */ + + /* Soit il n'y a pas de Gub, soit les variations de critere sont trop faible. Mais dans ce cas, + SupDeNouveauCritere a pu etre initialise */ + + PremiereFractionnalite = Pne->UTrav[PremFrac] - floor( Pne->UTrav[PremFrac] ); + if ( PremiereFractionnalite > ceil( Pne->UTrav[PremFrac] ) - Pne->UTrav[PremFrac] ) { + PremiereFractionnalite = ceil( Pne->UTrav[PremFrac] ) - Pne->UTrav[PremFrac]; + } + + CritereAGauche = Pne->Critere; /* Pour ne pas avoir de warning a la compilation */ + CritereADroite = Pne->Critere; /* Pour ne pas avoir de warning a la compilation */ + + VariableSelectionnee = NON_PNE; + i = PremFrac; + while ( i >= 0 && Count < NbSeuil ) { + + Frac = Pne->UTrav[i] - floor( Pne->UTrav[i] ); + if ( Frac > ceil( Pne->UTrav[i] ) - Pne->UTrav[i] ) { + Frac = ceil( Pne->UTrav[i] ) - Pne->UTrav[i]; + } + + if ( Frac < 0.1 * PremiereFractionnalite && Count > 20 ) break; + else if ( Frac < 0.01 * PremiereFractionnalite && 0 ) break; + else if ( Frac < 1.e-8 && 0 ) break; + + #if VERBOSE_PNE + printf(" Variable fractionnaire etudiee -> %d cout %e valeur %e UminTrav %lf UmaxTrav %lf SeuilDeFractionnalite %e\n", + i,Pne->LTrav[i],Pne->UTrav[i],Pne->UminTrav[i],Pne->UmaxTrav[i],Pne->SeuilDeFractionnalite[i]); + printf(" ----> Fixation a Umin:\n"); + #endif + + memcpy( (char *) UStrongBranching, (char *) UTrav , NombreDeVariablesTrav * sizeof( double ) ); + NbVarComplAGauche = 0; + DeltaXAGauche = UTrav[i]; + + PNE_StrongBranchingGraphedeConflit( Pne, i, 0.0 ); + + SPX_DualStrongBranching( + (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur, + /* La variable a brancher */ + i, + LTrav[i], + UminTrav[i], + UminTrav[i], + /* Sortie */ + &CoutReduitInf, + &ExistenceDUneSolAGauche, + &TypeDeSolution , + UStrongBranching , + PosVarAGauche , + &NbVarComplAGauche, + ComplBaseAGauche , + /* Donnees complementaires */ + NombreDeVariablesTrav, + TypeDeBorneTrav, + NombreDeContraintesTrav, + /* Coupes */ + Pne->Coupes.NombreDeContraintes, + Pne->Coupes.NbTerm, + PositionDeLaVariableDEcartAGauche + ); + /* Calcul du critere apres strong branching */ + if ( ExistenceDUneSolAGauche == OUI_SPX ) { + ExistenceSolutionAGauche = OUI_PNE; + for ( CritereAGauche = Pne->Z0 , Var = 0 ; Var < NombreDeVariablesTrav ; Var++ ) { + CritereAGauche += LTrav[Var] * UStrongBranching[Var]; + } + } + else { + ExistenceSolutionAGauche = NON_PNE; + CritereAGauche = CritereInfini; + #if VERBOSE_PNE + printf("Pas de solution a gauche\n"); + #endif + } + + #if VERBOSE_PNE + printf(" CritereAGauche : %e \n",CritereAGauche); + #endif + + #if VERBOSE_PNE + printf(" ----> Fixation a Umax:\n"); + #endif + + memcpy( (char *) UStrongBranching, (char *) UTrav , NombreDeVariablesTrav * sizeof( double ) ); + NbVarComplADroite = 0; + DeltaXADroite = UmaxTrav[i] - UTrav[i]; + + PNE_StrongBranchingGraphedeConflit( Pne, i, 1.0 ); + + SPX_DualStrongBranching( + (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur, + /* La variable a brancher */ + i, + LTrav[i], + UmaxTrav[i], + UmaxTrav[i], + /* Sortie */ + &CoutReduitSup, + &ExistenceDUneSolADroite, + &TypeDeSolution , + UStrongBranching, + PosVarADroite , + &NbVarComplADroite, + ComplBaseADroite , + /* Donnees complementaires */ + NombreDeVariablesTrav, + TypeDeBorneTrav, + NombreDeContraintesTrav, + /* Coupes */ + Pne->Coupes.NombreDeContraintes, + Pne->Coupes.NbTerm, + PositionDeLaVariableDEcartADroite + ); + /* Calcul du critere aprčs strong branching */ + if ( ExistenceDUneSolADroite == OUI_SPX ) { + ExistenceSolutionADroite = OUI_PNE; + for ( CritereADroite = Pne->Z0 , Var = 0 ; Var < NombreDeVariablesTrav ; Var++ ) { + CritereADroite += LTrav[Var] * UStrongBranching[Var]; + } + } + else { + /* On multiplie par 2 pour que s'il n'y a pas de solution ni a entier inf. ni a entier sup., la variable + puisse etre choisie */ + ExistenceSolutionADroite = NON_PNE; + CritereADroite = 2 * CritereInfini; + #if VERBOSE_PNE + printf("Pas de solution a entier sup\n"); + #endif + } + + #if VERBOSE_PNE + printf(" CritereADroite : %e\n",CritereADroite); + #endif + + PNE_StrongBranchingClasserLeResultat( Pne , ChoixDuTypeDeVariation , + ExistenceSolutionAGauche , ExistenceSolutionADroite , + CritereAGauche , DeltaXAGauche , + CritereADroite , DeltaXADroite , + CritereInfini , Marge , + &SupDeNouveauCritere , &SupEcartDInstanciation , i , + &ChoixDefinitif , &ChoixAmeliorant , + SeuilNouveauCout , + MinorantEspereAGauche , MinorantEspereADroite , + PositionDeLaVariableAGauche, NbVarDeBaseComplementairesAGauche, + ComplementDeLaBaseAGauche , PosVarAGauche , + NbVarComplAGauche , ComplBaseAGauche , + PositionDeLaVariableDEcartAGauche, + PositionDeLaVariableADroite , NbVarDeBaseComplementairesADroite, + ComplementDeLaBaseADroite , PosVarADroite , + NbVarComplADroite , ComplBaseADroite , + PositionDeLaVariableDEcartADroite, + BasesFilsDisponibles + ); + + if ( ChoixAmeliorant == OUI_PNE || ChoixDefinitif == OUI_PNE ) { + VariableSelectionnee = OUI_PNE; + if ( Pne->NbVarGauche > 0 && Pne->NbVarDroite > 0 ) { + Pne->NbVarGauche = 0; + Pne->NbVarDroite = 0; + } + } + + if ( ChoixDefinitif == OUI_PNE ) break; + + i = SuivFrac[i]; + Count++; + } + + /* Si une variable a ete choisie et si elle fait partie d'une gub, on cherche a faire + le branchement sur les gub */ + + TesterLeBranchementSurLesGub = NON_PNE; /* NON_PNE*/ + # if UTILISER_LES_GUB == OUI_PNE + TesterLeBranchementSurLesGub = OUI_PNE; + # endif + if ( VariableSelectionnee == OUI_PNE && TesterLeBranchementSurLesGub == OUI_PNE ) { + if ( Noeud->ProfondeurDuNoeud <= PROFONDEUR_LIMITE_POUR_UTILISATION_DES_GUB || Pne->YaUneSolutionEntiere == NON_PNE ) { + PNE_StrongBranchingTesterLesGUB( Pne ); + } + } + + free( PosVarAGauche ); + free( ComplBaseAGauche ); + free( PosVarADroite ); + free( ComplBaseADroite ); + free( PositionDeLaVariableDEcartAGauche ); + free( PositionDeLaVariableDEcartADroite ); + +} + +PasStrongBranching: + +if ( Pne->VariableLaPlusFractionnaire >= 0 ) { + #if VERBOSE_PNE + printf(" Variable la plus fractionnaire: %d Valeur: %e \n", + Pne->VariableLaPlusFractionnaire,Pne->UTrav[Pne->VariableLaPlusFractionnaire]); + #endif + if ( *BasesFilsDisponibles == OUI_PNE ) { + if ( PositionDeLaVariableAGauche[Pne->VariableLaPlusFractionnaire] < 0 || + PositionDeLaVariableADroite[Pne->VariableLaPlusFractionnaire] < 0 ) { printf("Bug dans le strong branching\n"); exit(0); } + } + fflush(stdout); + + if ( *CalculerDesCoupes != OUI_PNE && 0 ) { + /* test: on cherche les symetries (seulement colonnes identiques) */ + PNE_RechercheSymetries( Pne, Pne->VariableLaPlusFractionnaire, BasesFilsDisponibles ); + } + + +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Si une variable a ete choisie et si elle fait partie d'une gub, on cherche a faire + le branchement sur les gub */ +void PNE_StrongBranchingTesterLesGUB( PROBLEME_PNE * Pne ) +{ +char LaVariableInstancieeEstDansUneGub; int NbTGub; int GubChoisie; int NbVarNonFix; +int TaillePaquet1; int i; int Cnt; int il; int ilMax; int Var; int NombreDeGub; +int * NumeroDeContrainteDeLaGub; int * Mdeb; int * NbTerm; int * Nuvar; int * TypeDeBorne; +double * Xmin; double * Xmax; int Var0; int Prem; int VarPrec; double Frac; int * Suiv; +double * X; char Dernier; + +NombreDeGub = Pne->NombreDeGub; +NumeroDeContrainteDeLaGub = Pne->NumeroDeContrainteDeLaGub; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; +X = Pne->UTrav; + +NbTGub = -1; +GubChoisie = -1; +for ( i = 0 ; i < NombreDeGub ; i++ ) { + Cnt = NumeroDeContrainteDeLaGub[i]; + if ( Cnt < 0 ) continue; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + NbVarNonFix = 0; + LaVariableInstancieeEstDansUneGub = NON_PNE; + while ( il < ilMax ) { + Var = Nuvar[il]; + if ( TypeDeBorne[Var] != VARIABLE_FIXE && Xmin[Var] != Xmax[Var] ) { + NbVarNonFix++; + if ( Var == Pne->VariableLaPlusFractionnaire ) LaVariableInstancieeEstDansUneGub = OUI_PNE; + } + il++; + } + if ( LaVariableInstancieeEstDansUneGub == OUI_PNE ) { + if ( NbVarNonFix > NbTGub && NbVarNonFix >= MIN_TERMES_GUB && NbVarNonFix >= MAX_TERMES_GUB ) { + GubChoisie = i; + NbTGub = NbVarNonFix; + } + } +} + +if ( GubChoisie < 0 ) return; + +Suiv = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +if ( Suiv == NULL ) return; + +/* Si la variable instanciee se trouve dans une gub on instancie plutot la GUB */ +/* Il y aura quand meme un pb de base de depart et de minorant espere de chaque cote */ +/* On instancie une partie des variables de la GUB */ +/*printf("La variable selectionee dans la premiere partie est dans une GUB a plus de 2 termes \n");*/ +Cnt = NumeroDeContrainteDeLaGub[GubChoisie]; + +/* On classe les variables de la GUB dans l'ordre croissant des fractionnalites puis on fait 2 + paquets de taille equivalente a 1 pres */ + +Prem = -1; +il = Mdeb[Cnt]; +ilMax = il + NbTerm[Cnt]; +while ( il < ilMax ) { + Var = Nuvar[il]; + if ( TypeDeBorne[Var] != VARIABLE_FIXE && Xmin[Var] != Xmax[Var] ) { + Frac = fabs( 0.5 - X[Var] ); + /* Classement de la variable */ + if ( Prem == -1 ) { /* C'est la premiere variable */ + Prem = Var; + Suiv[Var] = -1; + } + else { + /* C'est pas la premiere variable: on lui cherche un emplacement */ + Var0 = Prem; + if ( Frac < fabs( 0.5 - X[Var0] ) ) { + Prem = Var; + Suiv[Var] = Var0; + } + else { + /* C'est pas la plus petite fractionnalite */ + Dernier = OUI_PNE; + VarPrec = Var0; + Var0 = Suiv[Var0]; + while ( Var0 >= 0 ) { + if ( Frac NbVarGauche = 0; +Pne->ValeurAGauche = Pne->ValeurDInstanciationPourLaGub[GubChoisie]; +Var = Prem; +while ( Pne->NbVarGauche < TaillePaquet1 && Var >= 0 ) { + Pne->PaquetDeGauche[Pne->NbVarGauche] = Var; + Pne->NbVarGauche++; + Var = Suiv[Var]; +} +Pne->NbVarDroite = 0; +Pne->ValeurADroite = Pne->ValeurDInstanciationPourLaGub[GubChoisie]; +while ( Var >= 0 ) { + Pne->PaquetDeDroite[Pne->NbVarDroite] = Var; + Pne->NbVarDroite++; + Var = Suiv[Var]; +} + +/* Choix de l'instanciation terminee */ +/* +printf("Instanciation sur une GUB NbVarGauche %d NbVarDroite %d ValeurDInstanciation %d\n", + Pne->NbVarGauche,Pne->NbVarDroite,Pne->ValeurDInstanciationPourLaGub[GubChoisie]); +*/ +if ( Pne->NbVarGauche <= 0 || Pne->NbVarDroite <= 0 ) { + /* + printf("Bug dans PNE_StrongBranchingTesterLesGUB NbVarGauche %d NbVarDroite %d\n",Pne->NbVarGauche,Pne->NbVarDroite); + */ +} + +free( Suiv ); + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PNE_StrongBranchingGraphedeConflit( PROBLEME_PNE * Pne, int Var, double ValeurDeVar ) +{ +double * Xmin; double * Xmax; int Edge; int Noeud; int Complement; int Nv; int Pivot; +int * First; int * Adjacent; int * Next; + +return; + +if ( Pne->ConflictGraph == NULL ) return; + +printf("Application du conflict graph variable %d: %e\n",Var,ValeurDeVar); + +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; + +Pivot = Pne->ConflictGraph->Pivot; +First = Pne->ConflictGraph->First; +Adjacent = Pne->ConflictGraph->Adjacent; +Next = Pne->ConflictGraph->Next; + +if ( ValeurDeVar == 1.0 ) { Noeud = Var; Complement = Pivot + Var; } +else { Noeud = Pivot + Var; Complement = Var; } + +printf("Pivot %d Noeud %d Complement %d\n",Pivot,Noeud,Complement); + +Edge = First[Noeud]; +while ( Edge >= 0 ) { + Nv = Adjacent[Edge]; + /* Attention a ne pas prendre le complement */ + if ( Nv == Complement ) goto NextEdge; + if ( Nv < Pivot ) { + Var = Nv; + /* On ne doit pas avoir X[Var] = 1.0 */ + if ( Xmin[Var] > 0.0001 ) { + printf("Instanciation infaisable\n"); + return; + } + if ( Xmin[Var] == Xmax[Var] ) goto NextEdge; + ValeurDeVar = 0.0; + printf("Variable %d fixee a %e\n",Var,ValeurDeVar); + fflush( stdout ); + PNE_StrongBranchingGraphedeConflit( Pne, Var, ValeurDeVar ); + } + else { + /* La valeur borne inf est interdite pour la variable */ + /* On doit donc fixer la variable a Umax et fixer les voisins de ce noeud */ + Var = Nv - Pivot; + /* On ne doit pas avoir X[Var] = 0.0 */ + if ( Xmax[Var] < 0.9999 ) { + printf("Instanciation infaisable\n"); + return; + } + if ( Xmin[Var] == Xmax[Var] ) goto NextEdge; + ValeurDeVar = 1.0; + printf("Variable %d fixee a %e\n",Var,ValeurDeVar); + fflush( stdout ); + PNE_StrongBranchingGraphedeConflit( Pne, Var, ValeurDeVar ); + } + NextEdge: + Edge = Next[Edge]; +} + +return; +} diff --git a/src/ext/Sirius_Solver/pne/pne_strong_branching_classer_le_resultat.c b/src/ext/Sirius_Solver/pne/pne_strong_branching_classer_le_resultat.c new file mode 100644 index 0000000000..5f501f2b3c --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_strong_branching_classer_le_resultat.c @@ -0,0 +1,244 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Strong branching pour le choix de la variable a instancier. + Appelé par le branch and bound, ce sous-programme retourne + le numéro de la variable a instancier et la base de depart + qu'il faudra utiliser lorsque l'on évaluera le noeud dans + une étape ultérieure. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# define SEUIL_ACCEPTATION_NOUVEAU_CRITERE 1.e-3 /*1.e-6*/ /*1.e-7*/ +/*----------------------------------------------------------------------------*/ + +void PNE_StrongBranchingClasserLeResultat( PROBLEME_PNE * Pne, + char ChoixDuTypeDeVariation, + char ExistenceSolutionAGauche, + char ExistenceSolutionADroite, + double CritereAGauche, + double DeltaXAGauche, + double CritereADroite, + double DeltaXADroite, + double CritereInfini, + double Marge, + double * SupDeNouveauCritere, + double * SupEcartDInstanciation, + int VariableInstanciee, + char * ChoixDefinitif, + char * ChoixAmeliorant, + double SeuilNouveauCout, + /* Choix de l'instanciation */ + double * MinorantEspereAGauche, + double * MinorantEspereADroite, + /* Base correspondante pour l'instanciation a gauche */ + int * PositionDeLaVariableAGauche , + int * NbVarDeBaseComplementairesAGauche, + int * ComplementDeLaBaseAGauche , + int * PosVarAGauche , + int NbVarComplAGauche, + int * ComplBaseAGauche , + char * PositionDeLaVariableDEcartAGauche, + /* Base correspondante pour l'instanciation a droite */ + int * PositionDeLaVariableADroite , + int * NbVarDeBaseComplementairesADroite, + int * ComplementDeLaBaseADroite , + int * PosVarADroite , + int NbVarComplADroite, + int * ComplBaseADroite , + char * PositionDeLaVariableDEcartADroite, + /* Indicateur de disponibilite des bases a gauche et droite */ + int * BasesFilsDisponibles + ) +{ +double NouveauCritere; double Seuil; double DeltaFSurDeltaXG; double DeltaFSurDeltaXD; +double X; char OnPrend; int i; int * NbTerm; + +if ( CritereAGauche < Pne->Critere ) CritereAGauche = Pne->Critere; +if ( CritereADroite < Pne->Critere ) CritereADroite = Pne->Critere; + +*ChoixDefinitif = NON_PNE; +*ChoixAmeliorant = NON_PNE; +OnPrend = NON_PNE; + +if ( ChoixDuTypeDeVariation == VALEUR_ABSOLUE_DE_LA_VARIATION ) { + /* NouveauCritere est la valeur qui va servir pour le test de selection */ + NouveauCritere = Pne->Critere; + if ( ExistenceSolutionAGauche == OUI_PNE && ExistenceSolutionADroite == OUI_PNE ) { + NouveauCritere = ( CritereAGauche + CritereADroite ) * 0.5; + } + + if ( ExistenceSolutionAGauche == NON_PNE ) NouveauCritere = CritereInfini; + if ( ExistenceSolutionADroite == NON_PNE ) NouveauCritere = 2. * CritereInfini; + + if ( ExistenceSolutionAGauche == NON_PNE && ExistenceSolutionADroite == NON_PNE ) { + /* Pour que la variable soit choisie a coup sur */ + NouveauCritere = 10. * CritereInfini; + } + + Seuil = *SupDeNouveauCritere; + + /* Pour pourvoir tester toutes les instanciations mais conserver le fait qu'on a interet a choisir une + variable qui n'a pas de solution ni a droite ni a gauche ainsi on pourra fermer l'arborescence */ + SeuilNouveauCout = /*2*/ 0.99 * CritereInfini; + + if ( NouveauCritere > SeuilNouveauCout ) { + OnPrend = OUI_PNE; + } + else if ( NouveauCritere > Seuil && fabs( CritereAGauche - CritereADroite ) > SEUIL_ACCEPTATION_NOUVEAU_CRITERE ) { + OnPrend = OUI_PNE; + if ( fabs( NouveauCritere - Pne->Critere ) < SEUIL_ACCEPTATION_NOUVEAU_CRITERE ) { + if ( fabs( CritereAGauche - CritereADroite ) < *SupEcartDInstanciation) { + OnPrend = NON_PNE; + } + } + } + goto TestDesVariation; +} + +if ( ChoixDuTypeDeVariation == PENTE_DE_LA_VARIATION ) { + /* NouveauCritere est le min des pentes de variation */ + DeltaFSurDeltaXG = 0.0; + if ( ExistenceSolutionAGauche == OUI_PNE ) { + X = CritereAGauche - Pne->Critere; + + /* Neutralisation des trop petites variations */ + if ( X < 1.e-6 ) X = 0.0; + + if ( X > 0.0 ) { + DeltaFSurDeltaXG = X / DeltaXAGauche; + } + } + DeltaFSurDeltaXD = 0.0; + if ( ExistenceSolutionADroite == OUI_PNE ) { + X = CritereADroite - Pne->Critere; + + /* Neutralisation des trop petites variations */ + if ( X < 1.e-6 ) X = 0.0; + + if ( X > 0.0 ) { + DeltaFSurDeltaXD = X / DeltaXADroite; + } + } + + if ( ExistenceSolutionAGauche == NON_PNE ) DeltaFSurDeltaXG = CritereInfini; + if ( ExistenceSolutionADroite == NON_PNE ) DeltaFSurDeltaXD = CritereInfini; + + NouveauCritere = DeltaFSurDeltaXG; + if ( NouveauCritere > DeltaFSurDeltaXD ) NouveauCritere = DeltaFSurDeltaXD; + + if ( ExistenceSolutionAGauche == NON_PNE && ExistenceSolutionADroite == NON_PNE ) { + /* Pour que la variable soit choisie a coup sur */ + NouveauCritere = 10. * CritereInfini; + } + + Seuil = *SupDeNouveauCritere; + + /* Pour pourvoir tester toutes les instanciations mais conserver le fait qu'on a interet a choisir une + variable qui n'a pas de solution ni a droite ni a gauche ainsi on pourra fermer l'arborescence */ + SeuilNouveauCout = /*2*/ 0.99 * CritereInfini; + + if ( NouveauCritere > SeuilNouveauCout ) { + OnPrend = OUI_PNE; + } + else if ( NouveauCritere > Seuil && fabs( CritereAGauche - CritereADroite ) > SEUIL_ACCEPTATION_NOUVEAU_CRITERE ) { + OnPrend = OUI_PNE; + if ( fabs( NouveauCritere ) < SEUIL_ACCEPTATION_NOUVEAU_CRITERE ) { + if ( fabs( CritereAGauche - CritereADroite ) < *SupEcartDInstanciation) { + OnPrend = NON_PNE; + } + } + } + + /* 12/2014 si les 2 criteres sont vraiment trop proches on ne prend pas de toutes facons */ + if ( fabs( CritereAGauche - CritereADroite ) < SEUIL_ACCEPTATION_NOUVEAU_CRITERE ) { + /*if ( OnPrend == OUI_PNE ) printf("Refus car critere a gauche et a droite identiques\n");*/ + OnPrend = NON_PNE; + } + + goto TestDesVariation; +} + +TestDesVariation: + +if ( OnPrend == OUI_PNE ) { + + *SupDeNouveauCritere = NouveauCritere; + *SupEcartDInstanciation = fabs( CritereAGauche - CritereADroite ); + *ChoixAmeliorant = OUI_PNE; + + if ( VariableInstanciee >= 0 ) { + /* Sinon c'est une Gub */ + Pne->VariableLaPlusFractionnaire = VariableInstanciee; + } + /* On s'arrete sur DeltaCoutNonNul que si les 2 couts sont valides ou invalides a la fois */ + if ( NouveauCritere > SeuilNouveauCout ) { + *ChoixDefinitif = OUI_PNE; + } + + X = 0.001 * fabs( NouveauCritere ); + /* On borne la valeur de X */ + + if ( X > 10 ) X = 10; + else if ( X < 1.e-6 ) X = 1.e-6; + + *SupDeNouveauCritere += X; + + *MinorantEspereAGauche = CritereAGauche - Marge; + *MinorantEspereADroite = CritereADroite - Marge; + *BasesFilsDisponibles = OUI_PNE; + *NbVarDeBaseComplementairesAGauche = NbVarComplAGauche; + *NbVarDeBaseComplementairesADroite = NbVarComplADroite; + memcpy( (char *) PositionDeLaVariableAGauche , (char *) PosVarAGauche , Pne->NombreDeVariablesTrav * sizeof( int ) ); + memcpy( (char *) ComplementDeLaBaseAGauche , (char *) ComplBaseAGauche , NbVarComplAGauche * sizeof( int ) ); + memcpy( (char *) PositionDeLaVariableADroite , (char *) PosVarADroite , Pne->NombreDeVariablesTrav * sizeof( int ) ); + memcpy( (char *) ComplementDeLaBaseADroite , (char *) ComplBaseADroite , NbVarComplADroite * sizeof( int ) ); + + /* Pour ne pas avoir de fausses alertes avec les outils de debogage au sujet des zones non intitialisees on + fait une init a EN_BASE_LIBRE (en effet, il arrive que l'on inihibe des coupes et dans ce cas le simplexe + ne donne pas de position pour la variable d'ecart de ces coupes */ + NbTerm = Pne->Coupes.NbTerm; + for ( i = 0 ; i < Pne->Coupes.NombreDeContraintes ; i++ ) { + if ( NbTerm[i] == 0 ) { + PositionDeLaVariableDEcartAGauche[i] = EN_BASE_LIBRE; + PositionDeLaVariableDEcartADroite[i] = EN_BASE_LIBRE; + } + } + + memcpy( (char *) Pne->Coupes.PositionDeLaVariableDEcartAGauche, + (char *) PositionDeLaVariableDEcartAGauche, Pne->Coupes.NombreDeContraintes * sizeof( char ) ); + memcpy( (char *) Pne->Coupes.PositionDeLaVariableDEcartADroite, + (char *) PositionDeLaVariableDEcartADroite, Pne->Coupes.NombreDeContraintes * sizeof( char ) ); + +} + +return; +} + + + diff --git a/src/ext/Sirius_Solver/pne/pne_sys.h b/src/ext/Sirius_Solver/pne/pne_sys.h new file mode 100644 index 0000000000..867011d061 --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_sys.h @@ -0,0 +1,36 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef PNE_SYS_DEJA_DEFINI +/*******************************************************************************************/ + +# include +# include +# include +# include +# include +/* # include */ +# include +# include +# include +# include + +/*******************************************************************************************/ +# define PNE_SYS_DEJA_DEFINI +# endif + + + diff --git a/src/ext/Sirius_Solver/pne/pne_trier_les_coupes_calculees.c b/src/ext/Sirius_Solver/pne/pne_trier_les_coupes_calculees.c new file mode 100644 index 0000000000..d45e3ce4df --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_trier_les_coupes_calculees.c @@ -0,0 +1,376 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul des coupes + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ +/* Tri des coupes: apres la reoptimisation, on examine la position des la + variable d'ecart. Si elle est basique alors la coupe n'est pas saturee: + dans ce cas on ne la conserve pas */ + +void PNE_TrierLesCoupesCalculees( PROBLEME_PNE * Pne, + int YaUneSolution, + int BasesFilsDisponibles, + char ProblemeReoptimiseSurLesCoupes, + char * CoupeSaturee, + char * CoupeSatureeAGauche, + char * CoupeSatureeADroite + ) +{ +int i; int j ; int jMax; int IndiceDeCoupe; int * ConserverLaContrainte; int IndexCnt; +int NbCoupesConservees; char ArchiverToutesLesCoupes; + +int NombreDeTermes; double * Coefficient_CG; int * IndiceDeLaVariable_CG; double SecondMembre; +COUPE_CALCULEE ** Coupe; char Type; BB * Bb; + +if ( YaUneSolution == NON ) goto FinDuTri; + +Pne->NbGDuCycle = 0; +Pne->NbIDuCycle = 0; +Pne->NbKDuCycle = 0; +Pne->NbGInsere = 0; +Pne->NbIInsere = 0; +Pne->NbKInsere = 0; + +Bb = (BB *) Pne->ProblemeBbDuSolveur; + +ArchiverToutesLesCoupes = BB_ArchiverToutesLesCoupesLorsDuTri( Bb ); + +/* Si on ne reoptimise pas le noeud on ne peut pas se contenter d'archiver que les coupes + saturees car on ne les connait pas */ +if ( ProblemeReoptimiseSurLesCoupes == NON_PNE ) ArchiverToutesLesCoupes = OUI_PNE; + +ConserverLaContrainte = (int *) malloc( Pne->Coupes.NombreDeContraintes * sizeof( int ) ); +if ( ConserverLaContrainte == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_TrierLesCoupesCalculees \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} + +for ( j = 0 ; j < Pne->Coupes.NombreDeContraintes ; j++ ) { + ConserverLaContrainte[j] = 3; +} + +/* Pour le nettoyage des coupes preexistantes */ +/* Si on n'archive pas toutes les coupes, on conserve celles qui sont saturees au noeud resolu + ainsi que celles qui sont saturees en au moins 1 des 2 noeuds fils du strong branching */ +jMax = Pne->Coupes.NombreDeContraintes - Pne->NombreDeCoupesCalculees; + +for ( j = 0 ; j < jMax ; j++ ) { + CoupeSaturee [j] = OUI_PNE; + CoupeSatureeAGauche[j] = OUI_PNE; + CoupeSatureeADroite[j] = OUI_PNE; +} + +if ( BasesFilsDisponibles == NON_PNE ) { + /* Noeud resolu */ + for ( j = 0 ; j < Pne->Coupes.NombreDeContraintes ; j++ ) { + if ( Pne->Coupes.PositionDeLaVariableDEcart[j] == EN_BASE ) { + /* La contrainte n'est pas saturee, on ne la conserve pas */ + if ( ArchiverToutesLesCoupes == NON_PNE ) ConserverLaContrainte[j] = 0; + if ( j < jMax ) CoupeSaturee[j] = NON_PNE; + } + } +} +else { + /* Noeud resolu */ + for ( j = 0 ; j < Pne->Coupes.NombreDeContraintes ; j++ ) { + if ( Pne->Coupes.PositionDeLaVariableDEcart[j] == EN_BASE ) { + /* La contrainte n'est pas saturee, on ne la conserve pas */ + if ( ArchiverToutesLesCoupes == NON_PNE ) ConserverLaContrainte[j]-=1; + } + } + /* Noeud fils Gauche */ + for ( j = 0 ; j < Pne->Coupes.NombreDeContraintes ; j++ ) { + if ( Pne->Coupes.PositionDeLaVariableDEcartAGauche[j] == EN_BASE ) { + /* La contrainte n'est pas saturee, on ne la conserve pas */ + if ( ArchiverToutesLesCoupes == NON_PNE ) ConserverLaContrainte[j]-= 1; + if ( j < jMax ) CoupeSatureeAGauche[j] = NON_PNE; + } + } + /* Noeud fils Droit */ + for ( j = 0 ; j < Pne->Coupes.NombreDeContraintes ; j++ ) { + if ( Pne->Coupes.PositionDeLaVariableDEcartADroite[j] == EN_BASE ) { + /* La contrainte n'est pas saturee, on ne la conserve pas */ + if ( ArchiverToutesLesCoupes == NON_PNE ) ConserverLaContrainte[j]-= 1; + if ( j < jMax ) CoupeSatureeADroite[j] = NON_PNE; + } + } +} + +for ( j = 0 ; j < Pne->Coupes.NombreDeContraintes ; j++ ) { + if ( Pne->Coupes.NbTerm[j] <= 0 ) { + ConserverLaContrainte[j] = 0; + Pne->Coupes.PositionDeLaVariableDEcart[j] = EN_BASE; + Pne->Coupes.PositionDeLaVariableDEcartAGauche[j] = EN_BASE; + Pne->Coupes.PositionDeLaVariableDEcartADroite[j] = EN_BASE; + /* Pour les coupes qui proviennent des noeuds peres: si on a mis NbTerm = 0, il faut que la + coupe soit non saturee a gauche et a droite sinon cela entraine une confusion dans la + constitution des bases de depart des noeuds suivants */ + if ( j < jMax ) { + CoupeSaturee[j] = NON_PNE; + CoupeSatureeAGauche[j] = NON_PNE; + CoupeSatureeADroite[j] = NON_PNE; + } + } +} + +/* Maintenant on procede au stockage des coupes au noeud */ + +IndexCnt = jMax - 1; +NbCoupesConservees = 0; +if ( Pne->ResolutionDuNoeudReussie == OUI_PNE ) { + for ( IndiceDeCoupe = 0 ; IndiceDeCoupe < Pne->NombreDeCoupesCalculees ; IndiceDeCoupe++ ) { + + Type = Pne->CoupesCalculees[IndiceDeCoupe]->Type; + NombreDeTermes = Pne->CoupesCalculees[IndiceDeCoupe]->NombreDeTermes; + Coefficient_CG = Pne->CoupesCalculees[IndiceDeCoupe]->Coefficient; + IndiceDeLaVariable_CG = Pne->CoupesCalculees[IndiceDeCoupe]->IndiceDeLaVariable; + SecondMembre = Pne->CoupesCalculees[IndiceDeCoupe]->SecondMembre; + + if ( Type == 'G' ) Pne->NbGDuCycle++; + else if ( Type == 'K' ) Pne->NbKDuCycle++; + else if ( Type == 'I' ) Pne->NbIDuCycle++; + + j = Pne->CoupesCalculees[IndiceDeCoupe]->NumeroDeLaContrainte; + + if ( Pne->Coupes.NbTerm[j] > 0 ) IndexCnt++; + + if ( ConserverLaContrainte[j] == 0 ) { + /* S'il ne s'agit pas d'une coupe negligee qu'on a essaye de remettre dans le cicrcuit, on la stocke + dans les coupes negligees */ + /* + if ( Type == 'K' ) { + if ( Pne->CoupesKNegligees != NULL ) { + if ( Pne->CoupesCalculees[IndiceDeCoupe]->IndexDansKNegligees < 0 ) PNE_CreerUneCoupeKNegligee( Pne, j ); + } + } + else if ( Type == 'G' ) { + if ( Pne->CoupesGNegligees != NULL ) { + if ( Pne->CoupesCalculees[IndiceDeCoupe]->IndexDansGNegligees < 0 ) PNE_CreerUneCoupeGNegligee( Pne, j ); + } + } + */ + continue; + } + + if ( Type == 'G' ) Pne->NbGInsere++; + else if ( Type == 'K' ) Pne->NbKInsere++; + else if ( Type == 'I' ) Pne->NbIInsere++; + + # if UTILISER_LE_GRAPHE_DE_CONFLITS == OUI_PNE + if ( Pne->Cliques != NULL ) { + i = Pne->CoupesCalculees[IndiceDeCoupe]->IndexDansCliques; + if ( i >= 0 && i < Pne->Cliques->NombreDeCliques ) Pne->Cliques->LaCliqueEstDansLePool[i] = OUI_PNE; + } + if ( Pne->CoupesDeProbing != NULL ) { + i = Pne->CoupesCalculees[IndiceDeCoupe]->IndexDansCoupesDeProbing; + if ( i >= 0 && i < Pne->CoupesDeProbing->NombreDeCoupesDeProbing ) Pne->CoupesDeProbing->LaCoupDeProbingEstDansLePool[i] = OUI_PNE; + } + + # if CONSTRUIRE_BORNES_VARIABLES == OUI_PNE + if ( Pne->ContraintesDeBorneVariable != NULL ) { + i = Pne->CoupesCalculees[IndiceDeCoupe]->IndexDansContraintesDeBorneVariable; + if ( i >= 0 && i < Pne->ContraintesDeBorneVariable->NombreDeContraintesDeBorne ) Pne->ContraintesDeBorneVariable->LaContrainteDeBorneVariableEstDansLePool[i] = OUI_PNE; + } + # endif + + # endif + + if ( Pne->CoupesKNegligees != NULL ) { + i = Pne->CoupesCalculees[IndiceDeCoupe]->IndexDansKNegligees; + if ( i >= 0 && i < Pne->CoupesKNegligees->NombreDeCoupes ) Pne->CoupesKNegligees->LaCoupeEstDansLePool[i] = OUI_PNE; + } + if ( Pne->CoupesGNegligees != NULL ) { + i = Pne->CoupesCalculees[IndiceDeCoupe]->IndexDansGNegligees; + if ( i >= 0 && i < Pne->CoupesGNegligees->NombreDeCoupes ) Pne->CoupesGNegligees->LaCoupeEstDansLePool[i] = OUI_PNE; + } + + BB_StockerUneCoupeGenereeAuNoeud( Bb, + NombreDeTermes, + Coefficient_CG, + IndiceDeLaVariable_CG, + SecondMembre, + Type ); + + if ( BasesFilsDisponibles == NON_PNE ) { + CoupeSaturee[jMax + NbCoupesConservees] = OUI_PNE; + if ( Pne->Coupes.PositionDeLaVariableDEcart[j] == EN_BASE ) CoupeSaturee[jMax + NbCoupesConservees] = NON_PNE; + + if ( ArchiverToutesLesCoupes == OUI_PNE ) { + if ( ProblemeReoptimiseSurLesCoupes == NON_PNE ) CoupeSaturee[jMax + NbCoupesConservees] = -1; + else if ( Pne->Coupes.PositionDeLaVariableDEcart[j] == EN_BASE ) CoupeSaturee[jMax + NbCoupesConservees] = -1; + } + + } + else { + CoupeSatureeAGauche[jMax + NbCoupesConservees] = OUI_PNE; + if ( Pne->Coupes.PositionDeLaVariableDEcartAGauche[j] == EN_BASE ) CoupeSatureeAGauche[jMax + NbCoupesConservees] = NON_PNE; + + if ( ArchiverToutesLesCoupes == OUI_PNE ) { + if ( ProblemeReoptimiseSurLesCoupes == NON_PNE ) CoupeSatureeAGauche[jMax + NbCoupesConservees] = -1; + else if ( Pne->Coupes.PositionDeLaVariableDEcartAGauche[j] == EN_BASE ) CoupeSatureeAGauche[jMax + NbCoupesConservees] = -1; + } + + CoupeSatureeADroite[jMax + NbCoupesConservees] = OUI_PNE; + if ( Pne->Coupes.PositionDeLaVariableDEcartADroite[j] == EN_BASE ) CoupeSatureeADroite[jMax + NbCoupesConservees] = NON_PNE; + + if ( ArchiverToutesLesCoupes == OUI_PNE ) { + if ( ProblemeReoptimiseSurLesCoupes == NON_PNE ) CoupeSatureeADroite[jMax + NbCoupesConservees] = -1; + else if ( Pne->Coupes.PositionDeLaVariableDEcartADroite[j] == EN_BASE ) CoupeSatureeADroite[jMax + NbCoupesConservees] = -1; + } + + } + + NbCoupesConservees++; + } +} + +#if VERBOSE_PNE + printf("-> Nombre de coupes calculees %d Nombre de coupes conservees %d\n",Pne->NombreDeCoupesCalculees,NbCoupesConservees); +#endif + +if ( Bb->AffichageDesTraces == OUI && VERBOSE_PNE == 1 ) { + if ( Pne->NbGDuCycle != 0 || Pne->NbIDuCycle != 0 || Pne->NbKDuCycle != 0 ) { + printf("Generating new cuts (family cut: computed/kept) "); + if ( Pne->NbGDuCycle != 0 ) { + printf("G: %3d/%3d ",Pne->NbGDuCycle,Pne->NbGInsere); + } + if ( Pne->NbIDuCycle != 0 ) { + printf("I: %3d/%3d ",Pne->NbIDuCycle,Pne->NbIInsere); + } + if ( Pne->NbKDuCycle != 0 ) { + printf("K: %3d/%3d ",Pne->NbKDuCycle,Pne->NbKInsere); + } + printf("\n"); + /* Pour forcer le reaffichage de la legende */ + Bb->NombreDAffichages = CYCLE_DAFFICHAGE_LEGENDE; + } +} + +free( ConserverLaContrainte ); + +FinDuTri: +/* Liberation de la structure COUPE_CALCULEE */ +if( Pne->NombreDeCoupesCalculees > 0 ) { + Coupe = Pne->CoupesCalculees; /* Pointeur sur le tableau de pointeurs sur les coupes */ + for ( i = 0 ; i < Pne->NombreDeCoupesCalculees ; i++ ) { + free( Coupe[i]->Coefficient ); + free( Coupe[i]->IndiceDeLaVariable ); + free( Coupe[i] ); + } + free( Pne->CoupesCalculees ); + Pne->NombreDeCoupesCalculees = 0; +} + +/*Pne->Coupes.NombreDeContraintes = 0;*/ /* Remis a 0 dans PNE_RecupererLeProblemeInitial */ + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Routine appelee par la partie branch and bound. Elle inhibe, au sens de + la partie PNE les coupes non saturees afin que lors d'une nouvelle evaluation + on ne mette pas trop de temps de calcul inutilement. Pour inhiber, on + met a 0 le nombre de termes de la coupe. + Attention cela n'est prevu que pour fonctionner au noeud racine car il + n'y a que la qu'on un grand nombre de round de coupes. */ + +void PNE_ActualiserLesCoupesAPrendreEnCompte( PROBLEME_PNE * Pne ) +{ +int j; int jMax; int NbSat; int Seuil; int NbConserve; + +jMax = Pne->Coupes.NombreDeContraintes - Pne->NombreDeCoupesCalculeesNonEvaluees; + +/* En dessous de x% de coupes, on ne fait rien */ +if ( jMax < 0.02 * Pne->NombreDeContraintesTrav || jMax <= 10 /*100*/ ) { + return; +} + +NbSat = 0; +Seuil = (int) ceil( 0.5 * jMax ); + +if ( Seuil <= 10 ) Seuil = 10; +for ( j = 0 ; j < jMax ; j++ ) { + if ( Pne->Coupes.NbTerm[j] <= 0 ) continue; + if ( Pne->Coupes.PositionDeLaVariableDEcart[j] != EN_BASE ) { + /* Contrainte saturee */ + NbSat++; + } +} +NbConserve = NbSat; + +/* On ne conserve que les coupes saturees */ +/* Il n'est pas judicieux de conserver des coupes non saturees car on risque de s'en servir pour calculer + des gomory supplementaires */ +if ( NbSat > Seuil ) { + /* Il y a deja beaucoup de contraintes saturee => on enleve les non saturee */ + for ( j = 0 ; j < jMax ; j++ ) { + if ( Pne->Coupes.NbTerm[j] <= 0 ) continue; + /* Si la contrainte n'est pas saturee, on ne la conserve pas */ + if ( Pne->Coupes.PositionDeLaVariableDEcart[j] != EN_BASE ) continue; + Pne->Coupes.NbTerm[j] = 0; + + /* Les coupes qui ont ete mises ici ne sont jamais des coupes negligees qu'on a essaye de remettre dans le circuit */ + if ( Pne->Coupes.TypeDeCoupe[j] == 'K' ) PNE_CreerUneCoupeKNegligee( Pne, j ); + else if ( Pne->Coupes.TypeDeCoupe[j] == 'G' ) PNE_CreerUneCoupeGNegligee( Pne, j ); + + } +} +else { + /* Il n'y a pas beaucoup de contraintes saturee => on conserve les contraintes + jusqu'a la valeur Seuil */ + for ( j = 0 ; j < jMax ; j++ ) { + if ( Pne->Coupes.NbTerm[j] <= 0 ) continue; + if ( Pne->Coupes.PositionDeLaVariableDEcart[j] != EN_BASE ) continue; + /* La contrainte n'est pas saturee */ + if ( NbConserve > Seuil ) { + /* On ne la conserve pas */ + Pne->Coupes.NbTerm[j] = 0; + + /* Les coupes qui ont ete mises ici ne sont jamais des coupes negligees qu'on a essaye de remettre dans le circuit */ + if ( Pne->Coupes.TypeDeCoupe[j] == 'K' ) PNE_CreerUneCoupeKNegligee( Pne, j ); + else if ( Pne->Coupes.TypeDeCoupe[j] == 'G' ) PNE_CreerUneCoupeGNegligee( Pne, j ); + + } + else NbConserve++; + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/pne/pne_two_step_mir.c b/src/ext/Sirius_Solver/pne/pne_two_step_mir.c new file mode 100644 index 0000000000..3c7c5f6b1d --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_two_step_mir.c @@ -0,0 +1,817 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Two step MIR tire de l'article paru dans INFORMS journal of + computing: Two Step MIR inegualities for mixed integer + programs de Dash Goycoolea Gunluk . + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "bb_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +# define PAS_DE_SUBSTITUTION 0 +# define SUBSTITUTION_BORNE_INF 1 +# define SUBSTITUTION_BORNE_SUP 2 + +# define VIOLATION_MIN 1.e-4 +# define F_NUL 1.e-7 +# define ALPHA_MIN 5.e-4 +# define RHO_NUL 1.e-5 +# define ZERO_COEFF 1.e-12 + + +# ifdef CMP2STEP + +char PNE_TwoMirCalulerAlphaEtTau( double , double , double * , double * ); + +void PNE_RechercheTwoStepMir( PROBLEME_PNE * , double , int , double * , double , double * , int * , char * , + double * , int , int * , char * , double * , double * , double * , int * , char * , char ); + +/*----------------------------------------------------------------------------*/ +/* On cherche Alpha = Fi / k ou Fi = partie fractionnaire du coefficent ai + On note FO la partie fractionnaire du second membre: + on choisi k parmi les entiers qui verifient F0 / (Fi/k) <= 20 + De plus le choix de t doit conduite a un Alpha admissible c'est a dire + etre tel que t = ceil( F0/Alpha ) et 1/Alpha >= t +*/ +char PNE_TwoMirCalulerAlphaEtTau( double F0, double Fi, double * TauChoisi, double * AlphaChoisi ) +{ +int kmax; int CodeRet; double Alpha; int k; double Rho; double Tau; +/* Doit satisfaire la contion F0 / (Fi/k) <= 20 i.e. k <= 20 Fi/F0 */ +kmax = ceil( 20 * (Fi/F0) ); /* Pour tomber su un entier */ +CodeRet = 0; +for ( k = 1 ; k <= kmax ; k++ ) { + Alpha = Fi / (double) k; + if ( Alpha < ALPHA_MIN ) break; + if ( F0 > Alpha + F_NUL ) { + Tau = (int) ceil( F0/Alpha ); + if ( Tau >= 2 ) { + if ( 1/Alpha >= Tau ) { + if ( Tau > (F0/Alpha) + F_NUL ) { + Rho = F0 - ( Alpha * floor( F0/Alpha ) ); + if ( Rho > RHO_NUL ) { + /* t donne un Alpha admissible => on arrete les calculs */ + *AlphaChoisi = Alpha; + *TauChoisi = Tau; + CodeRet = 1; + /* + printf("AlphaChoisi %e TauChoisi %e \n",*AlphaChoisi,*TauChoisi); + */ + break; + } + } + } + } + } +} +return( CodeRet ); +} +/*----------------------------------------------------------------------------*/ +/* On teste la violation de la MIR */ + +void PNE_RechercheTwoStepMir( PROBLEME_PNE * Pne, double ValDeVarContinue, int NbVarEntieres, + double * CoeffDeLaVariableEntiere, double SecondMembre, + double * ValeurDeLaVariableEntiere, + int * NumeroDeLaVariableEntiere, + char * TypeDeSubstitutionEntiere, + double * BorneDeSubstitutionEntiere, + int NbVarContinues, + int * NumeroDeLaVariableContinue, + char * TypeDeSubstitutionContinue, + double * BorneDeSubstitutionContinue, + double * CoefficientDeLaVariableContinue, + double * Coeff, + int * Indice, + char * T, + char NormaliserLaCoupe ) +{ +double F0; int j; double Fj; double Fi; double Tau; double Alpha; double RhoFoisTau; int NbT; +int CodeRet; double Rho; double MembreDeGauche; double Sec; double Terme_2; double X; +double Terme_3; double gAlpha; double Coeffi; int i; int Var; double PlusGrandCoeff; +int NbMaxTests; int Step; int NombreDeVariables; double * B; int VarSpx; int il; int ilMax; +int Var2Spx; int Cnt; +PROBLEME_SPX * Spx; + +F0 = SecondMembre - floor( SecondMembre ); +if ( F0 < F_NUL ) { + return; +} + +Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur; +if ( Spx == NULL ) return; +B = Spx->DonneesPourCoupesDeGomory->B; /* Attention a la translation de Xminentree */ +/* +printf("Attention on est en train de mettre au point l'utilisation d'un tableau T pour les variables d'ecart du simplexe \n"); +*/ +NombreDeVariables = Pne->NombreDeVariablesTrav; +/* On teste ne teste pas plus de NbMaxTests valeurs car sinon ca consomme trop de temps */ +NbMaxTests = 10; +Step = floor( (NbVarEntieres+1) / NbMaxTests ); +if ( Step < 1 ) Step = 1; +if ( NbVarEntieres <= 5 ) Step = 1; + +for ( j = 0 ; j < NbVarEntieres ; j = j + Step ) { + Fj = CoeffDeLaVariableEntiere[j] - floor( CoeffDeLaVariableEntiere[j] ); + if ( Fj < F_NUL ) continue; + if ( Fj >= F0 ) continue; + /*if ( ValeurDeLaVariableEntiere[j] == 0.0 ) continue;*/ + CodeRet = PNE_TwoMirCalulerAlphaEtTau( F0, Fj, &Tau, &Alpha ); + if ( CodeRet == 0 ) continue; + + Rho = F0 - ( Alpha * floor( F0/Alpha ) ); + if ( Rho < RHO_NUL ) continue; + + RhoFoisTau = Rho * Tau; + Sec = RhoFoisTau * ceil( SecondMembre ); + /* Relatif a toutes les variables continues ayant un coefficient positif */ + MembreDeGauche = ValDeVarContinue; + for ( i = 0 ; i < NbVarEntieres ; i++ ) { + Fi = CoeffDeLaVariableEntiere[i] - floor( CoeffDeLaVariableEntiere[i] ); + /* Calcul de g^Alpha(Fi) */ + Terme_2 = Rho * floor( Fi/Alpha ); + Terme_2 += Fi; + Terme_2 -= Alpha * floor( Fi/Alpha ); + Terme_3 = Rho * ceil( Fi/Alpha ); + gAlpha = RhoFoisTau; + if ( Terme_2 < gAlpha ) gAlpha = Terme_2; + if ( Terme_3 < gAlpha ) gAlpha = Terme_3; + Coeffi = ( RhoFoisTau * floor( CoeffDeLaVariableEntiere[i] ) ) + gAlpha; + MembreDeGauche += Coeffi * ValeurDeLaVariableEntiere[i]; + } + if ( MembreDeGauche < Sec - VIOLATION_MIN ) { + + printf(" violation 2step %e\n",Sec-MembreDeGauche); + + /* Variables continues */ + for ( i = 0 ; i < NbVarContinues ; i++ ) { + X = CoefficientDeLaVariableContinue[i]; + Var = NumeroDeLaVariableContinue[i]; + if ( Var < 0 ) { + /* + printf("Variable d'ecart du simplexe a trazouiller\n"); + */ + VarSpx = -Var - 1; + /* Var est une variable non native */ + /* Contrainte a laquelle appartient la variable d'ecart */ + Cnt = Spx->NumeroDeContrainte[Spx->Cdeb[VarSpx]]; + /* Remplacement de la variable d'ecart */ + il = Spx->Mdeb[Cnt]; + ilMax = il + Spx->NbTerm[Cnt]; + while ( il < ilMax ) { + Var2Spx = Spx->Indcol[il]; + if ( Spx->OrigineDeLaVariable[Var2Spx] == NATIVE ) { + Var = Spx->CorrespondanceVarSimplexeVarEntree[Var2Spx]; + /* Ici il n'y a pas lieu de tenir compte du fait que la variable serait HORS_BASE_SUR_BORNE_SUP */ + if ( T[Var] == 0 ) { + Coeff[Var] = -X * Spx->A[il] * Spx->ScaleX[VarSpx] / Spx->ScaleX[Var2Spx]; + T[Var] = 1; + } + else { + Coeff[Var] -= X * Spx->A[il] * Spx->ScaleX[VarSpx] / Spx->ScaleX[Var2Spx]; + } + } + il++; + } + /* Attention a la translation de Xminentree */ + Sec -= X * B[Cnt] * Spx->ScaleX[VarSpx] * Spx->SupXmax; + continue; + } + /* Si Var est negatif on a fait la substitution U~ = Umax - U <=> U = Umax - U~ + il faut donc revenir aux variables intiales */ + if ( TypeDeSubstitutionContinue[i] == SUBSTITUTION_BORNE_SUP ) { + /* On a fait U = Umax - U~ donc U~ = Umax - U */ + Sec -= X * BorneDeSubstitutionContinue[i]; + X *= -1.; + } + else if ( TypeDeSubstitutionContinue[i] == SUBSTITUTION_BORNE_INF ) { + /* On a fait U = Umin + U~ donc U~ = U - Umin */ + Sec += X * BorneDeSubstitutionContinue[i]; + } + if ( T[Var] == 0 ) { + Coeff[Var] = X; + T[Var] = 1; + } + else { + Coeff[Var] += X; + } + } + for ( i = 0 ; i < NbVarEntieres ; i++ ) { + Fi = CoeffDeLaVariableEntiere[i] - floor( CoeffDeLaVariableEntiere[i] ); + /* Calcul de g^Alpha(Fi) */ + Terme_2 = Rho * floor( Fi/Alpha ); + Terme_2 += Fi; + Terme_2 -= Alpha * floor( Fi/Alpha ); + Terme_3 = Rho * ceil( Fi/Alpha ); + gAlpha = RhoFoisTau; + if ( Terme_2 < gAlpha ) gAlpha = Terme_2; + if ( Terme_3 < gAlpha ) gAlpha = Terme_3; + X = ( RhoFoisTau * floor( CoeffDeLaVariableEntiere[i] ) ) + gAlpha; + Var = NumeroDeLaVariableEntiere[i]; + + if ( Var < 0 || Var >= Pne->NombreDeVariablesTrav ) { + printf("Erreur Var = %d\n",Var); + exit(0); + } + + if ( TypeDeSubstitutionEntiere[i] == SUBSTITUTION_BORNE_SUP ) { + /* On a fait U = Umax - U~ donc U~ = Umax - U */ + Sec -= X * BorneDeSubstitutionEntiere[i]; + X *= -1.; + } + else if ( TypeDeSubstitutionEntiere[i] == SUBSTITUTION_BORNE_INF ) { + /* On a fait U = Umin + U~ donc U~ = U - Umin */ + Sec += X * BorneDeSubstitutionEntiere[i]; + } + if ( T[Var] == 0 ) { + Coeff[Var] = X; + T[Var] = 1; + } + else { + Coeff[Var] += X; + } + } + + /* On transforme en une contrainte de type <= en multipliant par -1 et on supprime les termes nuls */ + NbT = 0; + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( T[Var] == 1 ) { + Coeff[NbT] = -Coeff[Var]; + Indice[NbT] = Var; + NbT++; + T[Var] = 0; + } + } + Sec *= -1.0; + if ( NbT > 0 ) { + if ( NormaliserLaCoupe == OUI_PNE ) { + PlusGrandCoeff = -LINFINI_PNE; + for ( i = 0 ; i < NbT ; i++ ) { + if ( fabs( Coeff[i] ) > PlusGrandCoeff ) PlusGrandCoeff = fabs( Coeff[i] ); + } + PNE_NormaliserUnCoupe( Coeff, &Sec, NbT, PlusGrandCoeff ); + } + X = 1.e+3; /* La violation ne sert pas a grand chose */ + printf("Archivage d'une 2mir \n"); + PNE_EnrichirLeProblemeCourantAvecUneCoupe( Pne, 'G', NbT, Sec, X, Coeff , Indice ); + } + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* On recoit une contraite sur laquelle on va faire une 2 step MIR */ +void PNE_TwoStepMirSurContrainte( PROBLEME_PNE * Pne ) +{ +double Signe; double ai; int Cnt; char * ContrainteMixte; double * B; int * Mdeb; +int * NbTerm; int * Nuvar; int * TypeDeVariable; int * TypeDeBorne; int LallocTas; +double * A; double * U; double * Umin; double * Umax; double * VariableDuale; +char * SensContrainte; double ValDeVarContinue; double SecondMembre; char * T; +double * CoeffDeLaVariableEntiere; double * ValeurDeLaVariableEntiere; char * pt; +int * NumeroDeLaVariableEntiere; char * Buff; int NombreDeVariables; int NombreDeContraintes; +int NbVarEntieres; int il; int ilMax; int Var; double CoeffDiviseur; int i; double Xu; +int IndexVariableContinue; int NbVarContinues; int * NumeroDeLaVariableContinue; +double DeltaSecondMembre; double * CoeffCoupe; int * IndiceCoupe; char NormaliserLaCoupe; +double * CoefficientDeLaVariableContinue; int Nn; double X; double u; +char * TypeDeSubstitutionEntiere; char * TypeDeSubstitutionContinue; char TypeDeSubstitution; +double * BorneDeSubstitutionEntiere; double * BorneDeSubstitutionContinue; double BorneDeSubstitution; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +ContrainteMixte = Pne->ContrainteMixte; +/*if ( ContrainteMixte == NULL ) return;*/ +B = Pne->BTrav; +SensContrainte = Pne->SensContrainteTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +A = Pne->ATrav; +Nuvar = Pne->NuvarTrav; +U = Pne->UTrav; +Umin = Pne->UminTravSv; +Umax = Pne->UmaxTravSv; +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +NormaliserLaCoupe = NON_PNE; + +LallocTas = 0; +LallocTas += NombreDeVariables * sizeof( double ); /* CoeffDeLaVariableEntiere */ +LallocTas += NombreDeVariables * sizeof( double ); /* ValeurDeLaVariableEntiere */ +LallocTas += NombreDeVariables * sizeof( int ); /* NumeroDeLaVariableEntiere */ +LallocTas += NombreDeVariables * sizeof( char ); /* TypeDeSubstitutionEntiere */ +LallocTas += NombreDeVariables * sizeof( double ); /* BorneDeSubstitutionEntiere */ +LallocTas += NombreDeVariables * sizeof( double ); /* CoeffCoupe */ +LallocTas += NombreDeVariables * sizeof( int ); /* IndiceCoupe */ +LallocTas += NombreDeVariables * sizeof( char ); /* T */ + +Buff = (char *) malloc( LallocTas ); +if ( Buff == NULL ) return; + +pt = Buff; +CoeffDeLaVariableEntiere = (double *) pt; +pt += NombreDeVariables * sizeof( double ); +ValeurDeLaVariableEntiere = (double *) pt; +pt += NombreDeVariables * sizeof( double ); +NumeroDeLaVariableEntiere = (int *) pt; +pt += NombreDeVariables * sizeof( int ); +TypeDeSubstitutionEntiere = (char *) pt; +pt += NombreDeVariables * sizeof( char ); +BorneDeSubstitutionEntiere = (double *) pt; +pt += NombreDeVariables * sizeof( double ); +CoeffCoupe = (double *) pt; +pt += NombreDeVariables * sizeof( double ); +IndiceCoupe = (int *) pt; +pt += NombreDeVariables * sizeof( int ); +T = (char *) pt; +pt += NombreDeVariables * sizeof( char ); + +memset( (char *) T, 0, NombreDeVariables * sizeof( char ) ); + +VariableDuale = Pne->VariablesDualesDesContraintesTravEtDesCoupes; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + /*if ( ContrainteMixte[Cnt] == NON_PNE ) continue;*/ + /*if ( fabs( VariableDuale[Cnt] ) < SEUIL_VARIABLE_DUALE_POUR_CALCUL_DE_COUPE ) continue;*/ + /* Important: dans la papier de Dash, la contrainte de depart est du type + >= . Comme dans la PNE on n'a que des egalites et des <= , si on a une + contrainte de type <= on change le signe des coefficients et du second membre */ + if ( SensContrainte[Cnt] == '<' ) Signe = -1.0; + else Signe = 1.0; + SecondMembre = Signe * B[Cnt]; + + ValDeVarContinue = 0.0; + NbVarEntieres = 0; + Nn = 0; + + memset( (char *) TypeDeSubstitutionEntiere, PAS_DE_SUBSTITUTION, NombreDeVariables * sizeof( char ) ); + + NumeroDeLaVariableContinue = &NumeroDeLaVariableEntiere[NombreDeVariables - 1]; + CoefficientDeLaVariableContinue = &CoeffDeLaVariableEntiere[NombreDeVariables - 1]; + TypeDeSubstitutionContinue = &TypeDeSubstitutionEntiere[NombreDeVariables - 1]; + BorneDeSubstitutionContinue = &BorneDeSubstitutionEntiere[NombreDeVariables - 1]; + + IndexVariableContinue = 0; + NbVarContinues = 0; + CoeffDiviseur = 0; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( A[il] == 0.0 ) goto NextIl; + Var = Nuvar[il]; + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) { + SecondMembre -= Signe * A[il] * U[Var]; + goto NextIl; + } + if ( TypeDeVariable[Var] != ENTIER ) { + /* Variable entiere elle ne doit pas etre non bornee */ + if ( TypeDeBorne[Var] == VARIABLE_NON_BORNEE ) { + NbVarEntieres = -1; + goto FinPreparation; + } + /* Si la coefficient est > on comptabilise la variable */ + ai = Signe * A[il]; + Xu = U[Var]; + DeltaSecondMembre = 0.0; + TypeDeSubstitution = PAS_DE_SUBSTITUTION; + BorneDeSubstitution = 0.0; + if ( TypeDeBorne[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( Xu > 0.5 * Umax[Var] ) { + /* On remplace par U~ = Umax - U <=> U = Umax - U~ */ + DeltaSecondMembre = ai * Umax[Var]; + Xu = Umax[Var] - U[Var]; + ai *= -1.0; + TypeDeSubstitution = SUBSTITUTION_BORNE_SUP; + BorneDeSubstitution = Umax[Var]; + } + } + if ( ai > 0.0 ) { + ValDeVarContinue += ai * Xu; + SecondMembre -= DeltaSecondMembre; + /* On enregistre le variable */ + CoefficientDeLaVariableContinue[IndexVariableContinue] = ai; + NumeroDeLaVariableContinue[IndexVariableContinue] = Var; + TypeDeSubstitutionContinue[IndexVariableContinue] = TypeDeSubstitution; + BorneDeSubstitutionContinue[IndexVariableContinue] = BorneDeSubstitution; + IndexVariableContinue--; + NbVarContinues++; + } + goto NextIl; + } + if ( TypeDeVariable[Var] == ENTIER ) { + ai = Signe * A[il]; + Xu = U[Var]; + DeltaSecondMembre = 0.0; + TypeDeSubstitution = PAS_DE_SUBSTITUTION; + BorneDeSubstitution = 0.0; + if ( U[Var] != Umin[Var] && U[Var] != Umax[Var] ) { + CoeffDiviseur += fabs( ai ); + Nn++; + } + /* Substitution eventuelle de borne */ + if ( U[Var] > 0.5 * Umax[Var] ) { + /* On remplace par U~ = Umax - U <=> U = Umax - U~ */ + DeltaSecondMembre = ai * Umax[Var]; + Xu = Umax[Var] - U[Var]; + ai *= -1.0; + TypeDeSubstitution = SUBSTITUTION_BORNE_SUP; + BorneDeSubstitution = Umax[Var]; + } + SecondMembre -= DeltaSecondMembre; + /* On enregistre le variable */ + CoeffDeLaVariableEntiere[NbVarEntieres] = ai; + ValeurDeLaVariableEntiere[NbVarEntieres] = Xu; + NumeroDeLaVariableEntiere[NbVarEntieres] = Var; + TypeDeSubstitutionEntiere[NbVarEntieres] = TypeDeSubstitution; + BorneDeSubstitutionEntiere[NbVarEntieres] = BorneDeSubstitution; + NbVarEntieres++; + } + NextIl: + il++; + } + + FinPreparation: + if ( NbVarEntieres < 1 || CoeffDiviseur <= 0.0 ) continue; + + if ( Nn > 1 ) CoeffDiviseur /= Nn; + + /* On change CoeffDiviseur pour ne pas avoir toujours la meme valeur */ + + X = fabs( Pne->Critere / NombreDeContraintes ); + u = fabs( VariableDuale[Cnt] ); + if ( X < u ) CoeffDiviseur += 1/(1+X); + else CoeffDiviseur += 1/(1+u); + + if ( CoeffDiviseur < 1.e-2 ) CoeffDiviseur = 1.e-2; + else if ( CoeffDiviseur > 1.e+2 ) CoeffDiviseur = 1.e+2; + + /*printf("CoeffDiviseur = %e Cnt %d\n",CoeffDiviseur,Cnt);*/ + + CoefficientDeLaVariableContinue = &CoefficientDeLaVariableContinue[IndexVariableContinue+1]; + NumeroDeLaVariableContinue = &NumeroDeLaVariableContinue[IndexVariableContinue+1]; + TypeDeSubstitutionContinue = &TypeDeSubstitutionContinue[IndexVariableContinue+1]; + BorneDeSubstitutionContinue = &BorneDeSubstitutionContinue[IndexVariableContinue+1]; + + /* On divise tout par le coeff d'une variable entiere qui n'est pas sur borne */ + for ( i = 0 ; i < NbVarEntieres ; i++ ) CoeffDeLaVariableEntiere[i] /= CoeffDiviseur; + for ( i = 0 ; i < NbVarContinues ; i++ ) CoefficientDeLaVariableContinue[i] /= CoeffDiviseur; + + SecondMembre /= CoeffDiviseur; + ValDeVarContinue /= CoeffDiviseur; + + /* + printf("Tentative 2stepMIR Cnt %d ValDeVarContinue %e sens %c CoeffDiviseur %e SecondMembre %e\n", + Cnt,ValDeVarContinue,SensContrainte[Cnt],CoeffDiviseur,SecondMembre); + */ + + PNE_RechercheTwoStepMir( Pne, ValDeVarContinue, NbVarEntieres, CoeffDeLaVariableEntiere, + SecondMembre, ValeurDeLaVariableEntiere, NumeroDeLaVariableEntiere, + TypeDeSubstitutionEntiere, BorneDeSubstitutionEntiere, + NbVarContinues, NumeroDeLaVariableContinue, TypeDeSubstitutionContinue, + BorneDeSubstitutionContinue, CoefficientDeLaVariableContinue, + CoeffCoupe, IndiceCoupe, T, NormaliserLaCoupe ); + +} + +free( Buff ); + +return; +} + +/*----------------------------------------------------------------------------*/ +/* On essaie de trouver une 2 step MIR sur une ligne du tableau su simplexe */ +void PNE_TwoStepMirSurTableau( PROBLEME_PNE * Pne, int VariablePneFractionnaire, + double ValeurDuZero ) +{ +double Signe; double ai; int * TypeDeVariable; int * TypeDeBorne; +int LallocTas; double * U; char NormaliserLaCoupe; char * T; +double ValDeVarContinue; double SecondMembre; double * CoeffDeLaVariableEntiere; +double * ValeurDeLaVariableEntiere; char * pt; int * NumeroDeLaVariableEntiere; +char * Buff; /* int NombreDeVariables;*/ int NbVarEntieres; int VariableFractionnaireSpx; +double Xu; double DeltaSecondMembre; int IndexVariableContinue; int NbVarContinues; +int * NumeroDeLaVariableContinue; double AlphaI0; int VarSpx; +int VarPne; char * LaVariableSpxEstEntiere; double * CoeffCoupe; int * IndiceCoupe; +double * CoefficientDeLaVariableContinue; double * B; int NombreDeTermes; int i; +int * IndiceDeLaVariableSpx; double * CoefficientSpx; char CodeRet; +char * TypeDeSubstitutionEntiere; char * TypeDeSubstitutionContinue; char TypeDeSubstitution; +double * BorneDeSubstitutionEntiere; double * BorneDeSubstitutionContinue; double BorneDeSubstitution; +int NbVar; int Cnt; int il; int ilMax; int Var2Spx; + +DONNEES_POUR_COUPES_DE_GOMORY * DonneesPourCoupesDeGomory; +DONNEES_POUR_COUPES_DINTERSECTION * DonneesPourCoupesDIntersection; +PROBLEME_SPX * Spx; + +BB * Bb; + +Bb = (BB *) Pne->ProblemeBbDuSolveur; +/* Uniquement au noeud racine */ +if ( Bb->NoeudEnExamen != Bb->NoeudRacine ) return; + +Spx = (PROBLEME_SPX *) Pne->ProblemeSpxDuSolveur; +if ( Spx == NULL ) return; +DonneesPourCoupesDIntersection = Spx->DonneesPourCoupesDIntersection; +if ( DonneesPourCoupesDIntersection == NULL ) return; +DonneesPourCoupesDeGomory = Spx->DonneesPourCoupesDeGomory; +if ( DonneesPourCoupesDeGomory == NULL ) return; +LaVariableSpxEstEntiere = DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere; +B = DonneesPourCoupesDeGomory->B; + +/* NombreDeVariables = Pne->NombreDeVariablesTrav; */ +U = Pne->UTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; + +if ( Spx->NombreDeVariables > Pne->NombreDeVariablesTrav ) NbVar = Spx->NombreDeVariables; +else NbVar = Pne->NombreDeVariablesTrav; + + +LallocTas = 0; +LallocTas += NbVar * sizeof( double ); /* CoeffDeLaVariableEntiere */ +LallocTas += NbVar * sizeof( double ); /* ValeurDeLaVariableEntiere */ +LallocTas += NbVar * sizeof( int ); /* NumeroDeLaVariableEntiere */ +LallocTas += NbVar * sizeof( int ); /* IndiceDeLaVariableSpx */ +LallocTas += NbVar * sizeof( double ); /* CoefficientSpx */ +LallocTas += NbVar * sizeof( char ); /* TypeDeSubstitutionEntiere */ +LallocTas += NbVar * sizeof( double ); /* BorneDeSubstitutionEntiere */ +LallocTas += NbVar * sizeof( double ); /* CoeffCoupe */ +LallocTas += NbVar * sizeof( int ); /* IndiceCoupe */ +LallocTas += NbVar * sizeof( char ); /* T */ + +Buff = (char *) malloc( LallocTas ); +if ( Buff == NULL ) return; + +pt = Buff; +CoeffDeLaVariableEntiere = (double *) pt; +pt += NbVar * sizeof( double ); +ValeurDeLaVariableEntiere = (double *) pt; +pt += NbVar * sizeof( double ); +NumeroDeLaVariableEntiere = (int *) pt; +pt += NbVar * sizeof( int ); +IndiceDeLaVariableSpx = (int *) pt; +pt += NbVar * sizeof( int ); +CoefficientSpx = (double *) pt; +pt += NbVar * sizeof( double ); +TypeDeSubstitutionEntiere = (char *) pt; +pt += NbVar * sizeof( char ); +BorneDeSubstitutionEntiere = (double *) pt; +pt += NbVar * sizeof( double ); +CoeffCoupe = (double *) pt; +pt += NbVar * sizeof( double ); +IndiceCoupe = (int *) pt; +pt += NbVar * sizeof( int ); +T = (char *) pt; +pt += NbVar * sizeof( char ); + +SPX_GetTableauRow( Spx, VariablePneFractionnaire, ValeurDuZero, + /* En retour, la ligne */ + &NombreDeTermes, CoefficientSpx, IndiceDeLaVariableSpx, + &AlphaI0, &CodeRet ); +if ( CodeRet == NON_PNE ) { + printf("coderet GetTableauRow non \n"); + goto Fin2MirSurTableau; +} + +SecondMembre = AlphaI0; + +/* Important: dans la papier de Dash, la contrainte de depart est du type >= . Comme il s'agit d'une + contrainte d'egalite on pourra etudier le cas > et le cas < c'est a dire Signe = 1 et Signe = -1 */ + +/* On ajoute tout de suite la variable fractionaire avec un coefficient egal a 1 */ +VariableFractionnaireSpx = Spx->CorrespondanceVarEntreeVarSimplexe[VariablePneFractionnaire]; +CoefficientSpx[NombreDeTermes] = 1.0; +IndiceDeLaVariableSpx[NombreDeTermes] = VariableFractionnaireSpx; +NombreDeTermes++; + +Signe = 1.0; +SecondMembre = Signe * AlphaI0; +for ( i = 0 ; i < NombreDeTermes ; i++ ) CoefficientSpx[i] *= Signe; + +memset( (char *) TypeDeSubstitutionEntiere, PAS_DE_SUBSTITUTION, NbVar * sizeof( char ) ); + +ValDeVarContinue = 0.0; +NbVarEntieres = 0; + +CoefficientDeLaVariableContinue = &CoeffDeLaVariableEntiere[NbVar - 1]; +NumeroDeLaVariableContinue = &NumeroDeLaVariableEntiere[NbVar - 1]; + +TypeDeSubstitutionContinue = &TypeDeSubstitutionEntiere[NbVar - 1]; +BorneDeSubstitutionContinue = &BorneDeSubstitutionEntiere[NbVar - 1]; + +IndexVariableContinue = 0; +NbVarContinues = 0; + +memset( (double *) CoeffCoupe, 0, NbVar * sizeof( double ) ); +memset( (char *) T, 0, NbVar * sizeof( char ) ); + +goto AAA; + +for ( i = 0 ; i < NombreDeTermes ; i++ ) { + CoeffCoupe[IndiceDeLaVariableSpx[i]] = CoefficientSpx[i]; + T[IndiceDeLaVariableSpx[i]] = 1; +} + +/* Test on fait tout de suite la substitution des variables d'ecart */ +for ( i = 0 ; i < NombreDeTermes ; i++ ) { + VarSpx = IndiceDeLaVariableSpx[i]; + /* Attention aux variables d'ecart */ + if ( Spx->OrigineDeLaVariable[VarSpx] != ECART ) continue; + ai = CoefficientSpx[i]; + Cnt = Spx->NumeroDeContrainte[Spx->Cdeb[VarSpx]]; + /* Remplacement de la variable d'ecart */ + il = Spx->Mdeb[Cnt]; + ilMax = il + Spx->NbTerm[Cnt]; + while ( il < ilMax ) { + Var2Spx = Spx->Indcol[il]; + if ( Spx->OrigineDeLaVariable[Var2Spx] == NATIVE ) { + if ( T[Var2Spx] == 0 ) { + CoeffCoupe[Var2Spx] = -ai * Spx->A[il] * Spx->ScaleX[VarSpx] / Spx->ScaleX[Var2Spx]; + T[Var2Spx] = 1; + } + else { + CoeffCoupe[Var2Spx] -= ai * Spx->A[il] * Spx->ScaleX[VarSpx] / Spx->ScaleX[Var2Spx]; + } + } + il++; + } + /* Attention a la translation de Xminentree */ + SecondMembre -= ai * B[Cnt] * Spx->ScaleX[VarSpx] * Spx->SupXmax; + CoeffCoupe[VarSpx] = 0.0; + T[VarSpx] = 0; +} + +NombreDeTermes = 0; +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + if ( T[VarSpx] != 0 ) { + if ( CoeffCoupe[VarSpx] != 0.0 ) { + CoefficientSpx[NombreDeTermes] = CoeffCoupe[VarSpx]; + IndiceDeLaVariableSpx[NombreDeTermes] = VarSpx; + NombreDeTermes++; + } + T[VarSpx] = 0; + CoeffCoupe[VarSpx] = 0.0; + } +} + +AAA: +printf("NombreDeTermes %d\n",NombreDeTermes); + +for ( i = 0 ; i < NombreDeTermes ; i++ ) { + VarSpx = IndiceDeLaVariableSpx[i]; + /* Attention aux variables d'ecart */ + if ( Spx->OrigineDeLaVariable[VarSpx] == ECART ) { + /* A ce stade si la variable d'ecart n'est pas nulle il y a un pb car elle est hors base */ + if ( Spx->X[VarSpx] != 0.0 ) goto Fin2MirSurTableau; + ai = CoefficientSpx[i]; + Xu = 0.; + if ( ai > 0.0 ) { + ValDeVarContinue += ai * Xu; + /* On enregistre le variable */ + CoefficientDeLaVariableContinue[IndexVariableContinue] = ai; + /* Negatif si variable d'ecart */ + NumeroDeLaVariableContinue[IndexVariableContinue] = - VarSpx - 1; + TypeDeSubstitutionContinue[IndexVariableContinue] = PAS_DE_SUBSTITUTION; + BorneDeSubstitutionContinue[IndexVariableContinue] = 0.0; + IndexVariableContinue--; + NbVarContinues++; + } + continue; + } + + VarPne = Spx->CorrespondanceVarSimplexeVarEntree[VarSpx]; + if ( TypeDeVariable[VarPne] != ENTIER ) { + /* Variable continue elle ne doit pas etre non bornee */ + if ( TypeDeBorne[VarPne] == VARIABLE_NON_BORNEE ) { + NbVarEntieres = -1; + goto FinPreparationTableau; + } + /* Si le coefficient est > on comptabilise la variable */ + ai = CoefficientSpx[i]; + Xu = U[VarPne]; + DeltaSecondMembre = 0.0; + TypeDeSubstitution = PAS_DE_SUBSTITUTION; + BorneDeSubstitution = 0.0; + if ( TypeDeBorne[VarPne] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( Xu > 0.5 * Pne->UmaxTravSv[VarPne] ) { + if ( Pne->UminTravSv[VarPne] != 0.0 ) printf("pb Umin variable continue %e\n",Pne->UminTrav[VarPne]); + /* On remplace par U~ = Umax - U <=> U = Umax - U~ */ + DeltaSecondMembre = ai * Pne->UmaxTravSv[VarPne]; + ai *= -1.0; + Xu = Pne->UmaxTravSv[VarPne] - U[VarPne]; + TypeDeSubstitution = SUBSTITUTION_BORNE_SUP; + BorneDeSubstitution = Pne->UmaxTravSv[VarPne]; + } + } + if ( ai > 0.0 ) { + ValDeVarContinue += ai * Xu; + SecondMembre -= DeltaSecondMembre; + /* On enregistre le variable */ + CoefficientDeLaVariableContinue[IndexVariableContinue] = ai; + NumeroDeLaVariableContinue[IndexVariableContinue] = VarPne; + TypeDeSubstitutionContinue[IndexVariableContinue] = TypeDeSubstitution; + BorneDeSubstitutionContinue[IndexVariableContinue] = BorneDeSubstitution; + IndexVariableContinue--; + NbVarContinues++; + } + continue; + } + + if ( TypeDeVariable[VarPne] == ENTIER ) { + if ( Pne->UminTrav[VarPne] == Pne->UmaxTrav[VarPne] && 0 ) { + /* La variable a ete instanciee en entree */ + if ( Pne->UminTrav[VarPne] == Pne->UmaxTravSv[VarPne] ) { + /* Faire le changement de variable U = Umin + U~ et U~ >= */ + CoeffDeLaVariableEntiere[NbVarEntieres] = CoefficientSpx[i]; + SecondMembre -= CoeffDeLaVariableEntiere[NbVarEntieres] * Pne->UminTrav[VarPne]; + ValeurDeLaVariableEntiere[NbVarEntieres] = 0.0; + TypeDeSubstitutionEntiere[NbVarEntieres] = SUBSTITUTION_BORNE_INF; + BorneDeSubstitutionEntiere[NbVarEntieres] = Pne->UminTrav[VarPne]; + NumeroDeLaVariableEntiere[NbVarEntieres] = VarPne; + NbVarEntieres++; + continue; + } + } + ai = CoefficientSpx[i]; + Xu = U[VarPne]; + DeltaSecondMembre = 0.0; + TypeDeSubstitution = PAS_DE_SUBSTITUTION; + BorneDeSubstitution = 0.0; + /* Substitution eventuelle de borne */ + if ( U[VarPne] > 0.5 * Pne->UmaxTravSv[VarPne] ) { + /* On remplace par U~ = Umax - U <=> U = Umax - U~ */ + DeltaSecondMembre = ai * Pne->UmaxTravSv[VarPne]; + Xu = Pne->UmaxTravSv[VarPne] - U[VarPne]; + ai *= -1.0; + TypeDeSubstitution = SUBSTITUTION_BORNE_SUP; + BorneDeSubstitution = Pne->UmaxTravSv[VarPne]; + } + SecondMembre -= DeltaSecondMembre; + /* On enregistre le variable */ + CoeffDeLaVariableEntiere[NbVarEntieres] = ai; + ValeurDeLaVariableEntiere[NbVarEntieres] = Xu; + TypeDeSubstitutionEntiere[NbVarEntieres] = TypeDeSubstitution; + BorneDeSubstitutionEntiere[NbVarEntieres] = BorneDeSubstitution; + NumeroDeLaVariableEntiere[NbVarEntieres] = VarPne; + NbVarEntieres++; + } + +} + +FinPreparationTableau: + +/*if ( NbVarContinues != 0 ) goto Fin2MirSurTableau;*/ + +if ( NbVarEntieres < 1 ) goto Fin2MirSurTableau; + + + /* printf("NbVarContinues %d NbVarEntieres %d\n",NbVarContinues,NbVarEntieres); */ + + CoefficientDeLaVariableContinue = &CoefficientDeLaVariableContinue[IndexVariableContinue+1]; + NumeroDeLaVariableContinue = &NumeroDeLaVariableContinue[IndexVariableContinue+1]; + TypeDeSubstitutionContinue = &TypeDeSubstitutionContinue[IndexVariableContinue+1]; + BorneDeSubstitutionContinue = &BorneDeSubstitutionContinue[IndexVariableContinue+1]; + + + /*printf("Tentative 2stepMIR sur tableau ValDeVarContinue %e SecondMembre %e\n", ValDeVarContinue,SecondMembre);*/ + + NormaliserLaCoupe = NON_PNE; + PNE_RechercheTwoStepMir( Pne, ValDeVarContinue, NbVarEntieres, CoeffDeLaVariableEntiere, + SecondMembre, ValeurDeLaVariableEntiere, NumeroDeLaVariableEntiere, + TypeDeSubstitutionEntiere, BorneDeSubstitutionEntiere, + NbVarContinues, NumeroDeLaVariableContinue, TypeDeSubstitutionContinue, + BorneDeSubstitutionContinue, CoefficientDeLaVariableContinue, + CoeffCoupe, IndiceCoupe, T, NormaliserLaCoupe ); + +Fin2MirSurTableau: +free( Buff ); + +return; +} + +# endif diff --git a/src/ext/Sirius_Solver/pne/pne_verifier_faisabilite_contrainte_egalite.c b/src/ext/Sirius_Solver/pne/pne_verifier_faisabilite_contrainte_egalite.c new file mode 100644 index 0000000000..1296ec256c --- /dev/null +++ b/src/ext/Sirius_Solver/pne/pne_verifier_faisabilite_contrainte_egalite.c @@ -0,0 +1,181 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Contraintes d'egalite avec variables entiere. On verifie + qu'il peut y avoir une solution. + On divise tout par le pgcd du membre de gauche. Si la + division du nombre a droite n'est pas entiere alors il n'y a + pas de solution. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pne_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*# define AAA*/ + +/*----------------------------------------------------------------------------*/ + +void PNE_DetectionContraintesEntieresInfaisable( PROBLEME_PNE * Pne ) +{ + +#ifdef AAA + +int Cnt; int NombreDeContraintes; int Var; double Co; int NbBool; char PrendreEnCompte; +int * Mdeb; int * NbTerm; int * Nuvar; int * TypeDeBorne; double * A; double * B; +double * Coeff; double * Xmin; double * Xmax; double BCnt; char * SensContrainte; +int * TypeDeVariable; int Kref; int i; int a; int b; int c; double Min; +char TousLesCoeffSontEntiers; int il; int ilMax; double * X; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +A = Pne->ATrav; +Nuvar = Pne->NuvarTrav; +B = Pne->BTrav; +SensContrainte = Pne->SensContrainteTrav; + +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; +X = Pne->UTrav; + +if ( Pne->Coefficient_CG == NULL ) { + Pne->Coefficient_CG = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); + Pne->IndiceDeLaVariable_CG = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); + if ( Pne->Coefficient_CG == NULL || Pne->IndiceDeLaVariable_CG == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PNE_DetectionContraintesEntieresInfaisable \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } +} +Coeff = Pne->Coefficient_CG; + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( SensContrainte[Cnt] != '=' ) continue; + PrendreEnCompte = OUI_PNE; + NbBool = 0; + BCnt = B[Cnt]; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Nuvar[il]; + if ( TypeDeVariable[Var] != ENTIER ) { PrendreEnCompte = NON_PNE; break; } + Co = A[il]; + if ( Co == 0.0 ) goto NextElement; + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) b -= Co * X[Var]; + else if ( Xmin[Var] == Xmax[Var] ) b -= Co * Xmin[Var]; + else { + Coeff[NbBool] = Co; + NbBool++; + } + NextElement: + il++; + } + if ( PrendreEnCompte == NON_PNE ) continue; + if ( NbBool < 2 ) continue; + + /* Si les coefficients ne sont pas entiers on essaie de les rendre entiers en deplacant + la virgule */ + + Min = ldexp( 2, 4 ); /*2^4=16 2^5=32 etc..*/ + + /* Si les coefficients sont entiers au passe a l'etape du PGCD */ + TousLesCoeffSontEntiers = OUI_PNE; + for ( i = 0 ; i < NbBool && TousLesCoeffSontEntiers == OUI_PNE ; i++ ) { + if ( Coeff[i] - floor( Coeff[i] ) != 0.0 ) TousLesCoeffSontEntiers = NON_PNE; + } + if ( TousLesCoeffSontEntiers == NON_PNE ) { + Kref = 3; /* Pour esperer se deplacer d'au moins un chiffre apres la virgule */ + for ( i = 0 ; i < NbBool ; i++ ) { + while ( ldexp( Coeff[i], Kref ) < Min ) Kref++; + } + for ( i = 0 ; i < NbBool ; i++ ) { + Coeff[i] = floor( ldexp( Coeff[i], Kref ) ); + } + } + + /* On cherche le PGCD du membre de gauche */ + if ( Coeff[0] > Coeff[1] ) { a = (int) Coeff[0]; b = (int) Coeff[1]; } + else { a = (int) Coeff[1]; b = (int) Coeff[0]; } + + i = 1; + + GCD: + + printf("a %d b %d\n",a,b); + + if ( a == 0 && b == 0 ) c = 0; + else if ( b == 0 ) c = a; + else if ( a == 0 ) c = b; + else { + c = a % b; + while ( c != 0 ) { + a = b; + b = c; + c = a % b; + } + c = b; + } + + i++; + if ( i < NbBool ) { + if ( (int) Coeff[i] > c ) { a = (int) Coeff[i]; b = c; } + else { a = c; b = (int) Coeff[i]; } + goto GCD; + } + + /* c est le pgcd */ + printf("pgcd = %d Cnt = %d\n",c,Cnt); + + if ( c != 0 ) { + /* On divise le second membre par le pgcd et si le resultat n'est pas entier + on est certain que la contrainte ne peut pas etre satisfaite */ + BCnt /= c; + + printf("BCnt %e\n",BCnt); + + if ( BCnt - floor( BCnt ) > 1.e-4 && ceil( BCnt ) - BCnt > 1.e-4) { + printf("La contrainte %d n'est jamais satisfaite\n",Cnt); + exit(0); + } + } + exit(0); + +} +# endif + +return; +} + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_alloc_matrice.c b/src/ext/Sirius_Solver/pointInterieur/pi_alloc_matrice.c new file mode 100644 index 0000000000..c800f66f51 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_alloc_matrice.c @@ -0,0 +1,290 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/*********************************************************************** + + FONCTION: Allocation de la matrice du point interieur et liberation + + AUTEUR: R. GONZALEZ + +************************************************************************/ +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# include "lu_fonctions.h" + +# ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pi_memoire.h" +# endif + +#define MARGE_ALLOC 256 + +/*-------------------------------------------------------------------------*/ +/* Allocation de la matrice du point interieur (systeme augmente) */ + +void PI_AllocMatrice( PROBLEME_PI * Pi ) +{ +int Cnt; int NombreDeColonnes; int NombreDElementsAlloues; + +/* Calcul de la taille a allouer (on ne tient pas compte d'une presence eventuelle de couts croises + pour en tenir compte il faut balayer les couts croises */ +NombreDElementsAlloues = 0; +for ( Cnt = 0 ; Cnt < Pi->NombreDeContraintes ; Cnt++ ) NombreDElementsAlloues+= Pi->NbTerm[Cnt]; +NombreDElementsAlloues*= 2; +NombreDElementsAlloues+= Pi->NombreDeVariables + Pi->NombreDeContraintes; +NombreDElementsAlloues+= MARGE_ALLOC; + +NombreDeColonnes = Pi->NombreDeVariables + Pi->NombreDeContraintes; + +Pi->MatricePi = (MATRICE_PI *) malloc( sizeof( MATRICE_PI ) ); +if ( Pi->MatricePi == NULL ) { + printf(" Point interieur, memoire insuffisante dans le sous programme PI_AllocMatrice \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} + +Pi->MatricePi->NombreDeColonnes = NombreDeColonnes; +Pi->MatricePi->NombreDElementsAlloues = NombreDElementsAlloues; + +Pi->MatricePi->Elm = (double *) malloc( NombreDElementsAlloues * sizeof( double ) ); + +Pi->MatricePi->Indl = (int *) malloc( NombreDElementsAlloues * sizeof( int ) ); +Pi->MatricePi->Ideb = (int *) malloc( NombreDeColonnes * sizeof( int ) ); +Pi->MatricePi->Nonu = (int *) malloc( NombreDeColonnes * sizeof( int ) ); +Pi->MatricePi->Sec = (double *) malloc( NombreDeColonnes * sizeof( double ) ); + +Pi->MatricePi->IndexDuTermeDiagonalDansU = (int*) malloc( Pi->MatricePi->NombreDeColonnes * sizeof( int ) ); + +if ( Pi->MatricePi->Elm == NULL || Pi->MatricePi->Indl == NULL || Pi->MatricePi->Ideb == NULL || + Pi->MatricePi->Nonu == NULL || Pi->MatricePi->Sec == NULL || + Pi->MatricePi->IndexDuTermeDiagonalDansU == NULL ) { + printf(" Point interieur, memoire insuffisante dans le sous programme PI_AllocMatrice \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} + +/* Et on nettoie tout ca pour etre tranquille */ + +memset( (char *) Pi->MatricePi->Elm , 0 , NombreDElementsAlloues * sizeof( double ) ); + +memset( (char *) Pi->MatricePi->Indl , 0 , NombreDElementsAlloues * sizeof( int ) ); +memset( (char *) Pi->MatricePi->Ideb , 0 , NombreDeColonnes * sizeof( int ) ); +memset( (char *) Pi->MatricePi->Nonu , 0 , NombreDeColonnes * sizeof( int ) ); + +Pi->MatricePi->IndexDebutDesLignesDeU = NULL; +Pi->MatricePi->NbTermesDesLignesDeU = NULL; +Pi->MatricePi->ValeurDesTermesDeU = NULL; +Pi->MatricePi->ValeurDesTermesDeU_SV = NULL; +Pi->MatricePi->IndicesDeColonneDeU = NULL; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Init des triangle L et U de la factorisee */ + +void PI_InitMatriceLU( PROBLEME_PI * Pi , + int * IndexDebutDesLignesDeU , int * NbTermesDesLignesDeU , + double * ValeurDesTermesDeU , int * IndicesDeColonneDeU ) +{ +int il; int ilMax; int IndiceLigne; int IndiceColonne; int Ordre; int Var; int Nb; +int NbElementsAllouesU; char * T; double * V; +int * Ldeb; int * Lsui; int * Indc; int * Lder; int ilk; +int ilc;int Kp; char Erreur; + +/* Recherche des termes diagonaux et allocations memoire */ +for ( IndiceColonne = 0 ; IndiceColonne < Pi->MatricePi->NombreDeColonnes ; IndiceColonne++ ) { + Pi->MatricePi->IndexDuTermeDiagonalDansU[IndiceColonne] = -1; +} + +NbElementsAllouesU = 0; +/* Parcours du triangle U et recherche de l'index auquel en lesquel on trouve le terme diagonal */ +for ( Ordre = 0 ; Ordre < Pi->MatricePi->NombreDeColonnes ; Ordre++ ) { + NbElementsAllouesU+= NbTermesDesLignesDeU[Ordre]; + /* L'indice colonne est donne par l'indice colonne du premier terme + de U et c'est le terme diagonal */ + il = IndexDebutDesLignesDeU[Ordre]; + Var = IndicesDeColonneDeU[il]; + Pi->MatricePi->IndexDuTermeDiagonalDansU[Var] = il; +} + +Pi->MatricePi->NbElementsDeU = NbElementsAllouesU; + +Nb = Pi->MatricePi->NombreDeColonnes; + +T = (char *) malloc( Nb * sizeof( char ) ); +V = (double *) malloc( Nb * sizeof( double ) ); + +Pi->MatricePi->IndexDebutDesLignesDeU = (int *) malloc( Nb * sizeof( int ) ); +Pi->MatricePi->NbTermesDesLignesDeU = (int *) malloc( Nb * sizeof( int ) ); +Pi->MatricePi->ValeurDesTermesDeU = (double *) malloc( NbElementsAllouesU * sizeof( double ) ); +Pi->MatricePi->ValeurDesTermesDeU_SV = (double *) malloc( NbElementsAllouesU * sizeof( double ) ); +Pi->MatricePi->IndicesDeColonneDeU = (int *) malloc( NbElementsAllouesU * sizeof( int ) ); + +if ( T == NULL || V == NULL || + Pi->MatricePi->IndexDebutDesLignesDeU == NULL || + Pi->MatricePi->NbTermesDesLignesDeU == NULL || + Pi->MatricePi->ValeurDesTermesDeU == NULL || + Pi->MatricePi->ValeurDesTermesDeU_SV == NULL || + Pi->MatricePi->IndicesDeColonneDeU == NULL ) { + printf(" Point interieur, memoire insuffisante dans le sous programme PI_InitMatriceLU \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} + +/* Init et raz des vecteurs */ +memset( (char *) T , 0 , Nb * sizeof( char ) ); +memset( (char *) V , 0 , Nb * sizeof( double ) ); + +memcpy( (char *) Pi->MatricePi->IndexDebutDesLignesDeU , (char *) IndexDebutDesLignesDeU , Nb * sizeof( int ) ); +memcpy( (char *) Pi->MatricePi->NbTermesDesLignesDeU , (char *) NbTermesDesLignesDeU , Nb * sizeof( int ) ); +memcpy( (char *) Pi->MatricePi->IndicesDeColonneDeU , (char *) IndicesDeColonneDeU , NbElementsAllouesU * sizeof( int ) ); +memset( (char *) Pi->MatricePi->ValeurDesTermesDeU , 0 , NbElementsAllouesU * sizeof( double ) ); + +/* On recopie la matrice d'entree dans les triangles */ +/* Triangle U */ +/* 1- Chainage de Matrice Pi par lignes */ +Ldeb = (int *) malloc( Pi->MatricePi->NombreDeColonnes * sizeof( int ) ); +Lsui = (int *) malloc( Pi->MatricePi->NombreDElementsAlloues * sizeof( int ) ); +Indc = (int *) malloc( Pi->MatricePi->NombreDElementsAlloues * sizeof( int ) ); +Lder = (int *) malloc( Pi->MatricePi->NombreDeColonnes * sizeof( int ) ); +if ( Ldeb == NULL || Lsui == NULL || Indc == NULL || Lder == NULL ) { + printf(" Point interieur, memoire insuffisante dans le sous programme PI_InitMatriceLU \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} +for ( IndiceLigne = 0 ; IndiceLigne < Pi->MatricePi->NombreDeColonnes ; IndiceLigne++ ) Ldeb[IndiceLigne] = -1; +for ( IndiceColonne = 0 ; IndiceColonne < Pi->MatricePi->NombreDeColonnes ; IndiceColonne++ ) { + il = Pi->MatricePi->Ideb[IndiceColonne]; + ilMax = il + Pi->MatricePi->Nonu[IndiceColonne]; + while ( il < ilMax ) { + IndiceLigne = Pi->MatricePi->Indl[il]; + if ( Ldeb[IndiceLigne] < 0 ) { + Ldeb[IndiceLigne] = il; + Indc[il] = IndiceColonne; + Lsui[il] = -1; + Lder[IndiceLigne] = il; + } + else { + ilk = Lder[IndiceLigne]; + Lsui[ilk] = il; + Indc[il] = IndiceColonne ; + Lsui[il] = -1; + Lder[IndiceLigne] = il; + } + il++; + } +} +/* 2- Tranfert dans le triangle U */ +for ( Ordre = 0 ; Ordre < Pi->MatricePi->NombreDeColonnes ; Ordre++ ) { + il = Pi->MatricePi->IndexDebutDesLignesDeU[Ordre]; + ilMax = il + Pi->MatricePi->NbTermesDesLignesDeU[Ordre]; + while ( il < ilMax ) { + T[Pi->MatricePi->IndicesDeColonneDeU[il]] = 1; + il++; + } + /* L'indice ligne est aussi l'indice colonne du premier terme + de U */ + IndiceLigne = Pi->MatricePi->IndicesDeColonneDeU[IndexDebutDesLignesDeU[Ordre]]; + /* Tous les termes a recopier se trouvent dans la ligne "IndiceLigne" de MatricePi */ + il = Ldeb[IndiceLigne]; + while ( il >= 0 ) { + IndiceColonne = Indc[il]; + if ( T[IndiceColonne] == 1 ) V[IndiceColonne] = Pi->MatricePi->Elm[il]; + il = Lsui[il]; + } + /* Et on recopie le vecteur */ + il = Pi->MatricePi->IndexDebutDesLignesDeU[Ordre]; + ilMax = il + Pi->MatricePi->NbTermesDesLignesDeU[Ordre]; + while ( il < ilMax ) { + IndiceColonne = Pi->MatricePi->IndicesDeColonneDeU[il]; + if ( T[IndiceColonne] == 1 ) Pi->MatricePi->ValeurDesTermesDeU[il] = V[IndiceColonne]; + T[IndiceColonne] = 0; + V[IndiceColonne] = 0.0; + il++; + } +} + +free( Ldeb ); +free( Lsui ); +free( Indc ); +free( Lder ); +Ldeb = NULL; +Lsui = NULL; +Indc = NULL; +Lder = NULL; + +free( T ); +free( V ); +T = NULL; +V = NULL; + +# if VERBOSE_PI + printf("-> Simulation d'une refactorisation\n"); +# endif + + LU_RefactorisationSimulation( (MATRICE *) Pi->MatriceFactorisee , &Erreur , Pi->MatricePi->NbElementsDeU ); +/* Tester le code Erreur */ + +# if VERBOSE_PI + printf("-> Nombre de termes du triangle U de la factorisee %d\n",Pi->MatricePi->NbElementsDeU); +# endif + +memcpy( (char *) Pi->MatricePi->ValeurDesTermesDeU_SV ,(char *) Pi->MatricePi->ValeurDesTermesDeU , + Pi->MatricePi->NbElementsDeU * sizeof( double ) ); + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Liberation de la matrice */ + +void PI_LibereMatrice( PROBLEME_PI * Pi ) +{ + +if ( Pi->MatriceFactorisee != NULL ) { + LU_LibererMemoireLU( (MATRICE *) Pi->MatriceFactorisee ); + Pi->MatriceFactorisee = NULL; +} + +if ( Pi->MatricePi == NULL) return; + +free( Pi->MatricePi->Elm ); +free( Pi->MatricePi->Indl ); +free( Pi->MatricePi->Ideb ); +free( Pi->MatricePi->Nonu ); +free( Pi->MatricePi->Sec ); + +free( Pi->MatricePi->IndexDebutDesLignesDeU ); +free( Pi->MatricePi->NbTermesDesLignesDeU ); +free( Pi->MatricePi->ValeurDesTermesDeU ); +free( Pi->MatricePi->ValeurDesTermesDeU_SV ); +free( Pi->MatricePi->IndicesDeColonneDeU ); + +free( Pi->MatricePi->IndexDuTermeDiagonalDansU ); + +free( Pi->MatricePi ); + +return; +} + + + + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_alloc_probleme.c b/src/ext/Sirius_Solver/pointInterieur/pi_alloc_probleme.c new file mode 100644 index 0000000000..c81ba94ecb --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_alloc_probleme.c @@ -0,0 +1,296 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + + +/*********************************************************************************** + + FONCTION: Allocations memoire pour le probleme d'optimisation + Liberation memoire a la fin du probleme + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# include "lu_define.h" + +# ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pi_memoire.h" +# endif + +/*------------------------------------------------------------------------*/ + +void PI_AllocProbleme( PROBLEME_PI * Pi, + int NombreDeVariables_E, + int NombreDeContraintes_E, + int * Nbter_E, + char * Sens_E, + char * VariableBinaire_E, + int * TypeVar_E + ) +{ +int i; int NombreDeVariables; int NombreIneg; int NombredeTermesCnt; +int NombreDeContraintes ; int NbVarBin ; + +Pi->MatriceFactorisee = NULL; + +NombreDeVariables = NombreDeVariables_E; +NombreDeContraintes = NombreDeContraintes_E; + +NombreIneg = 0; +NombredeTermesCnt = 0; +for ( i = 0 ; i < NombreDeContraintes_E ; i++ ) { + if ( Sens_E[i] != '=' ) NombreIneg++; + NombredeTermesCnt+= Nbter_E[i]; +} + +NombredeTermesCnt+= NombreIneg; +NombreDeVariables+= NombreIneg; + +NbVarBin = 0; +if ( MPCC == OUI_PI ) { + for ( i = 0 ; i < NombreDeVariables_E ; i++ ) { + if ( VariableBinaire_E[i] == OUI_PI && TypeVar_E[i] != VARIABLE_FIXE ) { + NbVarBin++; + if ( NbVarBin == 1000000 ) { + i++; + for ( ; i < NombreDeVariables_E ; i++ ) VariableBinaire_E[i] = NON_PI; + break; + } + } + } + if ( NbVarBin > 0 ) { + NombredeTermesCnt+= 3* NbVarBin; + NombredeTermesCnt+= 1; /* Marge par rapport a la derniere contrainte (si la derniere contrainte est < ) */ + NombreDeVariables++; /* Car on va creer une variable Xi pour la norme l-infini */ + NombreDeContraintes+= NbVarBin; /* Une contrainte de complementarite par variable binaire */ + NombreDeVariables+= NbVarBin; /* Car on va creer des variables d'ecart */ + } + printf("Nombre de variables binaires dans le point interieur: %d\n",NbVarBin); +} + +/* Pour les tests de splitting */ +/* +NombreDeVariables*= 2; +NombreDeContraintes*= 2; +NombredeTermesCnt*= 2; +*/ +/* Fin pour les tests de splitting */ +#if VERBOSE_PI + printf("Nombre de termes de la matrice des contraintes %d\n",NombredeTermesCnt); +#endif + +Pi->CorrespondanceVarEntreeVarPi = (int *) malloc( NombreDeVariables * sizeof( int ) ); +Pi->CorrespondanceCntEntreeCntPi = (int *) malloc( NombreDeContraintes * sizeof( int ) ); + +Pi->Q = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->L = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->Qpar2 = (double *) malloc( NombreDeVariables * sizeof( double ) ); + +Pi->NbTermesAllouesPourA = NombredeTermesCnt; +Pi->A = (double *) malloc( NombredeTermesCnt * sizeof( double ) ); +Pi->B = (double *) malloc( NombreDeContraintes * sizeof( double ) ); +Pi->Mdeb = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +Pi->NbTerm = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +Pi->Indcol = (int *) malloc( NombredeTermesCnt * sizeof( int ) ); + +Pi->Cdeb = (int *) malloc( NombreDeVariables * sizeof( int ) ); +Pi->CNbTerm = (int *) malloc( NombreDeVariables * sizeof( int ) ); +Pi->ACol = (double *) malloc( NombredeTermesCnt * sizeof( double ) ); +Pi->NumeroDeContrainte = (int *) malloc( NombredeTermesCnt * sizeof( int ) ); +Pi->Csui = (int *) malloc( NombredeTermesCnt * sizeof( int ) ); + +Pi->U = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->U0 = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->Umax = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->Umin = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->Alpha = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->Alpha2 = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->TypeDeVariable = (char *) malloc( NombreDeVariables * sizeof( char ) ); +Pi->VariableBinaire = (char *) malloc( NombreDeVariables * sizeof( char ) ); +Pi->NumeroDeLaContrainteDeComplementarite = (int *) malloc( NombreDeVariables * sizeof( int ) ); +Pi->S1 = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->S2 = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->Lambda = (double *) malloc( NombreDeContraintes * sizeof( double ) ); +Pi->Lambda0 = (double *) malloc( NombreDeContraintes * sizeof( double ) ); + +Pi->ScaleU = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->ScaleB = (double *) malloc( NombreDeContraintes * sizeof( double ) ); + +Pi->DeltaU = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->DeltaLambda = (double *) malloc( NombreDeContraintes * sizeof( double ) ); +Pi->DeltaS1 = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->DeltaS2 = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->UkMoinsUmin = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->UmaxMoinsUk = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->UnSurUkMoinsUmin = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->UnSurUmaxMoinsUk = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->DeltaUDeltaS1 = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->DeltaUDeltaS2 = (double *) malloc( NombreDeVariables * sizeof( double ) ); + +Pi->SecondMembre = (double *) malloc( ( NombreDeVariables + NombreDeContraintes ) * sizeof( double ) ); +Pi->SecondMembreAffine = (double *) malloc( ( NombreDeVariables + NombreDeContraintes ) * sizeof( double ) ); + +Pi->MukIteration = (double *) malloc( NOMBRE_MAX_DITERATION * sizeof( double ) ); + +Pi->MaxOptimalite = (double *) malloc( NOMBRE_MAX_DITERATION * sizeof( double ) ); +Pi->MaxContrainte = (double *) malloc( NOMBRE_MAX_DITERATION * sizeof( double ) ); +Pi->MaxStationnarite = (double *) malloc( NOMBRE_MAX_DITERATION * sizeof( double ) ); +Pi->IterationTetakP = (double *) malloc( NOMBRE_MAX_DITERATION * sizeof( double ) ); +Pi->IterationTetakD = (double *) malloc( NOMBRE_MAX_DITERATION * sizeof( double ) ); + +Pi->RegulVar = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Pi->RegulContrainte = (double *) malloc( NombreDeContraintes * sizeof( double ) ); + +Pi->Matrice = (MATRICE_A_FACTORISER *) malloc( sizeof( MATRICE_A_FACTORISER ) ); + +/* Test de validite */ +if ( + Pi->CorrespondanceVarEntreeVarPi == NULL || + Pi->CorrespondanceCntEntreeCntPi == NULL || + Pi->Q == NULL || + Pi->L == NULL || + Pi->Qpar2 == NULL || + Pi->A == NULL || + Pi->B == NULL || + Pi->Mdeb == NULL || + Pi->NbTerm == NULL || + Pi->Indcol == NULL || + Pi->Cdeb == NULL || + Pi->CNbTerm == NULL || + Pi->ACol == NULL || + Pi->NumeroDeContrainte == NULL || + Pi->Csui == NULL || + Pi->U == NULL || + Pi->U0 == NULL || + Pi->Umax == NULL || + Pi->Umin == NULL || + Pi->Alpha == NULL || + Pi->Alpha2 == NULL || + Pi->TypeDeVariable == NULL || + Pi->VariableBinaire == NULL || + Pi->NumeroDeLaContrainteDeComplementarite == NULL || + Pi->S1 == NULL || + Pi->S2 == NULL || + Pi->Lambda == NULL || + Pi->Lambda0 == NULL || + Pi->ScaleU == NULL || + Pi->ScaleB == NULL || + Pi->DeltaU == NULL || + Pi->DeltaLambda == NULL || + Pi->DeltaS1 == NULL || + Pi->DeltaS2 == NULL || + Pi->UkMoinsUmin == NULL || + Pi->UmaxMoinsUk == NULL || + Pi->UnSurUkMoinsUmin == NULL || + Pi->UnSurUmaxMoinsUk == NULL || + Pi->DeltaUDeltaS1 == NULL || + Pi->DeltaUDeltaS2 == NULL || + Pi->SecondMembre == NULL || + Pi->SecondMembreAffine == NULL || + Pi->MukIteration == NULL || + Pi->MaxOptimalite == NULL || + Pi->MaxContrainte == NULL || + Pi->MaxStationnarite == NULL || + Pi->IterationTetakP == NULL || + Pi->IterationTetakD == NULL || + Pi->RegulVar == NULL || + Pi->RegulContrainte == NULL || + Pi->Matrice == NULL + ) { + + printf(" Point interieur, memoire insuffisante. Sous-programme: PI_AllocProbleme\n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +Pi->MatricePi = NULL; + +return; +} + +/*------------------------------------------------------------------------*/ + +void PI_LibereProbleme( PROBLEME_PI * Pi ) +{ + +free( Pi->CorrespondanceVarEntreeVarPi ); +free( Pi->CorrespondanceCntEntreeCntPi ); +free( Pi->Q ); +free( Pi->L ); +free( Pi->Qpar2 ); +free( Pi->A ); +free( Pi->B ); +free( Pi->Mdeb ); +free( Pi->NbTerm ); +free( Pi->Indcol ); +free( Pi->Cdeb ); +free( Pi->CNbTerm ); +free( Pi->ACol ); +free( Pi->NumeroDeContrainte ); +free( Pi->Csui ); +free( Pi->U ); +free( Pi->U0 ); +free( Pi->Umax ); +free( Pi->Umin ); +free( Pi->Alpha ); +free( Pi->Alpha2 ); +free( Pi->TypeDeVariable ); +free( Pi->VariableBinaire ); +free( Pi->NumeroDeLaContrainteDeComplementarite ); +free( Pi->S1 ); +free( Pi->S2 ); +free( Pi->Lambda ); +free( Pi->Lambda0 ); +free( Pi->ScaleU ); +free( Pi->ScaleB ); +free( Pi->DeltaU ); +free( Pi->DeltaLambda ); +free( Pi->DeltaS1 ); +free( Pi->DeltaS2 ); +free( Pi->UkMoinsUmin ); +free( Pi->UmaxMoinsUk ); +free( Pi->UnSurUkMoinsUmin ); +free( Pi->UnSurUmaxMoinsUk ); +free( Pi->DeltaUDeltaS1 ); +free( Pi->DeltaUDeltaS2 ); +free( Pi->SecondMembre ); +free( Pi->SecondMembreAffine ); +free( Pi->MukIteration ); +free( Pi->MaxOptimalite ); +free( Pi->MaxContrainte ); +free( Pi->MaxStationnarite ); +free( Pi->IterationTetakP ); +free( Pi->IterationTetakD ); +free( Pi->RegulVar ); +free( Pi->RegulContrainte ); + +free( Pi->Matrice ); + +return; +} + + + + + + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_armijo.c b/src/ext/Sirius_Solver/pointInterieur/pi_armijo.c new file mode 100644 index 0000000000..1312e7112c --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_armijo.c @@ -0,0 +1,315 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************************** + + FONCTION: Armijo + + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pi_memoire.h" +# endif + +/*------------------------------------------------------------------------*/ + +double PI_Armijo( PROBLEME_PI * Pi , double CoeffLimite ) +{ +double t; double tg ; double td; double q0; double qt; double m1; +double * G; double * E; double qPrime0; double Muk; +double * U; double * Lambda; int Var; int Cnt; +double * S1; double * S2; int k; int NbIter; + +k = ( 3 * Pi->NombreDeVariables ) + Pi->NombreDeContraintes; +G = (double *) malloc( k * sizeof( double ) ); +E = (double *) malloc( k * sizeof( double ) ); +S1 = (double *) malloc( Pi->NombreDeVariables * sizeof( double ) ); +S2 = (double *) malloc( Pi->NombreDeVariables * sizeof( double ) ); +U = (double *) malloc( Pi->NombreDeVariables * sizeof( double ) ); +Lambda = (double *) malloc( Pi->NombreDeContraintes * sizeof( double ) ); + +Muk = Pi->Muk; +td = CoeffLimite; +m1 = 0.1; +NbIter = 0; + +/* Sauvegarde des variables */ +t = 0.0; +PI_CalculDesVariables( Pi , t , U , Lambda , S1 , S2 ); + +q0 = PI_CalculNormeSecondMembre( Pi , Muk , E , U , Lambda , S1 , S2 ); + +qPrime0 = PI_CalculDeLaDeriveeDuCritereEnZero( Pi , Muk , E , G , U , Lambda , S1 , S2 ); + +t = td; + +printf("t = %e q0 = %e qPrime0 = %e\n",t,q0,qPrime0); +if ( qPrime0 > 0.0 ) goto qPrime0Positif; + +CalculDeqt: +NbIter++; + +PI_CalculDesVariables( Pi , t , U , Lambda , S1 , S2 ); +qt = PI_CalculNormeSecondMembre( Pi , Muk , E , U , Lambda , S1 , S2 ); + +if ( (qt-q0)/t > m1 * qPrime0 ) { + /* t trop grand */ + td = t; + t = 0.75 * td; + goto CalculDeqt; +} +printf("t = %e qt = %e\n",t,qt); +if ( NbIter > 1 ) printf("Attention nombre d'iterations Armijo superieur a 1: %d\n",NbIter); + +qPrime0Positif: +if ( qPrime0 > 0.0 ) { + printf("La direction ne descend pas, on applique le pas initial\n"); + t = CoeffLimite; + PI_CalculDesVariables( Pi , t , U , Lambda , S1 , S2 ); + qt = PI_CalculNormeSecondMembre( Pi , Muk , E , U , Lambda , S1 , S2 ); + printf("avec ce pas de %e la prediction est de %e\n",t,qt); + printf("On prend 0.1 fois le pas\n"); + t = 0.1 * CoeffLimite; + PI_CalculDesVariables( Pi , t , U , Lambda , S1 , S2 ); + qt = PI_CalculNormeSecondMembre( Pi , Muk , E , U , Lambda , S1 , S2 ); + printf("avec ce pas de %e la prediction est de %e\n",t,qt); +} + +free( G ); +free( E ); +free( U ); +free( Lambda ); +free( S1 ); +free( S2 ); + +G = NULL; +E = NULL; +U = NULL; +Lambda = NULL; +S1 = NULL; +S2 = NULL; + +return( t ); +} + +/*------------------------------------------------------------------------*/ + +void PI_CalculDesVariables( PROBLEME_PI * Pi , double t , double * U , + double * Lambda , double * S1 , double * S2 ) +{ +int Var; int Cnt; + +for ( Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) { + U [Var] = Pi->U[Var] + ( t * Pi->DeltaU[Var] ); + S1[Var] = Pi->S1[Var] + ( t * Pi->DeltaS1[Var] ); + S2[Var] = Pi->S2[Var] + ( t * Pi->DeltaS2[Var] ); +} +for ( Cnt = 0 ; Cnt < Pi->NombreDeContraintes ; Cnt++ ) { + Lambda[Cnt] = Pi->Lambda[Cnt] + ( t * Pi->DeltaLambda[Cnt] ); +} + +return; +} + +/*------------------------------------------------------------------------*/ + +double PI_CalculDeLaDeriveeDuCritereEnZero( PROBLEME_PI * Pi , + double Muk , double * E , double * G , double * U , + double * Lambda , double * S1 , double * S2 ) +{ +int Var; int Cnt; double X; double S; int il; int ilMax; double qPrime0; + +/* Calcul du gradient du critere en x */ + +for ( Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) { + /* Derivees en S1 */ + S = 0.0; + X = 0.0; + if ( Pi->TypeDeVariable[Var] == BORNEE || Pi->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) X = -( U[Var] - Pi->Umin[Var] ) / Pi->Alpha[Var]; + S+= X * E[Var]; + + X = 0.0; + if ( Pi->TypeDeVariable[Var] == BORNEE || Pi->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) X = 1.; + S+= X * E[(2 * Pi->NombreDeVariables) + Var]; + + G[Var] = S; + + /* Derivees en S2 */ + S = 0.0; + X = 0.0; + if ( Pi->TypeDeVariable[Var] == BORNEE || Pi->TypeDeVariable[Var] == BORNEE_SUPERIEUREMENT ) X = -( Pi->Umax[Var] - U[Var] ) / Pi->Alpha[Var]; + S+= X * E[Pi->NombreDeVariables + Var]; + + X = 0.0; + if ( Pi->TypeDeVariable[Var] == BORNEE || Pi->TypeDeVariable[Var] == BORNEE_SUPERIEUREMENT ) X = -1.; + S+= X * E[(2 * Pi->NombreDeVariables) + Var]; + + G[Pi->NombreDeVariables + Var] = S; + + /* Derivees en U */ + S = 0.0; + X = 0.0; + if ( Pi->TypeDeVariable[Var] == BORNEE || Pi->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) X = -S1[Var] * Pi->Alpha[Var]; + S+= X * E[Var]; + + X = 0.0; + if ( Pi->TypeDeVariable[Var] == BORNEE || Pi->TypeDeVariable[Var] == BORNEE_SUPERIEUREMENT ) X = S2[Var] * Pi->Alpha[Var]; + S+= X * E[Pi->NombreDeVariables + Var]; + + X = - Pi->Qpar2[Var] * Pi->Alpha[Var]; + /* Terme de regularisation eventuellement ajoute */ + X-= Pi->RegulVar[Var] * Pi->Alpha[Var]; + + S+= X * E[(2 * Pi->NombreDeVariables) + Var]; + + il = Pi->Cdeb[Var]; + ilMax = il + Pi->CNbTerm[Var]; + while ( il < ilMax ) { + Cnt = Pi->NumeroDeContrainte[il]; + X = -Pi->ACol[il] * Pi->Alpha[Var]; + S+= X * E[(3 * Pi->NombreDeVariables) + Cnt]; + il++; + } + G[ (2 * Pi->NombreDeVariables) + Var] = S; + +} + +for ( Cnt = 0 ; Cnt < Pi->NombreDeContraintes ; Cnt++ ) { + /* Derivees en Lambda */ + /* */ + S = 0.; + il = Pi->Mdeb[Cnt]; + ilMax = il + Pi->NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Pi->Indcol[il]; + X = -Pi->A[il] * Pi->Alpha[Var]; + S+= X * E[(2 * Pi->NombreDeVariables) + Var]; + il++; + } + /* Terme de regularisation eventuellement ajoute */ + X = -Pi->RegulContrainte[Cnt]; + S+= X * E[(3 * Pi->NombreDeVariables) + Var]; + + G[(3 * Pi->NombreDeVariables) + Cnt] = S; +} + +qPrime0 = 0.0; +for ( Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) { + qPrime0+= G[Var] * Pi->DeltaS1[Var] * Pi->Alpha[Var]; + qPrime0+= G[Pi->NombreDeVariables + Var] * Pi->DeltaS2[Var] * Pi->Alpha[Var]; + qPrime0+= G[ (2 * Pi->NombreDeVariables) + Var] * Pi->DeltaU[Var] / Pi->Alpha[Var]; +} +for ( Cnt = 0 ; Cnt < Pi->NombreDeContraintes ; Cnt++ ) { + qPrime0+= G[ (3 * Pi->NombreDeVariables) + Cnt] * Pi->DeltaLambda[Cnt]; +} + +return( qPrime0 ); +} + +/*------------------------------------------------------------------------*/ + +double PI_CalculNormeSecondMembre( PROBLEME_PI * Pi , double Muk , double * E , double * U , + double * Lambda , double * S1 , double * S2 ) +{ +int Var; double X; int il; int ilMax; double Norme; int Cnt; + +Norme = 0.; + +/* Partie variables */ +for ( Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) { + X = 0.0; + if ( Pi->TypeDeVariable[Var] == BORNEE || Pi->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + X = S1[Var] * ( U[Var] - Pi->Umin[Var] ); + } + X = Muk - X; + E[Var] = X; + Norme+= X * X; +} + +for ( Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) { + X = 0.0; + if ( Pi->TypeDeVariable[Var] == BORNEE || Pi->TypeDeVariable[Var] == BORNEE_SUPERIEUREMENT ) { + X = S2[Var] * ( Pi->Umax[Var] - U[Var] ); + } + X = Muk - X; + E[Pi->NombreDeVariables + Var] = X; + Norme+= X * X; +} + +for ( Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) { + /* Partie gradient du critere */ + X = ( Pi->Qpar2[Var] * U[Var] ) + Pi->L[Var]; + /* Terme de regularisation eventuellement ajoute */ + X+= Pi->RegulVar[Var] * ( U[Var] - Pi->U0[Var] ); + /* Partie gradient transpose des contraintes */ + il = Pi->Cdeb[Var]; + ilMax = il + Pi->CNbTerm[Var]; + while ( il < ilMax ) { + Cnt = Pi->NumeroDeContrainte[il]; + X+= Pi->ACol[il] * Lambda[Cnt]; + il++; + } + /* Changement de signe */ + X = -X; + /* Partie en S1 et S2 */ + if ( Pi->TypeDeVariable[Var] == BORNEE ) { + X+= S1[Var] - S2[Var]; + } + else if ( Pi->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + X+= S1[Var]; + } + else if ( Pi->TypeDeVariable[Var] == BORNEE_SUPERIEUREMENT ) { + X+= -S2[Var]; + } + E[(2 * Pi->NombreDeVariables) + Var] = X * Pi->Alpha[Var]; + Norme+= X * X; +} + +/* Partie Contraintes */ +for ( Cnt = 0 ; Cnt < Pi->NombreDeContraintes ; Cnt++ ) { + X = 0.; + /* Terme de regularisation eventuellement ajoute */ + X+= Pi->RegulContrainte[Cnt] * ( Pi->Lambda[Cnt] - Pi->Lambda0[Cnt] ); + /* */ + il = Pi->Mdeb[Cnt]; + ilMax = il + Pi->NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Pi->Indcol[il]; + X+= Pi->A[il] * U[Var]; + il++; + } + X = Pi->B[Cnt] - X; + + E[(3 * Pi->NombreDeVariables) + Cnt] = X; + Norme+= X * X; +} + +Norme = 0.5 * Norme; + +return( Norme ); +} + + + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_calculs_utilitaires.c b/src/ext/Sirius_Solver/pointInterieur/pi_calculs_utilitaires.c new file mode 100644 index 0000000000..43303943e0 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_calculs_utilitaires.c @@ -0,0 +1,266 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************************** + + FONCTION: + + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +/*------------------------------------------------------------------------*/ +/* Calcul du coefficient barriere */ + +void PI_Calmuk( PROBLEME_PI * Pi ) +{ +int Var; double Ga ; double TetakP ; double TetakD ; double Produit; +double * UkMoinsUmin ; double * UmaxMoinsUk ; double * DeltaU ; double * S1 ; +double *S2 ; double * DeltaS1 ; double * DeltaS2 ; +char * TypeDeVariable ; double * DeltaUDeltaS1; double * DeltaUDeltaS2 ; +int NombreDeVariables; char Type; + +PI_CalculDesTeta( Pi , &TetakP , &TetakD ); + +UkMoinsUmin = Pi->UkMoinsUmin; +UmaxMoinsUk = Pi->UmaxMoinsUk; +DeltaU = Pi->DeltaU; +S1 = Pi->S1; +S2 = Pi->S2; +DeltaS1 = Pi->DeltaS1; +DeltaS2 = Pi->DeltaS2; + +NombreDeVariables = Pi->NombreDeVariables; + +TypeDeVariable = Pi->TypeDeVariable; + +DeltaUDeltaS1 = Pi->DeltaUDeltaS1; +DeltaUDeltaS2 = Pi->DeltaUDeltaS2; + +if ( Pi->NumeroDIteration <= 1 ) { + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + DeltaUDeltaS1[Var] = 0.; + DeltaUDeltaS2[Var] = 0.; + } +} + +Produit = TetakP * TetakD; +Ga = 0.0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + Type = TypeDeVariable[Var]; + if ( Type == BORNEE ) { + Ga+= ( UkMoinsUmin[Var] + ( DeltaU[Var] * TetakP ) ) * ( S1[Var] + ( DeltaS1[Var] * TetakD )); + Ga+= ( UmaxMoinsUk[Var] - ( DeltaU[Var] * TetakP ) ) * ( S2[Var] + ( DeltaS2[Var] * TetakD )); + DeltaUDeltaS1[Var] = DeltaU[Var] * DeltaS1[Var] * Produit; + DeltaUDeltaS2[Var] = DeltaU[Var] * DeltaS2[Var] * Produit; + } + else if ( Type == BORNEE_INFERIEUREMENT ) { + Ga+= ( UkMoinsUmin[Var] + ( DeltaU[Var] * TetakP ) ) * ( S1[Var] + ( DeltaS1[Var] * TetakD )); + DeltaUDeltaS1[Var] = DeltaU[Var] * DeltaS1[Var] * Produit; + } + else if ( Type == BORNEE_SUPERIEUREMENT ) { + Ga+= ( UmaxMoinsUk[Var] - ( DeltaU[Var] * TetakP ) ) * ( S2[Var] + ( DeltaS2[Var] * TetakD )); + DeltaUDeltaS2[Var] = DeltaU[Var] * DeltaS2[Var] * Produit; + } +} +Ga = fabs( Ga ); /* Pour les cas extremes ou il peut y avoir des imprecisions qui donnent + un nombre negatif. Si on met 0 cela revient a rester sur une iteration + affine donc on prend fabs */ +Pi->Muk = Ga / Pi->G; + +Pi->Muk = pow( Pi->Muk , /*2.0*/ 0.5 ); + +Pi->Muk = Pi->Muk * ( Ga * Pi->Ro ); + +if ( Pi->Muk < MUK_MIN ) Pi->Muk = MUK_MIN; +if ( Pi->Muk > MUK_MAX ) Pi->Muk = MUK_MAX; + +return; +} + +/*------------------------------------------------------------------------*/ +/* Correction pour la centralite */ + +void PI_Calcent( PROBLEME_PI * Pi ) +{ +int Var; char * TypeDeVariable ; double * SecondMembre ; double * UnSurUkMoinsUmin ; +double * UnSurUmaxMoinsUk ; double * DeltaUDeltaS1 ; double *DeltaUDeltaS2 ; +double Muk; int NombreDeVariables; int NombreDeContraintes; int Cnt; double * RegulVar; +double * U; double * U0 ; double * RegulContrainte; double * Lambda ; +double * Lambda0 ; double X; double * Alpha; char Type; + +NombreDeVariables = Pi->NombreDeVariables; +NombreDeContraintes = Pi->NombreDeContraintes; + +memcpy( (char *) Pi->SecondMembre, (char *) Pi->SecondMembreAffine, + ( NombreDeVariables + NombreDeContraintes ) * sizeof( double ) ); + +TypeDeVariable = Pi->TypeDeVariable; +SecondMembre = Pi->SecondMembre; +UnSurUkMoinsUmin = Pi->UnSurUkMoinsUmin; +UnSurUmaxMoinsUk = Pi->UnSurUmaxMoinsUk; +DeltaUDeltaS1 = Pi->DeltaUDeltaS1; +DeltaUDeltaS2 = Pi->DeltaUDeltaS2; + +RegulVar = Pi->RegulVar; +U = Pi->U; +U0 = Pi->U0; +RegulContrainte = Pi->RegulContrainte; +Lambda = Pi->Lambda; +Lambda0 = Pi->Lambda0; + +Alpha = Pi->Alpha; + +Muk = Pi->Muk; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + X = 0.0; + Type = TypeDeVariable[Var]; + if ( Type == BORNEE ) { + X = ( Muk * ( UnSurUkMoinsUmin[Var] - UnSurUmaxMoinsUk[Var] ) ) + - ( UnSurUkMoinsUmin[Var] * DeltaUDeltaS1[Var] ) + - ( UnSurUmaxMoinsUk[Var] * DeltaUDeltaS2[Var] ); + } + else if ( Type == BORNEE_INFERIEUREMENT ) { + X = ( Muk * UnSurUkMoinsUmin[Var] ) + - ( UnSurUkMoinsUmin[Var] * DeltaUDeltaS1[Var] ); + } + else if ( Type == BORNEE_SUPERIEUREMENT ) { + X = ( Muk * ( - UnSurUmaxMoinsUk[Var] ) ) + - ( UnSurUmaxMoinsUk[Var] * DeltaUDeltaS2[Var] ); + + } + SecondMembre[Var]+= X * Alpha[Var]; + + /* Ajout des termes correctifs pour tenir compte de la regularisation issus de la derniere + factorisation */ + SecondMembre[Var]-= ( RegulVar[Var] * ( U[Var] - U0[Var] ) ) * Alpha[Var]; + +} + +/* Ajout des termes correctifs pour tenir compte de la regularisation issus de la derniere + factorisation */ + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + /*SecondMembre[NombreDeVariables + Cnt]-= RegulContrainte[Cnt] * ( Lambda[Cnt] - Lambda0[Cnt] );*/ + SecondMembre[NombreDeVariables + Cnt]+= RegulContrainte[Cnt] * ( Lambda[Cnt] - Lambda0[Cnt] ); +} + +return; +} + +/*------------------------------------------------------------------------*/ +/* Calcul de l'ecart de complementarite */ + +void PI_Caldel( PROBLEME_PI * Pi ) +{ +int Var; int Icopt ; double Ecopt; double x; double X; char * TypeDeVariable; +double * UkMoinsUmin ; double * UmaxMoinsUk ; double * S1; double *S2 ; +double SeuilDOptimalite; double G; char Type; + +TypeDeVariable = Pi->TypeDeVariable; + +UkMoinsUmin = Pi->UkMoinsUmin; +UmaxMoinsUk = Pi->UmaxMoinsUk; +S1 = Pi->S1; +S2 = Pi->S2; +SeuilDOptimalite = Pi->SeuilDOptimalite; + +Pi->G = 0.; +Ecopt = 0.; +Icopt = -1; + +G = Pi->G; + +for ( Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) { + Type = TypeDeVariable[Var]; + if ( Type == BORNEE ) { + x = UkMoinsUmin[Var] * S1[Var]; + X = fabs( x ); + if ( X > SeuilDOptimalite ) { + if ( X > Ecopt ) { + Ecopt = X; + Icopt = Var; + } + } + G+= x; + x = UmaxMoinsUk[Var] * S2[Var]; + X = fabs( x ); + if ( X > SeuilDOptimalite ) { + if ( X > Ecopt ) { + Ecopt = X; + Icopt = Var; + } + } + G+= x; + } + else if ( Type == BORNEE_INFERIEUREMENT ) { + x = UkMoinsUmin[Var] * S1[Var]; + X = fabs( x ); + if ( X > SeuilDOptimalite ) { + if ( X > Ecopt ) { + Ecopt = X; + Icopt = Var; + } + } + G+= x; + } + else if ( Type == BORNEE_SUPERIEUREMENT ) { + x = UmaxMoinsUk[Var] * S2[Var]; + X = fabs( x ); + if ( X > SeuilDOptimalite ) { + if ( X > Ecopt ) { + Ecopt = X; + Icopt = Var; + } + } + G+= x; + } + /* Si non bornee rien a faire */ +} + +if ( G == 0.0 ) G = 1.0; +Pi->G = G; + +/* Test d'optimalite */ +Pi->MaxOptimalite[Pi->NumeroDIteration-1] = Ecopt; +if ( Ecopt > Pi->SeuilDOptimalite ) Pi->ArretOpt = NON_PI; + +#if VERBOSE_PI + printf("Optimalite : seuil %e ecart max %e ", Pi->SeuilDOptimalite,Ecopt); + if ( Icopt >= 0 ) { + printf("variable %d min %e valeur %e max %e S1 %e S2 %e ", + Icopt,Pi->Umin[Icopt],Pi->U[Icopt],Pi->Umax[Icopt],Pi->S1[Icopt],Pi->S2[Icopt]); + if ( Pi->TypeDeVariable[Icopt] == BORNEE ) printf(" BORNEE\n"); + else if ( Pi->TypeDeVariable[Icopt] == BORNEE_INFERIEUREMENT ) printf(" BORNEE_INFERIEUREMENT\n"); + else if ( Pi->TypeDeVariable[Icopt] == BORNEE_SUPERIEUREMENT ) printf(" BORNEE_SUPERIEUREMENT\n"); + else if ( Pi->TypeDeVariable[Icopt] == NON_BORNEE ) printf(" NON_BORNEE\n"); + } + else { + printf("\n"); + } + +#endif + +return; +} + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_calstaf.c b/src/ext/Sirius_Solver/pointInterieur/pi_calstaf.c new file mode 100644 index 0000000000..33651ca182 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_calstaf.c @@ -0,0 +1,160 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************************** + + FONCTION: + Calcul du second membre incluant le gradient et le test de stationnarite. + + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +/*-----------------------------------------------------------------------------------*/ + +void PI_Calstaf( PROBLEME_PI * Pi ) +{ +int i; int j; int il; int ilMax; double X; double Y; int iq; double Critere; +double Ecsta; int Icsta; double Eccnt; int Iccnt; int Var; double * Alpha; +double * RegulVar; double * U0; double * RegulContrainte; double * Lambda0; +double * Qpar2; double * L; double *S1 ; double * S2; int * Mdeb; int * NbTerm; int * Indcol; +double * A; double * U; double * SecondMembre; double * Lambda; double * B; +double SeuilDAdmissibilite; int NombreDeVariables;int NombreDeContraintes; + +Eccnt = 0.; Iccnt = -1; /* Raz */ +Ecsta = 0.; Icsta = -1; /* Raz */ + +Mdeb = Pi->Mdeb; +NbTerm = Pi->NbTerm; +Indcol = Pi->Indcol; +A = Pi->A; +B = Pi->B; + +U = Pi->U; +SecondMembre = Pi->SecondMembre; +Lambda = Pi->Lambda; + +Alpha = Pi->Alpha; + +SeuilDAdmissibilite = Pi->SeuilDAdmissibilite; +NombreDeVariables = Pi->NombreDeVariables; +NombreDeContraintes = Pi->NombreDeContraintes; + +RegulVar = Pi->RegulVar; +U0 = Pi->U0; + +RegulContrainte = Pi->RegulContrainte; +Lambda0 = Pi->Lambda0; + +for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + X = 0.; + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + /* Partie contrainte */ + Var = Indcol[il]; + X+= A[il] * U[Var]; + + /* Partie stationnarite */ + SecondMembre[Var]+= A[il] * Alpha[Var] * Lambda[i]; + + il++; + } + + SecondMembre[ NombreDeVariables + i ] = B[i] - X; + + X = SecondMembre[ NombreDeVariables + i ]; + /* On tient compte des termes de freinage dans la condition d'admissibilite */ + /*X-= RegulContrainte[i] * ( Lambda[i] - Lambda0[i] );*/ + + X = fabs( X ); + if ( X > SeuilDAdmissibilite ) { + if ( X > Eccnt ) { Eccnt = X; Iccnt = i; } + } + +} + +/*printf("Attention on ajoute RegulContrainte[i] * ( Lambda[i] - Lambda0[i] dans le controle du second membre contraintes\n");*/ + +Pi->MaxContrainte[Pi->NumeroDIteration-1] = Eccnt; +if ( Eccnt > Pi->SeuilDAdmissibilite ) Pi->ArretCnt = NON_PI; + +#if VERBOSE_PI + printf("Admissibilite: seuil %e ecart max %e ", Pi->SeuilDAdmissibilite, Eccnt); + if ( Iccnt >= 0 ) { + printf("contrainte %d regul %e", Iccnt,Pi->RegulContrainte[Iccnt]); + } + printf("\n"); +#endif + +/* Test sur la stationnarite */ + +Qpar2 = Pi->Qpar2; +L = Pi->L; +S1 = Pi->S1; +S2 = Pi->S2; +for ( i = 0 ; i < NombreDeVariables ; i++ ) { + + X = ( Qpar2[i] * U[i] ) + L[i]; + + X*= Alpha[i]; + + SecondMembre[i]+= X; + + Critere = ( ( S1[i] - S2[i] ) * Alpha[i] ) - SecondMembre[i]; + /* On tient compte des termes de freinage dans la condition de stationnarite */ + Critere-= RegulVar[i] * ( U[i] - U0[i] ) * Alpha[i]; + + SecondMembre[i] = -SecondMembre[i]; + + Y = fabs( Critere ); + /* Il faudrait tenir compte de Alpha dans la valeur du seuil mais si Alpha devient tres petit le seuil + peut devenir vraiment trop petit et on ne l'atteint jamais */ + if ( Y > Pi->SeuilDeStationnarite ) { + if ( Y > Ecsta ) { Ecsta = Y; Icsta = i; } + } +} + +Pi->MaxStationnarite[Pi->NumeroDIteration-1] = Ecsta; +if ( Icsta >= 0 ) Pi->ArretSta = NON_PI; + +#if VERBOSE_PI + printf("Stationnarite: seuil %e ecart max %e ", Pi->SeuilDeStationnarite, Ecsta); + if ( Icsta >= 0 ) { + printf("variable %d regul %e valeur var. %e", Icsta, Pi->RegulVar[Icsta], Pi->U[Icsta]); + if ( Pi->TypeDeVariable[Icsta] == BORNEE ) printf(" BORNEE "); + else if ( Pi->TypeDeVariable[Icsta] == BORNEE_INFERIEUREMENT ) printf(" BORNEE_INFERIEUREMENT "); + else if ( Pi->TypeDeVariable[Icsta] == BORNEE_SUPERIEUREMENT ) printf(" BORNEE_SUPERIEUREMENT "); + else if ( Pi->TypeDeVariable[Icsta] == NON_BORNEE ) printf(" NON_BORNEE "); + printf(" S1 %e S2 %e", Pi->S1[Icsta],Pi->S2[Icsta]); + if ( Pi->TypeDeVariable[Icsta] == BORNEE ) { + } + } + printf("\n"); +#endif + +/* Sauvegarde */ +memcpy( (char *) Pi->SecondMembreAffine, (char *) SecondMembre, ( NombreDeVariables + NombreDeContraintes ) * sizeof( double ) ); + +return; +} + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_constantes_externes.h b/src/ext/Sirius_Solver/pointInterieur/pi_constantes_externes.h new file mode 100644 index 0000000000..5686db48d0 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_constantes_externes.h @@ -0,0 +1,39 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef CONSTANTES_EXTERNES_POINT_INTERIEUR_DEJA_DEFINIES +/*******************************************************************************************/ +/* + Definition des constantes symboliques a utiliser par le module appelant le simplexe +*/ + +# define PI_ERREUR_INTERNE 2 +/* Constantes symboliques du OUI et du NON */ +# define OUI_PI 1 +# define NON_PI 0 +/* */ + +/* Type des variables fournies en entree */ +# define VARIABLE_FIXE 1 +# define VARIABLE_BORNEE_DES_DEUX_COTES 2 +# define VARIABLE_BORNEE_INFERIEUREMENT 3 +# define VARIABLE_BORNEE_SUPERIEUREMENT 4 +# define VARIABLE_NON_BORNEE 5 + +/*******************************************************************************************/ +# define CONSTANTES_EXTERNES_POINT_INTERIEUR_DEJA_DEFINIES +# endif + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_cremat.c b/src/ext/Sirius_Solver/pointInterieur/pi_cremat.c new file mode 100644 index 0000000000..5153d344ea --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_cremat.c @@ -0,0 +1,61 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/*********************************************************************** + + FONCTION: Creation de la matrice du point interieur. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# include "lu_constantes_externes.h" +# include "lu_definition_arguments.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +/*-------------------------------------------------------------------------*/ +/* Allocation de la matrice, calcul des termes, stockage des termes */ + +void PI_Cremat( PROBLEME_PI * Pi ) +{ + +PI_CrematSystemeAugmente( Pi ); + +return; +} + +/*-------------------------------------------------------------------------*/ +/* Calcul de termes de la matrice a chaque iteration puis factorisation */ + +void PI_Crebis( PROBLEME_PI * Pi ) +{ + +PI_CrebisSystemeAugmente( Pi ); + +return; +} + + + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_cremat_systeme_augmente.c b/src/ext/Sirius_Solver/pointInterieur/pi_cremat_systeme_augmente.c new file mode 100644 index 0000000000..a0b03fe9c7 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_cremat_systeme_augmente.c @@ -0,0 +1,415 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/*********************************************************************** + + FONCTION: Creation de la matrice du point interieur. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# include "lu_constantes_externes.h" +# include "lu_definition_arguments.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pi_memoire.h" +# endif + +/*-------------------------------------------------------------------------*/ +/* Allocation de la matrice, calcul des termes, stockage des termes */ + +void PI_CrematSystemeAugmente( PROBLEME_PI * Pi ) +{ +int Var; int Cnt ; int Colonne; int il; int ilMax ; int ilCourant; double X ; +char Type; double * Alpha; double * Alpha2; int NombreDeVariables; int NombreDeContraintes; +double * RegulVar; double * RegulContrainte; double * Qpar2; double * UnSurUkMoinsUmin; +double * UnSurUmaxMoinsUk; double * S1; double * S2; double * U0; double * Lambda0; double * U; +double * Lambda; char * TypeDeVariable; int NbIter; +int * Ideb; int * Nonu; int * Indl; int * Cdeb;int * CNbTerm; int * NumeroDeContrainte; +int * Mdeb; int * NbTerm; int * Indcol; double * Elm; double * ACol; double * A; +double * TermeDeRegularisation; + +MATRICE_A_FACTORISER * Matrice; + +Matrice = (MATRICE_A_FACTORISER *) Pi->Matrice; + +NombreDeVariables = Pi->NombreDeVariables; +NombreDeContraintes = Pi->NombreDeContraintes; + +TermeDeRegularisation = (double *) malloc( ( NombreDeVariables + NombreDeContraintes ) * sizeof( double )); +if ( TermeDeRegularisation == NULL ) { + printf(" Point interieur, memoire insuffisante dans le sous programme PI_CrebisSystemeAugmente \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} + +RegulVar = Pi->RegulVar; +RegulContrainte = Pi->RegulContrainte; + +TypeDeVariable = Pi->TypeDeVariable; + +Qpar2 = Pi->Qpar2; +UnSurUkMoinsUmin = Pi->UnSurUkMoinsUmin; +UnSurUmaxMoinsUk = Pi->UnSurUmaxMoinsUk; +S1 = Pi->S1; +S2 = Pi->S2; + +Cdeb = Pi->Cdeb; +CNbTerm = Pi->CNbTerm; +ACol = Pi->ACol; +NumeroDeContrainte = Pi->NumeroDeContrainte; + +Mdeb = Pi->Mdeb; +NbTerm = Pi->NbTerm; +Indcol = Pi->Indcol; +A = Pi->A; + +U0 = Pi->U0; +U = Pi->U; +Lambda0 = Pi->Lambda0; +Lambda = Pi->Lambda; +Alpha = Pi->Alpha; +Alpha2 = Pi->Alpha2; + +/* RAZ des termes de regularisation */ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + RegulVar[Var] = 0.0; + Alpha[Var] = 1.0; + Alpha2[Var] = 1.0; +} +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ){ + RegulContrainte[Cnt] = 0.0; +} +for ( Colonne = 0 ; Colonne < NombreDeVariables + NombreDeContraintes ; Colonne++ ) { + TermeDeRegularisation[Colonne] = 0.0; +} + +NbIter = 0; + +DebutCremat: + +NbIter++; + +PI_LibereMatrice( Pi ); +PI_AllocMatrice( Pi ); + +Ideb = Pi->MatricePi->Ideb; +Nonu = Pi->MatricePi->Nonu; +Elm = Pi->MatricePi->Elm; +Indl = Pi->MatricePi->Indl; + +Pi->MatricePi->NombreDeColonnes = NombreDeVariables + NombreDeContraintes; + +ilCourant = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + Colonne = Var; + Ideb[Colonne] = ilCourant; + Nonu[Colonne] = 0; + /* Terme diagonal ( hessien ) */ + Type = TypeDeVariable[Var]; + if ( Type == BORNEE ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ) + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else if ( Type == BORNEE_INFERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ); + } + else if ( Type == BORNEE_SUPERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else { + X = Qpar2[Var]; + } + Elm [ilCourant] = ( X + RegulVar[Var] ) * Alpha2[Var]; + TermeDeRegularisation[Var] = RegulVar[Var] * Alpha2[Var]; + Indl[ilCourant] = Var; + Nonu[Colonne]++; + ilCourant++; + /* Partie matrice des contraintes, vision transposee */ + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + Elm [ilCourant] = ACol[il] * Alpha[Var]; + Indl[ilCourant] = NombreDeVariables + NumeroDeContrainte[il]; + Nonu[Colonne]++; + ilCourant++; + il++; + } +} + +/* Matrice des contraintes */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + Colonne = NombreDeVariables + Cnt; + Ideb[Colonne] = ilCourant; + Nonu[Colonne] = 0; + + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + Elm [ilCourant] = A[il] * Alpha[Var]; + Indl[ilCourant] = Var; + Nonu[Colonne]++; + ilCourant++; + il++; + } + /* Terme de regularisation si necessaire */ + Elm [ilCourant] = RegulContrainte[Cnt]; + TermeDeRegularisation[Colonne] = RegulContrainte[Cnt]; + Indl[ilCourant] = Colonne; + Nonu[Colonne]++; + ilCourant++; +} + +/* Elimination ordonnee et factorisation */ +# if VERBOSE_PI + printf("-> Factorisation du systeme augmente\n"); +# endif + +if ( Pi->MatriceFactorisee != NULL ) { + LU_LibererMemoireLU( (MATRICE *) Pi->MatriceFactorisee ); + Pi->MatriceFactorisee = NULL; +} + +Matrice->ContexteDeLaFactorisation = LU_POINT_INTERIEUR; +/* S'il n'y a pas beaucoup de contraintes on n'utilise pas les super lignes */ +if ( Pi->NombreDeContraintes > 1000 ) Matrice->UtiliserLesSuperLignes = OUI_LU; +else Matrice->UtiliserLesSuperLignes = NON_LU; +Matrice->ValeurDesTermesDeLaMatrice = Elm; +Matrice->IndicesDeLigne = Indl; +Matrice->IndexDebutDesColonnes = Ideb; +Matrice->NbTermesDesColonnes = Nonu; +Matrice->NombreDeColonnes = Pi->MatricePi->NombreDeColonnes; +Matrice->FaireScalingDeLaMatrice = NON_LU; +Matrice->UtiliserLesValeursDePivotNulParDefaut = NON_LU; +Matrice->ValeurDuPivotMin = VALEUR_DU_PIVOT_MIN; +Matrice->ValeurDuPivotMinExtreme = VALEUR_DU_PIVOT_MIN_EXTREME; +Matrice->SeuilPivotMarkowitzParDefaut = NON_LU; +Matrice->ValeurDuPivotMarkowitz = 1.e-3; /* Sans importance si valeur par defaut */ +Matrice->FaireDuPivotageDiagonal = OUI_LU; +Matrice->LaMatriceEstSymetrique = OUI_LU; +Matrice->LaMatriceEstSymetriqueEnStructure = NON_LU; + +Matrice->ValeurDeRegularisation = VALEUR_DE_REGULARISATION; +Matrice->TermeDeRegularisation = TermeDeRegularisation; + +Pi->MatriceFactorisee = LU_Factorisation( Matrice ); + +if ( Pi->MatriceFactorisee == NULL ) { + printf(" Point interieur, memoire insuffisante dans le sous programme PI_CrematSystemeAugmente \n"); + Pi->AnomalieDetectee = PI_ERREUR_INTERNE; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} +if ( Matrice->ProblemeDeFactorisation != NON_LU ) { + printf(" Point interieur, factorisation impossible \n"); + Pi->AnomalieDetectee = PI_ERREUR_INTERNE; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} + +if ( Matrice->OnARegularise == OUI_LU ) { + # if VERBOSE_PI + printf("-> Regularisation de la matrice du systeme augmente\n"); + # endif + for ( Colonne = 0 ; Colonne < Pi->MatricePi->NombreDeColonnes ; Colonne++ ) { + if ( TermeDeRegularisation[Colonne] == 0.0 ) continue; + if ( Colonne < NombreDeVariables ) { + RegulVar[Colonne] = TermeDeRegularisation[Colonne] / Alpha2[Colonne]; + } + else { + RegulContrainte[Colonne-NombreDeVariables] = TermeDeRegularisation[Colonne]; + } + } + if ( NbIter < 1 ) goto DebutCremat; +} + +free( TermeDeRegularisation ); + +/* En sortie on recupere le triangle dans lesquels on remet la matrice d'entree + afin de la mettre a jour au cours des iterations suivantes */ +/* Triangle U stocke par Ligne */ +/* a revoir */ +/* +printf(" Revoir la routine PI_InitMatriceLU\n"); +*/ +PI_InitMatriceLU( Pi , + Matrice->IndexDebutDesLignesDeU , Matrice->NbTermesDesLignesDeU , + Matrice->ValeurDesTermesDeU , Matrice->IndicesDeColonneDeU ); + +return; +} + +/*-------------------------------------------------------------------------*/ +/* Calcul de termes de la matrice a chaque iteration puis factorisation */ + +void PI_CrebisSystemeAugmente( PROBLEME_PI * Pi ) +{ +int Var; double X; int il; char Position; char Erreur; int Cnt; int Ordre; +int IndiceLigne; int Colonne; int NombreDeContraintes; int NombreDeColonnes; +double * TermeDeRegularisation; char OnARegularise; int i; int ilMax; +char * TypeDeVariable; double * Qpar2; double * UnSurUkMoinsUmin; double * UnSurUmaxMoinsUk; +double * S1; double * S2; double * Lambda; int NombreDeVariables; +int * Ideb; double * Elm; int * IndexDuTermeDiagonalDansU; double * RegulContrainte; +double * RegulVar; double * ValeurDesTermesDeU; int NbIter; double * Alpha; double * Alpha2; +int Kp; int VarPiv; int * IndexDebutDesLignesDeU; int * NbTermesDesLignesDeU; +int * IndicesDeColonneDeU; double * ValeurDesTermesDeU_SV; char Type; + +TermeDeRegularisation = (double *) malloc( Pi->MatricePi->NombreDeColonnes * sizeof( double )); +if ( TermeDeRegularisation == NULL ) { + printf(" Point interieur, memoire insuffisante dans le sous programme PI_CrebisSystemeAugmente \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} + +TypeDeVariable = Pi->TypeDeVariable; +Qpar2 = Pi->Qpar2; +UnSurUkMoinsUmin = Pi->UnSurUkMoinsUmin; +UnSurUmaxMoinsUk = Pi->UnSurUmaxMoinsUk; +S1 = Pi->S1; +S2 = Pi->S2; +Lambda = Pi->Lambda; + +Alpha = Pi->Alpha; +Alpha2 = Pi->Alpha2; + +NombreDeVariables = Pi->NombreDeVariables; +NombreDeContraintes = Pi->NombreDeContraintes; +NombreDeColonnes = Pi->MatricePi->NombreDeColonnes; + +RegulVar = Pi->RegulVar; +RegulContrainte = Pi->RegulContrainte; + +Elm = Pi->MatricePi->Elm; +Ideb = Pi->MatricePi->Ideb; +IndexDuTermeDiagonalDansU = Pi->MatricePi->IndexDuTermeDiagonalDansU; +ValeurDesTermesDeU = Pi->MatricePi->ValeurDesTermesDeU; + +NbIter = 0; + +/* Modification du terme diagonal de MatricePi */ + +Refactorisation: + +# if VERBOSE_PI + printf("-> Refactorisation du systeme augmente\n"); +# endif + +NbIter++; +for ( i = 0 ; i < NombreDeColonnes ; i++ ) TermeDeRegularisation[i] = 0.0; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) RegulVar[Var] = 0.0; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) RegulContrainte[Cnt] = 0.0; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + Type = TypeDeVariable[Var]; + if ( Type == BORNEE ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ) + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else if ( Type == BORNEE_INFERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ); + } + else if ( Type == BORNEE_SUPERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else { + X = Qpar2[Var]; + } + + X*= Alpha2[Var]; + TermeDeRegularisation[Var] = RegulVar[Var] * Alpha2[Var]; + ValeurDesTermesDeU[IndexDuTermeDiagonalDansU[Var]] = X + TermeDeRegularisation[Var]; + +} + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + Var = NombreDeVariables + Cnt; + X = RegulContrainte[Cnt]; + TermeDeRegularisation[Var] = X; + ValeurDesTermesDeU[IndexDuTermeDiagonalDansU[Var]] = X; +} + +/* On met a jour les termes extra diagonaux de U en fonction du changement de variables */ +IndexDebutDesLignesDeU = Pi->MatricePi->IndexDebutDesLignesDeU; +NbTermesDesLignesDeU = Pi->MatricePi->NbTermesDesLignesDeU; +IndicesDeColonneDeU = Pi->MatricePi->IndicesDeColonneDeU; +ValeurDesTermesDeU_SV = Pi->MatricePi->ValeurDesTermesDeU_SV; + +Kp = 0; +ilMax = 0; +while ( Kp < NombreDeColonnes ) { + il = ilMax; + ilMax+= NbTermesDesLignesDeU[Kp]; + VarPiv = IndicesDeColonneDeU[il]; + il++; /* On saute le terme diagonal: a verifier que c'est aussi le cas dans cette vue i.e. terme diagonal en premier */ + while ( il < ilMax ) { + Colonne = IndicesDeColonneDeU[il]; + if ( Colonne < NombreDeVariables ) Var = Colonne; + else Var = VarPiv; + /* Il faut que Var et VarPiv soient dans les variables (pas dans les contraintes) */ + if ( Var < NombreDeVariables ) { + ValeurDesTermesDeU[il] = ValeurDesTermesDeU_SV[il] * Alpha[Var]; + } + il++; + } + Kp++; +} + +LU_Refactorisation( (MATRICE *) Pi->MatriceFactorisee, + ValeurDesTermesDeU, Pi->MatricePi->NbElementsDeU, + TermeDeRegularisation , VALEUR_DE_REGULARISATION , + &OnARegularise , &Erreur ); + +if ( Erreur == OUI_LU ) { + free( TermeDeRegularisation ); + /* On tente une factorisation complete car peut-ętre que les permutations ne sont + plus bonnes */ + PI_CrematSystemeAugmente( Pi ); + OnARegularise = NON_LU; +} + +if ( OnARegularise == OUI_LU ) { + for ( i = 0 ; i < NombreDeColonnes ; i++ ) { + if ( TermeDeRegularisation[i] == 0.0 ) continue; + if ( i < NombreDeVariables ) { + RegulVar[i] = TermeDeRegularisation[i] / Alpha2[i]; + /*printf("Regularisation sur la variable %d RegulVar %e\n",i,RegulVar[i]);*/ + } + else { + RegulContrainte[i-NombreDeVariables] = TermeDeRegularisation[i]; + /*printf("Regularisation sur la contrainte %d\n",i-NombreDeVariables);*/ + } + } + + # if VERBOSE_PI + printf("-> Regularisation de la matrice du systeme augmente\n"); + # endif + if ( NbIter < 1 ) goto Refactorisation; +} + +free( TermeDeRegularisation ); + +return; +} + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_define.h b/src/ext/Sirius_Solver/pointInterieur/pi_define.h new file mode 100644 index 0000000000..fe750c31f5 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_define.h @@ -0,0 +1,244 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef DEFINITIONS_PROBLEME_PI_FAITES +/*******************************************************************************************/ + +# include "pi_constantes_externes.h" + +# define VERBOSE_PI 0 + +# define PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE +# undef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + +# define MPCC NON_PI + +# define BORNEE 1 /* La variable est bornee des deux cotes */ +# define BORNEE_INFERIEUREMENT 2 /* La variable n'est bornee qu'inferieurement */ +# define BORNEE_SUPERIEUREMENT 3 /* La variable n'est bornee que superieurement. + Rq: en entree un traitement supplementaire la transforme en bornee inferieurement + de telle sorte qu'en cours d'algorithme il n'y a plus que des variables + bornees inferieurement */ +# define NON_BORNEE 4 /* La variable n'est ni inferieurement ni superieurement bornee */ + +# define ZERO 1.e-15 /*1.e-14*/ +# define VZER ( 1.1 * ZERO ) + +# define VALEUR_DE_REGULARISATION 1.e-9 /*1.e-8*/ +# define VALEUR_DU_PIVOT_MIN (1.e-3 * VALEUR_DE_REGULARISATION) /*1.e-10*/ +# define VALEUR_DU_PIVOT_MIN_EXTREME (1.e-3 * VALEUR_DE_REGULARISATION) /*1.e-10*/ + +# define LINFINI_PI 1.e+80 + +# define MUK_MIN 0.0 /*1.e-12*/ /* 1.e-9 */ +# define MUK_MAX 1.e+20 /* Pas de limite (presque) */ /*1.e+9*/ + +# define TOLERANCE_ADMISSIBILITE_PAR_DEFAUT 1.e-5 /*1.e-6*/ +# define TOLERANCE_STATIONNARITE_PAR_DEFAUT 1.e-5 /*1.e-5*/ +# define TOLERANCE_COMPLEMENTARITE_PAR_DEFAUT 1.e-5 /*1.e-5*/ + +# define CONDITIONNEMENT_MIN 100. +# define CONDITIONNEMENT_MAX 1000. + +# define NOMBRE_MAX_DITERATION 300 /*200*/ + +# define INCREMENT_DALLOCATION 4096 + +# define AFFINE 1 +# define CENTRALISATION 2 + +#ifndef COMPACT + # define COMPACT 1 +#endif + +#ifndef CREUX + # define CREUX 2 +#endif + +# define BON 1 +# define APPROX 2 +# define PARFAIT 3 +# define RANGE 1.e+8 +# define RANGE_MIN 1.e+6 +# define RANGE_MAX 1.e+10 +# define SEUIL_PARFAIT 1.e-8 +# define SEUIL_APPROX 1.e-6 + +# define ITERATION_DEBUT_RAFINEMENT_ITERATIF 6 /* Il faut mettre un nombre pair */ + +typedef struct { +/* La matrice est rangee par colonne */ +int NombreDElementsAlloues; +double * Elm; +int * Indl; +int * Ideb; +int * Nonu; +int NombreDeColonnes; +/* Resultat de la factorisation: les triangles L et U */ +int NbElementsDeU; +/* Triangle U par Ligne */ +int * IndexDebutDesLignesDeU; +int * NbTermesDesLignesDeU; +double * ValeurDesTermesDeU; +double * ValeurDesTermesDeU_SV; +int * IndicesDeColonneDeU; +/* Emplacement du terme diagonal dans la factorisee */ +int * IndexDuTermeDiagonalDansU; +/* Table de travail utilisee pour les resolutions de systeme et les factorisations */ +double * Sec; +} MATRICE_PI; + + +typedef struct { +/* Pour les outils de gestion memoire */ +void * Tas; + +MATRICE_PI * MatricePi; + +int NombreDeVariables; +int NombreDeContraintes; +int NombreDeContraintesSV; +int * CorrespondanceVarEntreeVarPi; +int * CorrespondanceCntEntreeCntPi; + +/*-------------------------------------------------------------------------*/ +int AnomalieDetectee; +jmp_buf Env; +/*-------------------------------------------------------------------------*/ +/* Coefficients de la fonction objectifs et leur chainage */ +double * Q; +double * L; +double * Qpar2; /* c'est 2 * Q */ + +/* Chainage de la matrice des contraintes */ +int NbTermesAllouesPourA; +double * A; +double * B; +int * Mdeb; +int * NbTerm; +int * Indcol; + +/* Chainage de la matrice transposee des contraintes **/ +int * Cdeb; +int * CNbTerm; +double * ACol; +int * NumeroDeContrainte; +int * Csui; + +/* Chainage de la matrice A * AT par colonne */ +/*double * MoinsDMoins1; +int NbTermesAllouesPourAFoisATranspose; +int * CDebFormeNormale; +int * CNbTermFormeNormale; +int * LigneFormeNormale; +double * AFormeNormale; +*/ + +/* Les variables */ +double * U; +double * U0; +double * Umax; +double * Umin; +double * Alpha; /* Coeff de la matrice diagonale de changement de variable (utilite en test) */ +double * Alpha2; /* Alpha au carre */ +char * TypeDeVariable; /* Bornée, non bornée etc... */ +/* Pour la penalisation des contraintes de complementarite (norme l infini) */ +char * VariableBinaire; /* OUI_PI ou NON_PI */ +int NombreDeVariablesBinaires; +int * NumeroDeLaContrainteDeComplementarite; +double Rho; /* Coefficient de penalisation de la variable Xi */ +int NumeroDeLaVariableXi; +/* */ +double * S1; +double * S2; +double * Lambda; +double * Lambda0; + +/* Pour le scaling */ +double * ScaleU; +double * ScaleB; +double ScaleLigneDesCouts; +double ScaleLigneDesU; +char PrendreEnCompteLesCoutsLineairesDansLeScaling; + +/* Pour les iterations du calcul variables */ +double SeuilDOptimalite; +double SeuilDAdmissibilite; +double SeuilDeStationnarite; + +double Smin; +double G; +double Ro; + +double * DeltaU; +double * DeltaLambda; +double * DeltaS1; +double * DeltaS2; +double * UkMoinsUmin; +double * UmaxMoinsUk; +double * UnSurUkMoinsUmin; +double * UnSurUmaxMoinsUk; +double * DeltaUDeltaS1; +double * DeltaUDeltaS2; + +double * SecondMembre; +double * SecondMembreAffine; + +double Gamma; +char Resolution; +double Range; + +int ComplementariteAtteinte; +int RealisabiliteAtteinte; +int StationnariteAtteinte; +int NumeroDIteration; + +int TypeDIteration; +double Muk; +double * MukIteration; +double MukPrecedent; + +double * MaxOptimalite; +double * MaxContrainte; +double * MaxStationnarite; +double * IterationTetakP; +double * IterationTetakD; + +double * RegulVar; +double * RegulContrainte; + +int ArretSta; +int ArretCnt; +int ArretOpt; +int Traces; + +int YaUneSolution; + +void * MatriceFactorisee; +void * Matrice; /* C'est la matrice a factoriser */ + +} PROBLEME_PI; + +/*******************************************************************************************/ +# define DEFINITIONS_PROBLEME_PI_FAITES +# endif +# ifdef __cplusplus + } +# endif diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_definition_arguments.h b/src/ext/Sirius_Solver/pointInterieur/pi_definition_arguments.h new file mode 100644 index 0000000000..c2a39d2485 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_definition_arguments.h @@ -0,0 +1,121 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef PROBLEME_POINT_INTERIEUR_DEJA_DEFINI +/*******************************************************************************************/ +/* + Le passage des informations a la routine de resolution du point interieur se fait par un pointeur + a la structure C definie ci-apres. + + Le fichier pi_constantes_externes.h doit etre inclus dans le code de l'appelant. + Le fichier pi_definition_arguments.h doit etre inclus dans le code de l'appelant, + il contient la definition de la structure C exploitee par la fonction. + Apres avoir renseigne les champs, le module utilisateur appelle la fonction + PI_Quamin avec, pour argument d'appel, un pointeur a la structure ci-dessous. + + Exemple d'utilisation : + + PROBLEME_POINT_INTERIEUR Mon_Probleme; <- definition d'une structure "Mon_Probleme" de type PROBLEME_POINT_INTERIEUR + ....... + ....... + Remplissage des champs de la structure + ....... + ....... + ....... + Appel de la fonction: + + PI_Quamin( &Mon_Probleme ); Attention maintenant c'est comme pour le simplexe (pour marcher en multi threading) + +*/ + +typedef struct { + + double * CoutQuadratique; + double * CoutLineaire; + + double * X; + double * Xmin; + double * Xmax; + int NombreDeVariables; + int * TypeDeVariable; /* Indicateur du type de variable, il ne doit prendre que les suivantes + (voir le fichier pi_constantes_externes.h mais ne jamais utiliser les valeurs explicites + des constantes): + VARIABLE_FIXE , + VARIABLE_BORNEE_DES_DEUX_COTES , + VARIABLE_BORNEE_INFERIEUREMENT , + VARIABLE_BORNEE_SUPERIEUREMENT , + VARIABLE_NON_BORNEE */ + char * VariableBinaire; /* Vaut OUI_PI ou NON_PI */ + /* La matrice des contraintes */ + int NombreDeContraintes; /* Nombre de contraintes */ + int * IndicesDebutDeLigne; /* Pointeur sur le debut de chaque ligne de la matrice des contraintes */ + int * NombreDeTermesDesLignes; /* Nombre de termes non nuls de chaque ligne */ + int * IndicesColonnes; /* Indice colonne des termes de la matrice des contraintes. + Attention, les termes de la ligne doivent etre ranges dans l'ordre + croissant des indices de colonnes */ + double * CoefficientsDeLaMatriceDesContraintes; /* Les termes de la matrice des contraintes */ + + /* Le second membre */ + char * Sens; /* Sens de contrainte: '<' ou '>' ou '=' */ + double * SecondMembre; /* Valeurs de second membre */ + + /* Parametres de controle */ + int NombreMaxDIterations; /* Si < 0 , le point interieur prendre sa valeur par defaut */ + int AffichageDesTraces; /* Vaut OUI_PI ou NON_PI */ + + int UtiliserLaToleranceDAdmissibiliteParDefaut; + double ToleranceDAdmissibilite; + + int UtiliserLaToleranceDeStationnariteParDefaut; + double ToleranceDeStationnarite; + + int UtiliserLaToleranceDeComplementariteParDefaut; + double ToleranceDeComplementarite; + + /* Indicateur de deroulement (sortie) */ + int ExistenceDUneSolution; /* En sortie, vaut : + OUI_PI s'il y a une solution, + NON_PI si pas de solution trouvee + PI_ERREUR_INTERNE si probleme a l'execution (saturation memoire par exemple), et + dans ce cas il n'y a pas de solution + */ + + /* Variables duales (sortie) */ + double * CoutsMarginauxDesContraintes; + double * CoutsMarginauxDesContraintesDeBorneInf; + double * CoutsMarginauxDesContraintesDeBorneSup; + /* */ + +} PROBLEME_POINT_INTERIEUR; + + +/*******************************************************************************************/ +# define PROBLEME_POINT_INTERIEUR_DEJA_DEFINI +# endif +# ifdef __cplusplus + } +# endif + + + + + + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_fonctions.h b/src/ext/Sirius_Solver/pointInterieur/pi_fonctions.h new file mode 100644 index 0000000000..23086e1332 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_fonctions.h @@ -0,0 +1,117 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef FONCTIONS_PI_DEJA_DEFINIES +/*-----------------------------------------------------------------------------------------*/ + +# include "pi_definition_arguments.h" +# include "pi_define.h" + +void PI_AugmenterLaTailleDeLaMatrice( PROBLEME_PI * ); + +void PI_Cremat( PROBLEME_PI * ); + +void PI_Crebis( PROBLEME_PI * ); + +void PI_CrematSystemeAugmente( PROBLEME_PI * ); + +void PI_CrebisSystemeAugmente( PROBLEME_PI * ); + +void PI_Sos1s2( PROBLEME_PI * ); + +void PI_Calmuk( PROBLEME_PI * ); + +void PI_Calcent( PROBLEME_PI * ); + +void PI_Caldel( PROBLEME_PI * ); + +void PI_Calstaf( PROBLEME_PI * ); + +void PI_Incrementation( PROBLEME_PI * ); + +void PI_CalculDesTeta( PROBLEME_PI * , double * , double * ); + +void PI_InitXS( PROBLEME_PI * ); + +void PI_SplitColonnes( PROBLEME_PI * ); + +void PI_InverseDeMiseALEchelle( PROBLEME_PI * ); + +void PI_CalculerLeScaling( PROBLEME_PI * ); + +void PI_Scaling( PROBLEME_PI * ); + +void PI_ArrondiEnPuissanceDe2( double * ); + +void PI_UnScaling( PROBLEME_PI * ); + +void PI_RestitutionDesResultats( PROBLEME_PI * , int , double * , double * , double * , int , double * ); + +void PI_Joptimise( PROBLEME_PI * ); + +void PI_InitATransposee( PROBLEME_PI * , int ); + +void PI_Qinit( PROBLEME_PI *, double , int , double , int , double , int ); + +void PI_MdEqua( PROBLEME_PI * , int , double * , double * , double * , double * , + int * , char * , double * , int , int * , int * , + int * , double * , double * , char * ); + +void PI_MettreLaContrainteSousFormeStandard( PROBLEME_PI * , int ); + +void PI_SplitContraintes( PROBLEME_PI * ); + +void PI_AllocProbleme( PROBLEME_PI * , int , int , int * , char * , char * , int * ); + +void PI_LibereProbleme( PROBLEME_PI * ); + +void PI_AllocMatrice( PROBLEME_PI * ); + +void PI_InitMatriceLU( PROBLEME_PI * , int * , int * , double * , int * ); + +void PI_LibereMatrice( PROBLEME_PI * ); + +void PI_Resolution( PROBLEME_PI * ); + +void PI_ReconstruireLaMatriceDuSystemeAResoudre( PROBLEME_PI * Pi ); + +void PI_ResolutionSystemeAugmente( PROBLEME_PI * ); + +void PI_QuaminCalculs( PROBLEME_POINT_INTERIEUR * , PROBLEME_PI * ); + +void PI_Quamin( PROBLEME_POINT_INTERIEUR * ); + +/***********************************************************/ +double PI_Armijo( PROBLEME_PI * , double ); + +void PI_CalculDesVariables( PROBLEME_PI * , double , double * , double * , double * , double * ); + +double PI_CalculNormeSecondMembre( PROBLEME_PI * , double , double * , double * , double * , double * , double * ); + +double PI_CalculDeLaDeriveeDuCritereEnZero( PROBLEME_PI * , double , double * , double * , double * , double * , double * , double * ); + +void PI_GradientConjugue( PROBLEME_PI * ); + +/*-----------------------------------------------------------------------------------------*/ +# define FONCTIONS_PI_DEJA_DEFINIES +# endif +# ifdef __cplusplus + } +# endif diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_gradient_conjugue.c b/src/ext/Sirius_Solver/pointInterieur/pi_gradient_conjugue.c new file mode 100644 index 0000000000..d75dfe5bcc --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_gradient_conjugue.c @@ -0,0 +1,336 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Gradient conjugue pour affiner la resolution. + Le point initial est la resolution du systeme regularise + ou non. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# include "lu_constantes_externes.h" +# include "lu_definition_arguments.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pi_memoire.h" +# endif + +/*--------------------------------------------------------------------------------*/ + +void PI_GradientConjugue( PROBLEME_PI * Pi ) +{ +int ic; int icMax; int il; int ilMax; int Var; int Cnt; int i; double NormeGradientF; +int NombreDeVariables; int NombreDeContraintes; int Iteration; int IterationMax; + +int * Cdeb; int * CNbTerm; int * NumeroDeContrainte; +int * Mdeb; int * NbTerm; int * Indcol; +double * Dk; double * ADk; double * B; double * Xk; +double DktADk; double X; + +double GradientFtDk; double GradientFtADk; +double * GradientF; + +double tk; double Betak; +double * ACol; double * A; double * DeltaU; double * DeltaLambda; + +char * TypeDeVariable; double * Qpar2; double * UnSurUkMoinsUmin; double * UnSurUmaxMoinsUk; +double * S1; double * S2; double * RegulVar; double * RegulContrainte; double * U; double * U0; +double * Lambda; double * Lambda0; + +NombreDeVariables = Pi->NombreDeVariables; +NombreDeContraintes = Pi->NombreDeContraintes; + +TypeDeVariable = Pi->TypeDeVariable; +Qpar2 = Pi->Qpar2; +UnSurUkMoinsUmin = Pi->UnSurUkMoinsUmin; +UnSurUmaxMoinsUk = Pi->UnSurUmaxMoinsUk; +S1 = Pi->S1; +S2 = Pi->S2; + +U = Pi->U; +U0 = Pi->U0; +Lambda = Pi->Lambda; +Lambda0 = Pi->Lambda0; + +RegulVar = Pi->RegulVar; +RegulContrainte = Pi->RegulContrainte; + +Cdeb = Pi->Cdeb; +CNbTerm = Pi->CNbTerm; +ACol = Pi->ACol; +NumeroDeContrainte = Pi->NumeroDeContrainte; + +Mdeb = Pi->Mdeb; +NbTerm = Pi->NbTerm; +A = Pi->A; +Indcol = Pi->Indcol; + +DeltaU = Pi->DeltaU; +DeltaLambda = Pi->DeltaLambda; + +Dk = (double *) malloc( (NombreDeVariables + NombreDeContraintes ) * sizeof( double ) ); +ADk = (double *) malloc( (NombreDeVariables + NombreDeContraintes ) * sizeof( double ) ); +B = (double *) malloc( (NombreDeVariables + NombreDeContraintes ) * sizeof( double ) ); +Xk = (double *) malloc( (NombreDeVariables + NombreDeContraintes ) * sizeof( double ) ); + +GradientF = (double *) malloc( (NombreDeVariables + NombreDeContraintes ) * sizeof( double ) ); + +Iteration = 0; +IterationMax = 10; + +/* Initialiser B a partir de la sauvegarde du second membre qui a ete faite dans PI_ResolutionSystemeAugmente */ +memcpy( (char *) B, (char *) Pi->SecondMembreAffine, ( NombreDeVariables + NombreDeContraintes ) * sizeof( double ) ); + +/* On enleve le terme de regularisation */ +for ( i = 0 ; i < NombreDeVariables ; i++ ) { + B[i]+= RegulVar[i] * ( U[i] - U0[i] ); +} +for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + B[NombreDeVariables + i]+= RegulContrainte[i] * ( Lambda[i] - Lambda0[i] ); +} + + +/* Initialiser Xk a la solution du systeme */ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) Xk[Var] = DeltaU[Var]; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) Xk[NombreDeVariables + Cnt] = DeltaLambda[Cnt]; + +/* Initialiser Dk a la solution du systeme */ +/* Calcul de GradientFk */ +for ( i = 0 ; i < NombreDeVariables + NombreDeContraintes ; i++ ) GradientF[i] = -B[i]; + +for ( Var = 0 ; Var < NombreDeVariables; Var++ ) { + X = 0.0; + /* Partie Hessien */ + if ( TypeDeVariable[Var] == BORNEE ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ) + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ); + } + else if ( TypeDeVariable[Var] == BORNEE_SUPERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else if ( TypeDeVariable[Var] == NON_BORNEE ) { + X = Qpar2[Var]; + } + /* On ne met pas le terme de regularisation */ + + X*= Xk[Var]; + + /* Partie Contraintes */ + ic = Cdeb[Var]; + icMax = ic + CNbTerm[Var]; + while ( ic < icMax ) { + X+= ACol[ic] * Xk[NombreDeVariables+NumeroDeContrainte[ic]]; + ic++; + } + GradientF[Var]+= X; +} +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + X = 0.0; + + /* On ne met pas le terme de regularisation */ + + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + /* Partie contrainte */ + X+= A[il] * Xk[Indcol[il]]; + il++; + } + GradientF[NombreDeVariables+Cnt]+= X; +} + +NormeGradientF = 0.0; +for ( i = 0 ; i < NombreDeVariables + NombreDeContraintes ; i++ ) { + NormeGradientF+= GradientF[i] * GradientF[i]; +} +NormeGradientF = sqrt( NormeGradientF ); +printf("Norme du gradient %e\n",NormeGradientF); + +for ( i = 0 ; i < NombreDeVariables + NombreDeContraintes ; i++ ) Dk[i] = -GradientF[i]; + +NouvelleIteration: + +X = 0.0 ; +for ( i = 0 ; i < NombreDeVariables + NombreDeContraintes ; i++ ) { + X+= Dk[i] * Dk[i]; +} +printf(" Norme de Dk %e\n",sqrt(X)); + +/* Calcul de GradientFtDk */ +GradientFtDk = 0.0; +for ( i = 0 ; i < NombreDeVariables + NombreDeContraintes ; i++ ) { + GradientFtDk+= GradientF[i] * Dk[i]; +} +printf(" GradientFtDk %e\n",GradientFtDk); +/* Calcul de ADk */ +for ( Var = 0 ; Var < NombreDeVariables; Var++ ) { + X = 0.0; + /* Partie Hessien */ + if ( TypeDeVariable[Var] == BORNEE ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ) + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ); + } + else if ( TypeDeVariable[Var] == BORNEE_SUPERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else if ( TypeDeVariable[Var] == NON_BORNEE ) { + X = Qpar2[Var]; + } + /* On ne met pas le terme de regularisation */ + X*= Dk[Var]; + /* Partie Contraintes */ + ic = Cdeb[Var]; + icMax = ic + CNbTerm[Var]; + while ( ic < icMax ) { + X+= ACol[ic] * Dk[NombreDeVariables+NumeroDeContrainte[ic]]; + ic++; + } + ADk[Var] = X; +} +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + X = 0.0; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + /* Partie contrainte */ + X+= A[il] * Dk[Indcol[il]]; + il++; + } + ADk[NombreDeVariables+Cnt] = X; +} + +/* Calcul de DktADk */ +DktADk = 0.0; +for ( i = 0 ; i < NombreDeVariables + NombreDeContraintes ; i++ ) { + DktADk+= Dk[i] * ADk[i]; +} +printf(" DktADk %e\n",DktADk ); + +/* Calcul de tk */ +tk = -GradientFtDk / DktADk; +tk = 1.e-10/( 1 + ( Iteration * Iteration) ); +printf(" tk %e\n",tk ); + +/* Calcul de Xk a k+1 */ +for ( i = 0 ; i < NombreDeVariables + NombreDeContraintes ; i++ ) { + Xk[i]+= tk * Dk[i]; +} + +/* Calcul de GradientF k+1 */ +for ( i = 0 ; i < NombreDeVariables + NombreDeContraintes ; i++ ) GradientF[i] = -B[i]; +for ( Var = 0 ; Var < NombreDeVariables; Var++ ) { + X = 0.0; + /* Partie Hessien */ + if ( TypeDeVariable[Var] == BORNEE ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ) + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ); + } + else if ( TypeDeVariable[Var] == BORNEE_SUPERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else if ( TypeDeVariable[Var] == NON_BORNEE ) { + X = Qpar2[Var]; + } + + /* On ne met pas le terme de regularisation */ + + X*= Xk[Var]; + + /* Partie Contraintes */ + ic = Cdeb[Var]; + icMax = ic + CNbTerm[Var]; + while ( ic < icMax ) { + X+= ACol[ic] * Xk[NombreDeVariables+NumeroDeContrainte[ic]]; + ic++; + } + GradientF[Var]+= X; +} +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + X = 0.0; + + /* On ne met pas le terme de regularisation */ + + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + /* Partie contrainte */ + X+= A[il] * Xk[Indcol[il]]; + il++; + } + GradientF[NombreDeVariables+Cnt]+= X; +} + +NormeGradientF = 0.0; +for ( i = 0 ; i < NombreDeVariables + NombreDeContraintes ; i++ ) { + NormeGradientF+= GradientF[i] * GradientF[i]; +} +NormeGradientF = sqrt( NormeGradientF ); +printf("Norme du gradient %e\n",NormeGradientF); + +/* Calcul de GradientFkPlus1ADk */ +GradientFtADk = 0.0; +for ( i = 0 ; i < NombreDeVariables + NombreDeContraintes ; i++ ) { + GradientFtADk+= GradientF[i] * ADk[i]; +} +printf(" GradientFkPlus1ADk %e\n",GradientFtADk ); + +/* Calcul de Betak */ +Betak = GradientFtADk / DktADk; +Betak = 0.0; +printf(" Betak %e\n", Betak); + +/* Calcul de Dk a k+1 */ +for ( i = 0 ; i < NombreDeVariables + NombreDeContraintes ; i++ ) { + Dk[i] = -GradientF[i] + ( Betak * Dk[i] ); +} + +if ( Iteration < IterationMax ) { + Iteration++; + goto NouvelleIteration; +} + +exit(0); + +/* Recuperation du resultat */ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) DeltaU[Var] = Xk[Var]; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) DeltaLambda[Cnt] = Xk[NombreDeVariables + Cnt]; + +free( Dk ); +free( ADk ); +free( B ); +free( GradientF ); +free( Xk ); + +return; +} diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_incrementation.c b/src/ext/Sirius_Solver/pointInterieur/pi_incrementation.c new file mode 100644 index 0000000000..d398e8f52e --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_incrementation.c @@ -0,0 +1,330 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************************** + + FONCTION: Incrementation des variables + + PI_CalculDesTeta , PI_Incrementation + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +/*------------------------------------------------------------------------*/ +/* Calcul des pas primaux et duaux */ + +void PI_CalculDesTeta( PROBLEME_PI * Pi , double * TetakP , double * TetakD ) +{ +int i; +double Marge ; double Z ; double Sm; +double UmaxMoinsUkM; double UkMoinsUminM; double Xs; + +int NombreDeVariables; double * UmaxMoinsUk; double * UkMoinsUmin; +char * TypeDeVariable; double * DeltaU; double * S1; double * S2; +double * DeltaS1; double * DeltaS2; double Smin; + +NombreDeVariables = Pi->NombreDeVariables; + +UmaxMoinsUk = Pi->UmaxMoinsUk; +UkMoinsUmin =Pi->UkMoinsUmin; +TypeDeVariable = Pi->TypeDeVariable; +DeltaU = Pi->DeltaU; +S1 = Pi->S1; +S2 = Pi->S2; +DeltaS1 = Pi->DeltaS1; +DeltaS2 = Pi->DeltaS2; +Smin = Pi->Smin; + +*TetakP = 1.; *TetakD = 1.; Marge = ZERO; Z = 0.; + +for ( i = 0 ; i < NombreDeVariables ; i++ ) { + UmaxMoinsUkM = UmaxMoinsUk[i] - Marge; + if ( UmaxMoinsUkM < Z ) UmaxMoinsUkM = Z; + UkMoinsUminM = UkMoinsUmin[i] - Marge; + if ( UkMoinsUminM < Z ) UkMoinsUminM = Z; + + if ( TypeDeVariable[i] == BORNEE ) { + if ( DeltaU[i] >= UmaxMoinsUkM || -DeltaU[i] >= UkMoinsUminM ) { + if ( DeltaU[i] > ZERO ) { + Xs = UmaxMoinsUkM / DeltaU[i]; + if ( *TetakP > Xs ) *TetakP = Xs; + } + else if ( DeltaU[i] < -ZERO ) { + Xs = -UkMoinsUminM / DeltaU[i]; + if ( *TetakP > Xs ) *TetakP = Xs; + } + else DeltaU[i] = 0.; + } + } + else if ( TypeDeVariable[i] == BORNEE_INFERIEUREMENT ) { + if ( -DeltaU[i] >= UkMoinsUminM ) { + if ( DeltaU[i] < -ZERO ) { + Xs = -UkMoinsUminM / DeltaU[i]; + if ( *TetakP > Xs ) *TetakP = Xs; + } + else DeltaU[i] = 0.; + } + } + else if ( TypeDeVariable[i] == BORNEE_SUPERIEUREMENT ) { + if ( DeltaU[i] >= UmaxMoinsUkM ) { + if ( DeltaU[i] > ZERO ) { + Xs = UmaxMoinsUkM / DeltaU[i]; + if ( *TetakP > Xs ) *TetakP = Xs; + } + else DeltaU[i] = 0.; + } + } + /* Pas d'ecretement si non bornee */ + + /* Variable S1 */ + if ( TypeDeVariable[i] == BORNEE || TypeDeVariable[i] == BORNEE_INFERIEUREMENT ) { + Sm = S1[i] - Smin; + if ( Sm < Z ) Sm = Z; + if ( DeltaS1[i] <= -Sm ) { + Xs = -S1[i] / DeltaS1[i]; + if ( *TetakD > Xs ) *TetakD = Xs; + } + } + + /* Variable S2 */ + if ( TypeDeVariable[i] == BORNEE || TypeDeVariable[i] == BORNEE_SUPERIEUREMENT ) { + Sm = S2[i] - Smin; + if ( Sm < Z ) Sm = Z; + if ( DeltaS2[i] <= -Sm ) { + Xs = -S2[i] / DeltaS2[i]; + if ( *TetakD > Xs ) *TetakD = Xs; + } + } +} + +# if VERBOSE_PI + printf("Pas primal TetakP %e - pas dual TetakD %e\n",*TetakP,*TetakD); +# endif + +return; +} + +/*------------------------------------------------------------------------*/ +/* Incrementation des variables */ + +void PI_Incrementation( PROBLEME_PI * Pi ) +{ +int i; double TetakP; double TetakD; double CoeffP; double CoeffS; double CoeffL; +double X; char * TypeDeVariable; int NombreDeVariables; double * U; double X1; double X2; +double * U0; double Smin; double * DeltaU; double * S1; double * S2; double * DeltaS1; +double * DeltaS2; double * Umin; double * Umax; double * UkMoinsUmin; +double * UmaxMoinsUk; double * UnSurUkMoinsUmin; double * UnSurUmaxMoinsUk; +double * Lambda; double * Lambda0; double * DeltaLambda; char Type; +double AlphaK; double UnMoinsAlphaK; int NombreDeContraintes; +double InfDeVzerEtZero; double Div; double UnSurInfDeVzerEtZero; double Vm; +double Amin; double Amax; double Dx; double Dm; double * Alpha; double * Alpha2; + +PI_CalculDesTeta( Pi , &TetakP , &TetakD ); /* Calcul du pas primal et dual */ + +Pi->IterationTetakP[Pi->NumeroDIteration-1] = TetakP; +Pi->IterationTetakD[Pi->NumeroDIteration-1] = TetakD; + +CoeffP = Pi->Gamma * TetakP; +CoeffS = Pi->Gamma * TetakD; +CoeffL = CoeffS; + +NombreDeVariables = Pi->NombreDeVariables; +NombreDeContraintes = Pi->NombreDeContraintes; +TypeDeVariable = Pi->TypeDeVariable; +U = Pi->U; +U0 = Pi->U0; +DeltaU = Pi->DeltaU; +S1 = Pi->S1; +S2 = Pi->S2; +DeltaS1 = Pi->DeltaS1; +DeltaS2 = Pi->DeltaS2; +Alpha = Pi->Alpha; +Alpha2 = Pi->Alpha2; +Smin = Pi->Smin; +Umin = Pi->Umin; +Umax = Pi->Umax; +UkMoinsUmin = Pi->UkMoinsUmin; +UmaxMoinsUk = Pi->UmaxMoinsUk; +UnSurUkMoinsUmin = Pi->UnSurUkMoinsUmin; +UnSurUmaxMoinsUk = Pi->UnSurUmaxMoinsUk; + +InfDeVzerEtZero = VZER; +if ( InfDeVzerEtZero < ZERO ) InfDeVzerEtZero = ZERO; +UnSurInfDeVzerEtZero = 1. / InfDeVzerEtZero; + +/* Variables U, S1, S2 */ +AlphaK = 0.5; +UnMoinsAlphaK = 1. - AlphaK; +for ( i = 0 ; i < NombreDeVariables ; i++ ) { + U0[i] = U[i]; + U [i]+= DeltaU[i] * CoeffP; + U0[i] = ( AlphaK * U[i] ) + ( UnMoinsAlphaK * U0[i] ); + Type = TypeDeVariable[i]; + if ( Type == BORNEE ) { + if ( ( U[i] - Umin[i] ) > ZERO ) { + UkMoinsUmin[i] = U[i] - Umin[i]; + UnSurUkMoinsUmin[i] = 1. / UkMoinsUmin[i]; + } + else { + U[i] = Umin[i] + VZER; + UkMoinsUmin[i] = VZER; + UmaxMoinsUk[i] = Umax[i] - U[i]; + UnSurUkMoinsUmin[i] = UnSurInfDeVzerEtZero; + if ( UmaxMoinsUk[i] > ZERO ) Div = UmaxMoinsUk[i]; + else Div = ZERO; + UnSurUmaxMoinsUk[i] = 1. / Div; + } + if ( ( Umax[i] - U[i] ) > ZERO ) { + UmaxMoinsUk[i] = Umax[i] - U[i]; + UnSurUmaxMoinsUk[i] = 1. / UmaxMoinsUk[i]; + } + else { + U[i] = Umax[i] - VZER; + UkMoinsUmin[i] = U[i] - Umin[i]; + UmaxMoinsUk[i] = VZER; + UnSurUmaxMoinsUk[i] = UnSurInfDeVzerEtZero; + if ( UkMoinsUmin[i] > ZERO ) Div = UkMoinsUmin[i]; + else Div = ZERO; + UnSurUkMoinsUmin[i] = 1. / Div; + } + } + else if ( Type == BORNEE_INFERIEUREMENT ) { + if ( ( U[i] - Umin[i] ) > ZERO ) { + UkMoinsUmin[i] = U[i] - Umin[i]; + UnSurUkMoinsUmin[i] = 1. / UkMoinsUmin[i]; + } + else { + U[i] = Umin[i] + VZER; + UkMoinsUmin[i] = VZER; + UnSurUkMoinsUmin[i] = UnSurInfDeVzerEtZero; + } + } + else if ( Type == BORNEE_SUPERIEUREMENT ) { + if ( ( Umax[i] - U[i] ) > ZERO ) { + UmaxMoinsUk[i] = Umax[i] - U[i]; + UnSurUmaxMoinsUk[i] = 1. / UmaxMoinsUk[i]; + } + else { + U[i] = Umax[i] - VZER; + UmaxMoinsUk[i] = VZER; + UnSurUmaxMoinsUk[i] = UnSurInfDeVzerEtZero; + } + } +} + +for ( i = 0 ; i < NombreDeVariables ; i++ ) { + Type = TypeDeVariable[i]; + if ( Type == BORNEE ) { + S1[i]+= DeltaS1[i] * CoeffS; + S2[i]+= DeltaS2[i] * CoeffS; + if ( S1[i] < Smin ) S1[i] = Smin; + if ( S2[i] < Smin ) S2[i] = Smin; + + } + else if ( Type == BORNEE_INFERIEUREMENT ) { + S1[i]+= DeltaS1[i] * CoeffS; + if ( S1[i] < Smin ) S1[i] = Smin; + } + else if ( Type == BORNEE_SUPERIEUREMENT ) { + S2[i]+= DeltaS2[i] * CoeffS; + if ( S2[i] < Smin ) S2[i] = Smin; + } +} + +/* Variables Lambda */ +Lambda = Pi->Lambda; +Lambda0 = Pi->Lambda0; +DeltaLambda = Pi->DeltaLambda; + +AlphaK = 0.5; +UnMoinsAlphaK = 1. - AlphaK; + +for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + Lambda0[i] = Lambda[i]; + Lambda[i]+= CoeffL * DeltaLambda[i]; + Lambda0[i] = ( AlphaK * Lambda[i] ) + ( UnMoinsAlphaK * Lambda0[i] ); +} + +Amin = 1.e-10; +Amax = 1.e+3; +Vm = 1.; + +Dx = -1.0; +Dm = LINFINI_PI; + +for ( i = 0 ; i < NombreDeVariables ; i++ ) { + Type = TypeDeVariable[i]; + X = 1; + X1 = S1[i] * UnSurUkMoinsUmin[i]; + X2 = S2[i] * UnSurUmaxMoinsUk[i]; + if ( Type == BORNEE_INFERIEUREMENT ) { + if ( X1 < Vm ) X = U[i] - Umin[i]; + } + else if ( Type == BORNEE_SUPERIEUREMENT ) { + if ( X2 < Vm ) X = Umax[i] - U[i]; + } + + if ( X > Amax ) X = Amax; + if ( X < Amin ) X = Amin; + + Alpha[i] = X; + Alpha2[i] = X * X; + + X = X1 + X2; + X*= Alpha2[i]; + if ( X > Dx ) Dx = X; + if ( X < Dm ) Dm = X; + +} + +if ( Pi->Resolution == PARFAIT ) Pi->Range*= 2.; +else if ( Pi->Resolution == APPROX ) Pi->Range/= 2.; + +if ( Pi->Range < RANGE_MIN ) Pi->Range = RANGE_MIN; +else if ( Pi->Range > RANGE_MAX ) Pi->Range = RANGE_MAX; + +#if VERBOSE_PI + printf (" Dm = %e Dx = %e Range = %e\n",Dm,Dx,Pi->Range); +#endif + +if ( Dx - Dm > Pi->Range && Pi->NumeroDIteration >= ITERATION_DEBUT_RAFINEMENT_ITERATIF ) { + X = sqrt( Pi->Range / ( Dx - Dm ) ); + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + Alpha[i]*= X; + Alpha2[i]*= X * X; + } +} + +return; +} + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_init_transposee.c b/src/ext/Sirius_Solver/pointInterieur/pi_init_transposee.c new file mode 100644 index 0000000000..0ee8617ad1 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_init_transposee.c @@ -0,0 +1,106 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************************** + + FONCTION: Chainage des termes de la transposee des contraintes + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pi_memoire.h" +# endif + +/*------------------------------------------------------------------------*/ +/* Chainage des termes de la transposee des contraintes */ + +void PI_InitATransposee( PROBLEME_PI * Pi , int TypeChainage ) +{ +int Var ; int Cnt ; int il; int ilk; int ilMax; int Colonne; +int * Cder; int * Csui; int * NumeroDeContrainte ; int ilC; + +Cder = (int *) malloc( Pi->NombreDeVariables * sizeof( int ) ); +NumeroDeContrainte = (int *) malloc( Pi->NbTermesAllouesPourA * sizeof( int ) ); +Csui = (int *) malloc( Pi->NbTermesAllouesPourA * sizeof( int ) ); +if ( Cder == NULL || NumeroDeContrainte == NULL || Csui == NULL ) { + printf(" Point interieur, memoire insuffisante dans le sous programme PI_InitATransposee \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +for ( Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) Pi->Cdeb[Var] = -1; + +for ( Cnt = 0 ; Cnt < Pi->NombreDeContraintes ; Cnt++ ) { + il = Pi->Mdeb[Cnt]; + ilMax = il + Pi->NbTerm[Cnt]; + while ( il < ilMax ) { + Colonne = Pi->Indcol[il]; + if ( Pi->Cdeb[Colonne] < 0 ) { + Pi->Cdeb[Colonne] = il; + NumeroDeContrainte[il] = Cnt; + Csui[il] = -1; + Cder[Colonne] = il; + } + else { + ilk = Cder[Colonne]; + Csui[ilk] = il; + NumeroDeContrainte[il] = Cnt; + Csui[il] = -1; + Cder[Colonne] = il; + } + il++; + } +} + +if ( TypeChainage == COMPACT ) { + /* Attention Cdeb devient temporairement Cder */ + memcpy( (char *) Cder , (char *) Pi->Cdeb , Pi->NombreDeVariables * sizeof( int ) ); + + for ( ilC = 0 , Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) { + Pi->Cdeb [Var] = ilC; + Pi->CNbTerm[Var] = 0; + il = Cder[Var]; + while ( il >= 0 ) { + Pi->ACol [ilC] = Pi->A[il]; + Pi->NumeroDeContrainte[ilC] = NumeroDeContrainte[il]; + Pi->CNbTerm[Var]++; + ilC++; + il = Csui[il]; + } + } +} +else { + memcpy( (char *) Pi->NumeroDeContrainte , (char *) NumeroDeContrainte , Pi->NbTermesAllouesPourA * sizeof( int ) ); + memcpy( (char *) Pi->Csui , (char *) Csui , Pi->NbTermesAllouesPourA * sizeof( int ) ); +} + +free( Cder ); +free( NumeroDeContrainte ); +free( Csui ); +Cder = NULL; +NumeroDeContrainte = NULL; +Csui = NULL; + +return; +} + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_initxs.c b/src/ext/Sirius_Solver/pointInterieur/pi_initxs.c new file mode 100644 index 0000000000..122e7142da --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_initxs.c @@ -0,0 +1,71 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************************** + + FONCTION: + + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +/*------------------------------------------------------------------------*/ +/* Initialisation des variables */ + +void PI_InitXS( PROBLEME_PI * Pi ) +{ +int Var; double Div; + +for ( Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) { + + Pi->Qpar2[Var] = 2. * Pi->Q[Var]; + + Pi->UkMoinsUmin[Var] = Pi->U[Var] - Pi->Umin[Var]; + Pi->UmaxMoinsUk[Var] = Pi->Umax[Var] - Pi->U[Var]; + + Div = Pi->UkMoinsUmin[Var]; + if ( Div < ZERO ) Div = ZERO; + Pi->UnSurUkMoinsUmin[Var] = 1. / Div; + Div = Pi->UmaxMoinsUk[Var]; + if ( Div < ZERO ) Div = ZERO; + Pi->UnSurUmaxMoinsUk[Var] = 1. / Div; + + if ( Pi->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + Pi->UnSurUmaxMoinsUk[Var] = 0.; + Pi->UmaxMoinsUk [Var] = 0.; + } + else if ( Pi->TypeDeVariable[Var] == BORNEE_SUPERIEUREMENT ) { + Pi->UnSurUkMoinsUmin[Var] = 0.; + Pi->UkMoinsUmin [Var] = 0.; + } + else if ( Pi->TypeDeVariable[Var] == NON_BORNEE ) { + Pi->UnSurUkMoinsUmin[Var] = 0.; + Pi->UnSurUmaxMoinsUk[Var] = 0.; + Pi->UkMoinsUmin [Var] = 0.; + Pi->UmaxMoinsUk [Var] = 0.; + } + +} + +return; +} + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_md_equa.c b/src/ext/Sirius_Solver/pointInterieur/pi_md_equa.c new file mode 100644 index 0000000000..a760e19f7c --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_md_equa.c @@ -0,0 +1,339 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/*********************************************************************************** + + FONCTION: + + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +/*------------------------------------------------------------------------*/ +/* Initialisation */ + +void PI_MdEqua( PROBLEME_PI * Pi, + int NombreDeVariables_E, + double * Q_E, + double * L_E, + double * Umin_E, + double * Umax_E, + int * TypeVar_E, + char * VariableBinaire_E, + double * U_E, + int NombreDeContraintes_E, + int * Mdeb_E, + int * Nbter_E, + int * Nuvar_E, + double * A_E, + double * B_E, + char * Sens_E ) +{ +int i ; int iq; int iqMax; int VarPi ; int VarPi2; int iqt; int OkInit; +int jqNew; double SecondMembre ; double Coeff; int CntPi ; + +Pi->ScaleLigneDesCouts = 1.; +Pi->ScaleLigneDesU = 1.; + +/* Decompte des variables */ +Pi->NombreDeVariables = 0; +Pi->NombreDeVariablesBinaires = 0; +for ( i = 0 ; i < NombreDeVariables_E ; i++ ) { + if ( TypeVar_E[i] == VARIABLE_FIXE ) { + /* La variable est fixe, on suppose que la valeur est donnee dans U_E */ + Pi->CorrespondanceVarEntreeVarPi[i] = -1; + continue; + } + else { + Pi->Q [Pi->NombreDeVariables] = Q_E[i]; + Pi->L [Pi->NombreDeVariables] = L_E[i]; + Pi->Umin [Pi->NombreDeVariables] = Umin_E[i]; + Pi->Umax [Pi->NombreDeVariables] = Umax_E[i]; + Pi->U [Pi->NombreDeVariables] = U_E[i]; + Pi->ScaleU[Pi->NombreDeVariables] = 1.; + /* */ + Pi->CorrespondanceVarEntreeVarPi[i] = Pi->NombreDeVariables; + /* */ + if ( TypeVar_E[i] == VARIABLE_BORNEE_DES_DEUX_COTES ) Pi->TypeDeVariable[Pi->NombreDeVariables] = BORNEE; + else if ( TypeVar_E[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Pi->TypeDeVariable[Pi->NombreDeVariables] = BORNEE_INFERIEUREMENT; + Pi->Umax [Pi->NombreDeVariables] = LINFINI_PI; + } + else if ( TypeVar_E[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Pi->TypeDeVariable[Pi->NombreDeVariables] = BORNEE_SUPERIEUREMENT; + Pi->Umin [Pi->NombreDeVariables] = -LINFINI_PI; + } + else if ( TypeVar_E[i] == VARIABLE_NON_BORNEE ) { + Pi->TypeDeVariable[Pi->NombreDeVariables] = NON_BORNEE; + Pi->Umin [Pi->NombreDeVariables] = -LINFINI_PI; + Pi->Umax [Pi->NombreDeVariables] = LINFINI_PI; + } + else { + printf("Erreur entree du solveur: le seul type de variables reconnues est: \n"); + printf(" VARIABLE_FIXE -> valeur de constante: %d\n",VARIABLE_FIXE); + printf(" VARIABLE_BORNEE_DES_DEUX_COTES -> valeur de constante: %d\n",VARIABLE_BORNEE_DES_DEUX_COTES); + printf(" VARIABLE_BORNEE_INFERIEUREMENT -> valeur de constante: %d\n",VARIABLE_BORNEE_INFERIEUREMENT); + printf(" VARIABLE_BORNEE_SUPERIEUREMENT -> valeur de constante: %d\n",VARIABLE_BORNEE_SUPERIEUREMENT); + printf(" VARIABLE_NON_BORNEE -> valeur de constante: %d\n",VARIABLE_NON_BORNEE); + printf("Or la variable %i est du type %d => exit volontaire car pb de mise au point\n",i,TypeVar_E[i]); + exit(0); + } + Pi->VariableBinaire[Pi->NombreDeVariables] = NON_PI; + if ( MPCC == OUI_PI ) { + if ( VariableBinaire_E[i] == OUI_PI ) { + Pi->VariableBinaire[Pi->NombreDeVariables] = OUI_PI; + Pi->NombreDeVariablesBinaires++; + } + } + Pi->NombreDeVariables++; + } +} +/* +printf("Pi->NombreDeVariablesBinaires %d\n",Pi->NombreDeVariablesBinaires); +*/ +/* Second membre et contraintes */ +Pi->NombreDeContraintes = 0; +iqt = 0; +for ( i = 0 ; i < NombreDeContraintes_E ; i++ ) { + Pi->CorrespondanceCntEntreeCntPi[i] = -1; + Coeff = 1.; + if ( Sens_E[i] == '>' ) Coeff = -1.; /* Pour transformer en < */ + SecondMembre = 0.; + OkInit = NON_PI; + iq = Mdeb_E[i]; + iqMax = iq + Nbter_E[i]; + while ( iq < iqMax ) { + VarPi = Pi->CorrespondanceVarEntreeVarPi[Nuvar_E[iq]] ; + if ( VarPi >= 0 ) { + if ( OkInit == NON_PI ) { + Pi->Mdeb [Pi->NombreDeContraintes] = iqt; + Pi->NbTerm[Pi->NombreDeContraintes] = 0; + OkInit = OUI_PI; + } + Pi->NbTerm[Pi->NombreDeContraintes]++; + Pi->A [iqt] = Coeff * A_E[iq]; + Pi->Indcol[iqt] = VarPi; + iqt++; + } + else { + /* La variable est fixee => on modifie le second membre */ + SecondMembre+= A_E[iq] * U_E[Nuvar_E[iq]]; + } + iq++; + } + if ( OkInit == OUI_PI ) { + /* Dans le cas des contraintes d'inegalite il va y avoir la variable + d'ecart */ + if ( Sens_E[i] != '=' ) iqt++; + Pi->B [Pi->NombreDeContraintes] = Coeff * ( B_E[i] - SecondMembre ); + Pi->ScaleB[Pi->NombreDeContraintes] = 1.; + Pi->CorrespondanceCntEntreeCntPi[i] = Pi->NombreDeContraintes; + Pi->NombreDeContraintes++; + } +} + +/* Scaling du probleme avant sa mise sous forme standard (on le fait ici pour eviter + de faire un scaling sur les variables additionnelles de mise sous forme standard) */ +/* attention, faire en 2 temps comme dans le simplexe */ +PI_InitATransposee( Pi , CREUX ); +PI_CalculerLeScaling( Pi ); +PI_Scaling( Pi ); + +/* Mise du probleme sous la forme standard */ +for ( i = 0 ; i < NombreDeContraintes_E ; i++ ) { + if ( Sens_E[i] == '=' ) continue; + CntPi = Pi->CorrespondanceCntEntreeCntPi[i]; + PI_MettreLaContrainteSousFormeStandard( Pi , CntPi ); + if ( Pi->YaUneSolution == NON_PI ) return; +} + +/* Cas MPCC */ +Pi->Rho = 0.0; +if ( MPCC == OUI_PI && Pi->NombreDeVariablesBinaires > 0 ) { + + { double MxC; + MxC = -1.0; + for ( i = 0 ; i < Pi->NombreDeVariables ; i++ ) { + if ( fabs( Pi->L[i] ) > MxC ) MxC = fabs( Pi->L[i] ); + } + printf("Plus grand cout lineaire: %e\n",MxC); + Pi->Rho = 1. * MxC; + } + + /* Creation de la variable Xi */ + Pi->Q [Pi->NombreDeVariables] = 0.0; + Pi->L [Pi->NombreDeVariables] = Pi->Rho; + Pi->Umin [Pi->NombreDeVariables] = 0.0; + Pi->Umax [Pi->NombreDeVariables] = LINFINI_PI; + Pi->U [Pi->NombreDeVariables] = 1.; + Pi->ScaleU[Pi->NombreDeVariables] = 1.; + Pi->TypeDeVariable [Pi->NombreDeVariables] = BORNEE_INFERIEUREMENT; + Pi->VariableBinaire[Pi->NombreDeVariables] = NON_PI; + Pi->NumeroDeLaVariableXi = Pi->NombreDeVariables; + Pi->NombreDeVariables++; + + /* Creation de la ligne de A correspondant a d'inegalite x(1-x) < Xi */ + /* Normalement il faut mettre 1-2x, a ce stade ca n'a pas d'importance */ + iqt = Pi->Mdeb[Pi->NombreDeContraintes-1] + Pi->NbTerm[Pi->NombreDeContraintes-1]; /* Car deja standard */ + for ( i = 0 ; i < Pi->NombreDeVariables ; i++ ) { + if ( Pi->VariableBinaire[i] == OUI_PI ) { + printf("VARIABLE BINAIRE %d Umax = %e\n",i,Pi->Umax[i]); + Pi->NumeroDeLaContrainteDeComplementarite[i] = Pi->NombreDeContraintes; + Pi->Mdeb [Pi->NombreDeContraintes] = iqt; + Pi->NbTerm[Pi->NombreDeContraintes] = 0; + Pi->A [iqt] = 1; + Pi->Indcol[iqt] = i; + Pi->NbTerm[Pi->NombreDeContraintes]++; + iqt++; + /* Variable Xi */ + Pi->A [iqt] = -1; + Pi->Indcol[iqt] = Pi->NumeroDeLaVariableXi; + Pi->NbTerm[Pi->NombreDeContraintes]++; + iqt++; + Pi->B [Pi->NombreDeContraintes] = 0.0; + Pi->ScaleB[Pi->NombreDeContraintes] = 1.; + Pi->NombreDeContraintes++; + iqt++; /* On laisse une place pour la variable d'ecart */ + } + } + for ( i = 0 ; i < Pi->NombreDeVariables ; i++ ) { + if ( Pi->VariableBinaire[i] == OUI_PI ) { + CntPi = Pi->NumeroDeLaContrainteDeComplementarite[i]; + PI_MettreLaContrainteSousFormeStandard( Pi , CntPi ); + if ( Pi->YaUneSolution == NON_PI ) return; + } + } +} + +memset( (char *) Pi->RegulVar , 0 , Pi->NombreDeVariables * sizeof( double ) ); +memset( (char *) Pi->RegulContrainte , 0 , Pi->NombreDeContraintes * sizeof( double ) ); + +for ( i = 0 ; i < Pi->NombreDeVariables ; i++ ) Pi->Alpha[i] = 1.0; + +#if VERBOSE_PI + printf("Nombre de variables du probleme %d\n",Pi->NombreDeVariables); +#endif +{int NbBor; int NbBorInf; int NbBorSup; int NbNonBor; + NbBor=0;NbBorInf=0;NbBorSup=0;NbNonBor=0; + for ( i = 0 ; i < Pi->NombreDeVariables ; i++ ) { + if ( Pi->TypeDeVariable[i] == BORNEE ) NbBor++; + else if ( Pi->TypeDeVariable[i] == BORNEE_INFERIEUREMENT ) NbBorInf++; + else if ( Pi->TypeDeVariable[i] == BORNEE_SUPERIEUREMENT ) NbBorSup++; + else if ( Pi->TypeDeVariable[i] == NON_BORNEE ) { + NbNonBor++; + } + } + #if VERBOSE_PI + printf(" Nombre de variables BORNEE : %d\n",NbBor); + printf(" Nombre de variables BORNEE_INFERIEUREMENT : %d\n",NbBorInf); + printf(" Nombre de variables BORNEE_SUPERIEUREMENT : %d\n",NbBorSup); + printf(" Nombre de variables NON_BORNEE : %d\n",NbNonBor); + #endif +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* A ce stade, les contraintes d'inegalite sont toujours de signe < + et la place pour la variable d'ecart a deja ete reservee */ + +void PI_MettreLaContrainteSousFormeStandard( PROBLEME_PI * Pi , int Cnt ) +{ +int il; int ilMax; int Var; double Smin; char OnBorneDesDeuxCotes; double Seuil; + +OnBorneDesDeuxCotes = NON_PI; + +il = Pi->Mdeb[Cnt]; +ilMax = il + Pi->NbTerm[Cnt]; +Smin = 0.; +while ( il < ilMax) { + Var = Pi->Indcol[il]; + if ( Pi->A[il] <= 0. ) { + if ( Pi->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT || Pi->TypeDeVariable[Var] == NON_BORNEE ) { + OnBorneDesDeuxCotes = NON_PI; + goto CreationDeLaVariableDEcart; + } + Smin+= Pi->A[il] * Pi->Umax[Var]; + } + else { + if ( Pi->TypeDeVariable[Var] == NON_BORNEE ) { + OnBorneDesDeuxCotes = NON_PI; + goto CreationDeLaVariableDEcart; + } + Smin+= Pi->A[il] * Pi->Umin[Var]; + } + il++; +} + +if ( Smin > ( Pi->B[Cnt] + Pi->SeuilDAdmissibilite) ) { + #if VERBOSE_PI + printf("Point interieur: impossible de satisfaire la contrainte d'inegalite %d car Smin = %lf B = %lf \n",Cnt,Smin,Pi->B[Cnt]); + #endif + Pi->YaUneSolution = NON_PI; + return; +} + +CreationDeLaVariableDEcart: + +/* Creation de la variable d'ecart */ +Pi->Umin [Pi->NombreDeVariables] = 0.; +Pi->U [Pi->NombreDeVariables] = 0.; +Pi->Q [Pi->NombreDeVariables] = 0.; +Pi->L [Pi->NombreDeVariables] = 0.; +Pi->Umax [Pi->NombreDeVariables] = LINFINI_PI; +Pi->ScaleU[Pi->NombreDeVariables] = 1.; + +Pi->TypeDeVariable [Pi->NombreDeVariables] = BORNEE_INFERIEUREMENT; + +Pi->VariableBinaire[Pi->NombreDeVariables] = NON_PI; + +if ( OnBorneDesDeuxCotes == OUI_PI ) { + Pi->Umax[Pi->NombreDeVariables] = Pi->B[Cnt] - Smin + 1.; + Pi->TypeDeVariable[Pi->NombreDeVariables] = BORNEE; + if ( Pi->Umax[Pi->NombreDeVariables] > 1.e+15 ) { + Pi->Umax [Pi->NombreDeVariables] = LINFINI_PI; + Pi->TypeDeVariable[Pi->NombreDeVariables] = BORNEE_INFERIEUREMENT; + printf("creation d'une variable d'ecart non bornee superieurement \n"); + exit(0); /* temporaire, a enlever */ + } + else { + /*printf("creation d'une variable d'ecart bornee des 2 cotes \n");*/ + } +} +else { + /*printf("creation d'une variable d'ecart non bornee superieurement \n");*/ +} + +/* On la met dans l'équation de la contrainte */ +il = Pi->Mdeb[Cnt] + Pi->NbTerm[Cnt]; /* On a deja reserve la place de cette variable a la creation du probleme */ +Pi->NbTerm[Cnt]++; +Pi->Indcol[il] = Pi->NombreDeVariables; +Pi->A [il] = 1.; + +/* Incrementation du nombre de variables */ +Pi->NombreDeVariables++; + +return; +} + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_memoire.h b/src/ext/Sirius_Solver/pointInterieur/pi_memoire.h new file mode 100644 index 0000000000..dc90517a84 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_memoire.h @@ -0,0 +1,34 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef PI_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# include "mem_fonctions.h" +/***************************************************************** + + + Macros pour redefinir les primitives de gestion memoire lorsqu'on + ne veut pas utiliser celles de lib de l'OS + + +*****************************************************************/ + +# define malloc(Taille) MEM_Malloc(Pi->Tas,Taille) +# define free(Pointeur) MEM_Free(Pointeur) +# define realloc(Pointeur,Taille) MEM_Realloc(Pi->Tas,Pointeur,Taille) + +/*****************************************************************/ +# define PI_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# endif diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_qinit.c b/src/ext/Sirius_Solver/pointInterieur/pi_qinit.c new file mode 100644 index 0000000000..f0a5262b54 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_qinit.c @@ -0,0 +1,174 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************************** + + FONCTION: Initialisations + + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# define VALEUR_MIN_POUR_S 1.e+1 +# define VALEUR_MAX_POUR_S 1.e+3 +# define ECART_U 1.e+3 + +/*------------------------------------------------------------------------*/ +/* Initialisation */ + +void PI_Qinit( PROBLEME_PI * Pi , + double ToleranceAdmissibilite_E , + int ChoixToleranceAdmissibiliteParDefaut, + double ToleranceStationnarite_E , + int ChoixToleranceStationnariteParDefaut, + double ToleranceComplementarite_E , + int ChoixToleranceComplementariteParDefaut ) +{ +int i ; double TestBornes; int NbBor; int NbBorInf; int NbBorSup; +double X; int NbDiv ; int Cnt ; + +NbBor = 0; +NbBorInf = 0; +NbBorSup = 0; +for ( i = 0 ; i < Pi->NombreDeVariables ; i++ ) { + if ( Pi->TypeDeVariable[i] == BORNEE ) NbBor++; + else if ( Pi->TypeDeVariable[i] == BORNEE_INFERIEUREMENT ) NbBorInf++; + else if ( Pi->TypeDeVariable[i] == BORNEE_SUPERIEUREMENT ) NbBorSup++; +} + +NbDiv = ( ( 2. * NbBor) + NbBorInf + NbBorSup ); +if ( NbDiv != 0 ) { + Pi->Ro = 1. / (double) NbDiv; +} +else Pi->Ro = 1.0; + +if ( ChoixToleranceAdmissibiliteParDefaut != OUI_PI && + ChoixToleranceAdmissibiliteParDefaut != NON_PI ) { + printf(" Point interieur, fournir un type de tolerance pour l admissibilite \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} +if ( ChoixToleranceStationnariteParDefaut != OUI_PI && + ChoixToleranceStationnariteParDefaut != NON_PI ) { + printf(" Point interieur, fournir un type de tolerance pour la stationnarite \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} +if ( ChoixToleranceComplementariteParDefaut != OUI_PI && + ChoixToleranceComplementariteParDefaut != NON_PI ) { + printf(" Point interieur, fournir un type de tolerance pour la complementarite \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} + +if ( ChoixToleranceAdmissibiliteParDefaut == OUI_PI ) { + Pi->SeuilDAdmissibilite = TOLERANCE_ADMISSIBILITE_PAR_DEFAUT; +} +else { + Pi->SeuilDAdmissibilite =ToleranceAdmissibilite_E; +} + +if ( ChoixToleranceStationnariteParDefaut == OUI_PI ) { + Pi->SeuilDeStationnarite = TOLERANCE_STATIONNARITE_PAR_DEFAUT; +} +else { + Pi->SeuilDeStationnarite = ToleranceStationnarite_E; +} + +if ( ChoixToleranceComplementariteParDefaut == OUI_PI ) { + Pi->SeuilDOptimalite = TOLERANCE_COMPLEMENTARITE_PAR_DEFAUT; +} +else { + Pi->SeuilDOptimalite = ToleranceComplementarite_E; +} + +Pi->Smin = 0.0; + +Pi->Resolution = BON; +Pi->Range = RANGE; + +memset( (char *) Pi->DeltaUDeltaS1 , 0 , Pi->NombreDeVariables * sizeof( double ) ); +memset( (char *) Pi->DeltaUDeltaS2 , 0 , Pi->NombreDeVariables * sizeof( double ) ); +memset( (char *) Pi->Lambda , 0 , Pi->NombreDeContraintes * sizeof( double ) ); +memset( (char *) Pi->Lambda0 , 0 , Pi->NombreDeContraintes * sizeof( double ) ); + +memset( (char *) Pi->RegulVar , 0 , Pi->NombreDeVariables * sizeof( double ) ); +memset( (char *) Pi->RegulContrainte , 0 , Pi->NombreDeContraintes * sizeof( double ) ); + +TestBornes = 1.e-8; +for ( i = 0 ; i < Pi->NombreDeVariables ; i++ ) { + if ( Pi->TypeDeVariable[i] == BORNEE ) { + if ( ( Pi->Umax[i] - Pi->Umin[i] ) < TestBornes ) { + printf(" Point interieur, borne min = borne max sur la variables %d \n", i); + printf(" borne min = %lf borne max = %lf \n", Pi->Umin[i], Pi->Umax[i]); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); + } + + /*Pi->U[i] = 0.5 * ( Pi->Umax[i] + Pi->Umin[i] );*/ + /* On prend le plus petit entre X/2 et racine carrée de X */ + X = Pi->Umax[i] - Pi->Umin[i]; + if ( X > 4. ) Pi->U[i] = Pi->Umin[i] + sqrt( X ); + else Pi->U[i] = Pi->Umin[i] + ( 0.5 * X ); + + X = fabs( Pi->L[i] ); + if ( X >= VALEUR_MIN_POUR_S && X <= VALEUR_MAX_POUR_S ) { + Pi->S1[i] = X; + Pi->S2[i] = X; + } + else if ( X < VALEUR_MIN_POUR_S ) { + Pi->S1[i] = VALEUR_MIN_POUR_S; + Pi->S2[i] = VALEUR_MIN_POUR_S; + } + else { + Pi->S1[i] = VALEUR_MAX_POUR_S; + Pi->S2[i] = VALEUR_MAX_POUR_S; + } + } + else if ( Pi->TypeDeVariable[i] == BORNEE_INFERIEUREMENT ) { + Pi->U[i] = Pi->Umin[i] + ECART_U; + X = fabs( Pi->L[i] ); + if ( X >= VALEUR_MIN_POUR_S && X <= VALEUR_MAX_POUR_S ) Pi->S1[i] = X; + else if ( X < VALEUR_MIN_POUR_S ) Pi->S1[i] = VALEUR_MIN_POUR_S; + else Pi->S1[i] = VALEUR_MAX_POUR_S; + Pi->S2[i] = 0.; + } + else if ( Pi->TypeDeVariable[i] == BORNEE_SUPERIEUREMENT ) { + Pi->U[i] = Pi->Umax[i] - ECART_U; + Pi->S1[i] = 0.; + X = fabs( Pi->L[i] ); + if ( X >= VALEUR_MIN_POUR_S && X <= VALEUR_MAX_POUR_S ) Pi->S2[i] = X; + else if ( X < VALEUR_MIN_POUR_S ) Pi->S2[i] = VALEUR_MIN_POUR_S; + else Pi->S2[i] = VALEUR_MAX_POUR_S; + } + else if ( Pi->TypeDeVariable[i] == NON_BORNEE ) { + Pi->U[i] = 0.; + Pi->S1[i] = 0.; + Pi->S2[i] = 0.; + } + else printf("Bug dans le point interieur, type de variable %d non reconnu\n",i); +} + +memcpy( (char *) Pi->U0 , (char *) Pi->U , Pi->NombreDeVariables * sizeof( double ) ); + +return; +} diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_quamin.c b/src/ext/Sirius_Solver/pointInterieur/pi_quamin.c new file mode 100644 index 0000000000..94f581b164 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_quamin.c @@ -0,0 +1,93 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Routine principale du point interieur. Cette implementation + du point interieur est thread safe c'est a dire qu'on + peut lancer plusieurs point interieur en parallele. + + Optimisation d'un critere quadratique ou lineaire sous contraintes + lineaires. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pi_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ +/* Routine d'entree du point interieur */ + +void PI_Quamin( PROBLEME_POINT_INTERIEUR * Probleme ) +{ +PROBLEME_PI * Pi; void * Tas; + +Pi = NULL; + +if ( Pi == NULL ) { + # ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + Tas = MEM_Init(); + Pi = (PROBLEME_PI *) MEM_Malloc( Tas, sizeof( PROBLEME_PI ) ); + if ( Pi == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet PROBLEME_PI\n"); + Probleme->ExistenceDUneSolution = PI_ERREUR_INTERNE; + return; + } + Pi->Tas = Tas; + # else + Pi = (PROBLEME_PI *) malloc( sizeof( PROBLEME_PI ) ); + if ( Pi == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet PROBLEME_PI\n"); + Probleme->ExistenceDUneSolution = PI_ERREUR_INTERNE; + return; + } + Pi->Tas = NULL; + # endif +} + +Pi->AnomalieDetectee = NON_PI; /* codes d'erreur a revoir */ +setjmp( Pi->Env ); +if ( Pi->AnomalieDetectee != NON_PI ) { + /* Liberation du probleme */ + PI_LibereProbleme( Pi ); + PI_LibereMatrice( Pi ); + + # ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + MEM_Quit( Pi->Tas ); + # else + free( Pi ); + # endif + + return; +} +else { + /* Optimisation */ + PI_QuaminCalculs( Probleme , Pi ); + /* Pi est toujours libere */ +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_quamin_calculs.c b/src/ext/Sirius_Solver/pointInterieur/pi_quamin_calculs.c new file mode 100644 index 0000000000..25dbb53140 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_quamin_calculs.c @@ -0,0 +1,357 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Routine principale du point interieur + + Optimisation d'un critere quadratique ou lineaire sous contraintes + lineaires. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# ifdef PNE_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pne_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ +/* Routine d'entree du point interieur */ +void PI_QuaminCalculs( PROBLEME_POINT_INTERIEUR * Probleme , PROBLEME_PI * Pi ) +{ +/* Le probleme d'entree */ +int NombreDeVariables_E ; double * Q_E ; double * L_E ; +double * Umin_E ; double * Umax_E; int * TypeDeVariable_E; char * VariableBinaire_E; double * U_E; +int NombreDeContraintes_E; double * A_E ; int * Mdeb_E ; int * Nbter_E; +int * Nuvar_E ; double * B_E ; char * Sens_E ; +double ToleranceAdmissibilite_E ; int ChoixToleranceAdmissibiliteParDefaut ; +double ToleranceStationnarite_E ; int ChoixToleranceStationnariteParDefaut ; +double ToleranceComplementarite_E; int ChoixToleranceComplementariteParDefaut; + +int * Convergence; /* Indicateur de convergence en sortie pas utilise */ +double * VariablesDualesDeContraintes; double * S1_E; double * S2_E; +int Preconditionnement; +/* */ + +int TracesALaFin ; int ImprimerLeProbleme; int ImprimerLesIterationsSiDivergence; + +/*----------------------------------------------------------------------------------------------------*/ + +NombreDeVariables_E = Probleme->NombreDeVariables; +Q_E = Probleme->CoutQuadratique; +L_E = Probleme->CoutLineaire; + +Umin_E = Probleme->Xmin; +Umax_E = Probleme->Xmax; +TypeDeVariable_E = Probleme->TypeDeVariable; +VariableBinaire_E = Probleme->VariableBinaire; +U_E = Probleme->X; + +NombreDeContraintes_E = Probleme->NombreDeContraintes; +A_E = Probleme->CoefficientsDeLaMatriceDesContraintes; +Mdeb_E = Probleme->IndicesDebutDeLigne; +Nbter_E = Probleme->NombreDeTermesDesLignes; +Nuvar_E = Probleme->IndicesColonnes; +B_E = Probleme->SecondMembre; +Sens_E = Probleme->Sens; + +ToleranceAdmissibilite_E = Probleme->ToleranceDAdmissibilite; +ChoixToleranceAdmissibiliteParDefaut = Probleme->UtiliserLaToleranceDAdmissibiliteParDefaut; +ToleranceStationnarite_E = Probleme->ToleranceDeStationnarite; +ChoixToleranceStationnariteParDefaut = Probleme->UtiliserLaToleranceDeStationnariteParDefaut; +ToleranceComplementarite_E = Probleme->ToleranceDeComplementarite; +ChoixToleranceComplementariteParDefaut = Probleme->UtiliserLaToleranceDeComplementariteParDefaut; +VariablesDualesDeContraintes = Probleme->CoutsMarginauxDesContraintes; + +/*----------------------------------------------------------------------------------------------------*/ + +Pi->YaUneSolution = OUI_PI; + +ImprimerLesIterationsSiDivergence = OUI_PI; /* a faire */ +ImprimerLeProbleme = NON_PI; /* a faire */ +TracesALaFin = NON_PI; /* a faire */ + +Pi->YaUneSolution = OUI_PI; + +PI_AllocProbleme( Pi, NombreDeVariables_E, NombreDeContraintes_E, Nbter_E, Sens_E, VariableBinaire_E, TypeDeVariable_E ); + +PI_MdEqua( Pi, NombreDeVariables_E, Q_E, L_E, Umin_E , Umax_E , TypeDeVariable_E, VariableBinaire_E, U_E, + NombreDeContraintes_E, Mdeb_E, Nbter_E, Nuvar_E, A_E, B_E, Sens_E ); + +if ( Pi->NombreDeVariables <= 0 ) { + Probleme->ExistenceDUneSolution = Pi->YaUneSolution; + goto Fin; +} + +/* PI_SplitContraintes( Pi ); */ + +/* Test */ + +/* PI_SplitColonnes( Pi ); */ + +/* Fin test */ + +PI_Qinit( Pi, + ToleranceAdmissibilite_E , ChoixToleranceAdmissibiliteParDefaut, + ToleranceStationnarite_E , ChoixToleranceStationnariteParDefaut, + ToleranceComplementarite_E , ChoixToleranceComplementariteParDefaut ); + +PI_InitATransposee( Pi , COMPACT ); + +/*PI_Scaling( Pi );*/ /*fait ailleurs */ + +PI_InitXS( Pi ); + +/*PI_AllocMatrice( Pi );*/ /* fait dans PI_Cremat */ + +Pi->YaUneSolution = NON_PI; /* L'indicateur est remis a jour dans PI_Joptimise */ + +PI_Joptimise( Pi ); + +Probleme->ExistenceDUneSolution = Pi->YaUneSolution; + +PI_UnScaling( Pi ); + +/* a revoir if ( FaireMiseALEchelle == OUI_PI ) PI_InverseDeMiseALEchelle( Pi );*/ + +/* Restitution de la solution */ +S1_E = NULL; /* Car sinon visual studio croit qu'on utilise ces variables sans les avoir initialisees */ +S2_E = NULL; /* c'est idiot de sa part mais bon, c'est toujours le moins con qui cčde en premier */ +PI_RestitutionDesResultats( Pi, + NombreDeVariables_E , U_E , S1_E , S2_E , + NombreDeContraintes_E , VariablesDualesDeContraintes ); + + if ( MPCC != OUI_PI ) goto Fin; +{ +int Var; double C; double pi; double Cp;int i; double SLambda; +C = 0.0; +Cp = -1.0; +pi = 10.; +i = -1; +SLambda = 0.0; +for ( Var = 0 ; Var < NombreDeVariables_E ; Var++ ) { + C+= Q_E[Var] * U_E[Var] * U_E[Var]; + C+= L_E[Var] * U_E[Var]; + if ( VariableBinaire_E[Var] == OUI_PI ) { + /*Cp+= pi * U_E[Var] * ( 1. - U_E[Var] );*/ + SLambda+= Pi->Lambda[Pi->NumeroDeLaContrainteDeComplementarite[Pi->CorrespondanceVarEntreeVarPi[Var]]]; + if ( U_E[Var] < 1. - U_E[Var] ) { + if ( U_E[Var] > Cp ) { + i = Var; + Cp = U_E[Var]; + } + } + else { + if ( 1. - U_E[Var] > Cp ) { + i = Var; + Cp = 1. - U_E[Var]; + } + } + printf("Variable binaire %d valeur %e Lambda %e\n",Var,U_E[Var], + Pi->Lambda[Pi->NumeroDeLaContrainteDeComplementarite[Pi->CorrespondanceVarEntreeVarPi[Var]]]); + } +} +printf("Cout de la solution %e\n",C); +printf("Plus grande non integrite %e variable %d \n",Cp,i); +printf("Umin %e U %e Umax %e\n",Umin_E[i],U_E[i],Umax_E[i]); +printf("Valeur de Xi: %e\n",Pi->U[Pi->NumeroDeLaVariableXi]); +printf("SLambda = %e Rho = %e\n",SLambda,Pi->L[Pi->NumeroDeLaVariableXi]); +exit(0); +} + +/* liberer le probleme et la matrice aussi */ +Fin: + +PI_LibereProbleme( Pi ); +PI_LibereMatrice( Pi ); + +# ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + MEM_Quit( Pi->Tas ); +# else + free( Pi ); +# endif + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Routine d'optimisation */ + +void PI_Joptimise( PROBLEME_PI * Pi ) +{ +int NombreDeTestsDArretNonSatisfaits; +int IterationComplementariteOK; +int IterationAdmissibiliteOK; +int IterationStationnariteOK; + +Pi->ComplementariteAtteinte = NON_PI; +Pi->RealisabiliteAtteinte = NON_PI; +Pi->StationnariteAtteinte = NON_PI; +Pi->NumeroDIteration = 1; +Pi->TypeDIteration = AFFINE; + +while ( Pi->NumeroDIteration <= NOMBRE_MAX_DITERATION ) { + + Pi->Gamma = 0.9995; /* 0.9995 */ + + /* Pour ne pas s'approcher trop rapidement des bornes afin de ne pas detruite trop rapidement + le conditionnement de la matrice */ + if ( Pi->NumeroDIteration <= 2 ) Pi->Gamma = 0.9; + + if( Pi->TypeDIteration == CENTRALISATION ) { + PI_Calmuk( Pi ); /* Calcul de muk */ + Pi->MukIteration[Pi->NumeroDIteration-1] = Pi->Muk; /* Sauvegarde pour les les traces */ + Pi->MukPrecedent = Pi->Muk; + #if VERBOSE_PI + printf("\n*** Iteration numero %d de type CENTRALISATION, valeur utilisee pour Muk %e\n",Pi->NumeroDIteration,Pi->Muk); + #endif + PI_Calcent( Pi ); /* Correction pour la centralisation */ + } + else { /* Cas d'une iteration affine */ + #if VERBOSE_PI + printf("\n*** Iteration numero %d de type AFFINE\n",Pi->NumeroDIteration); + #endif + + memset( (char *) Pi->SecondMembre , 0 , ( Pi->NombreDeVariables + Pi->NombreDeContraintes ) * sizeof( double ) ); /* Nettoyage */ + + NombreDeTestsDArretNonSatisfaits = 0; + + Pi->ArretOpt = OUI_PI; + Pi->Traces = NON_PI; + PI_Caldel( Pi ); /* Calcul de l'ecart de complementarite et test par rapport au seuil d'optimalite */ + if ( Pi->ArretOpt == NON_PI ) NombreDeTestsDArretNonSatisfaits++; + else { Pi->ComplementariteAtteinte = OUI_PI; IterationComplementariteOK = Pi->NumeroDIteration; } + + Pi->Muk = 0.; /* muk = 0 pour une iteration affine */ + + Pi->ArretCnt = OUI_PI; + Pi->ArretSta = OUI_PI; + Pi->Traces = NON_PI; + PI_Calstaf( Pi ); /* Test d'admissibilite et de stationnarite + calcul du second membre */ + if ( Pi->ArretCnt == NON_PI ) NombreDeTestsDArretNonSatisfaits++; + else { Pi->RealisabiliteAtteinte = OUI_PI; IterationAdmissibiliteOK = Pi->NumeroDIteration; } + if ( Pi->ArretSta == NON_PI ) NombreDeTestsDArretNonSatisfaits++; + else { Pi->StationnariteAtteinte = OUI_PI; IterationStationnariteOK = Pi->NumeroDIteration; } + + if( NombreDeTestsDArretNonSatisfaits == 0 ) { + if ( MPCC == OUI_PI && Pi->NombreDeVariablesBinaires > 0 && 0) { + printf("Valeur de Xi:%e et de Rho: %e\n",Pi->U[Pi->NumeroDeLaVariableXi], Pi->Rho); + if ( Pi->U[Pi->NumeroDeLaVariableXi] > 1.e-6 ) { + { + int Var; double SLambda; double X; double Ec; double RhoSv; int Cnt; int il; int ilMax; + SLambda = 0.0; + for ( Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) { + if ( Pi->VariableBinaire[Var] == OUI_PI ) { + SLambda+= Pi->Lambda[Pi->NumeroDeLaContrainteDeComplementarite[Var]]; + Cnt = Pi->NumeroDeLaContrainteDeComplementarite[Var]; + printf("Cnt de la variable binaire %d\n",Cnt); + printf(" U(Umax-U)= %e ",Pi->U[Var] * ( Pi->Umax[Var] - Pi->U[Var] ) ); + il = Pi->Mdeb[Cnt]; + ilMax = il + Pi->NbTerm[Cnt]; + il++; + while ( il < ilMax ) { + printf("U = %e ",Pi->U[Pi->Indcol[il]]); + il++; + } + printf("\n"); + } + } + printf("SLambda = %e Rho = %e\n",SLambda,Pi->L[Pi->NumeroDeLaVariableXi]); + RhoSv = Pi->Rho; + Pi->Rho*= 10.; + Pi->L[Pi->NumeroDeLaVariableXi] = Pi->Rho; + NombreDeTestsDArretNonSatisfaits = 3; + printf("Nouvelle valeur de Rho: %e\n",Pi->Rho); + for ( Var = 0 ; Var < Pi->NombreDeVariables ; Var++ ) { + if ( Pi->VariableBinaire[Var] == OUI_PI ) { + Pi->Lambda[Pi->NumeroDeLaContrainteDeComplementarite[Var]] = Pi->Rho / Pi->NombreDeVariablesBinaires; + } + Ec = 1.e-3; + if ( Pi->TypeDeVariable[Var] == BORNEE ) { + X = Ec * ( Pi->Umax[Var] - Pi->Umin[Var] ); + if ( Pi->U[Var] < Pi->Umin[Var] + X ) Pi->U[Var] = Pi->Umin[Var] + X; + else if ( Pi->U[Var] > Pi->Umax[Var] - X ) Pi->U[Var] = Pi->Umax[Var] - X; + if ( Pi->S1[Var] < Ec ) Pi->S1[Var] = Ec; + if ( Pi->S2[Var] < Ec ) Pi->S2[Var] = Ec; + } + if ( Pi->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + X = Ec; + if ( Pi->U[Var] < Pi->Umin[Var] + X ) Pi->U[Var] = Pi->Umin[Var] + X; + if ( Pi->S1[Var] < Ec ) Pi->S1[Var] = Ec; + } + if ( Pi->TypeDeVariable[Var] == BORNEE_SUPERIEUREMENT ) { + X = Ec; + if ( Pi->U[Var] > Pi->Umax[Var] - X ) Pi->U[Var] = Pi->Umax[Var] - X; + if ( Pi->S2[Var] < Ec ) Pi->S2[Var] = Ec; + } + } + /*Pi->U[Pi->NumeroDeLaVariableXi]+= 1000.;*/ + } + } + } + } + + if( NombreDeTestsDArretNonSatisfaits == 0 && Pi->NumeroDIteration > 1 ) { + /* On a converge mais on impose un test complementaire: + il faut en plus que muk soit suffisamment petit*/ + if ( Pi->MukPrecedent < 1.e-3 ) { + Pi->YaUneSolution = OUI_PI; + /*printf("Point interieur, convergence atteinte, iteration %d \n", Pi->NumeroDIteration);*/ + break; + } + } + } + /* */ + if ( Pi->NumeroDIteration == 1 && Pi->TypeDIteration == AFFINE ) { + PI_Cremat( Pi ); /* A la premiere iteration, elimination ordonnee et factorisation de la matrice du point interieur */ + } + else { + if ( Pi->TypeDIteration == AFFINE ) { + PI_Crebis( Pi ); + } + } + /* */ + PI_Resolution( Pi ); /* Resolution de systeme */ + if ( Pi->TypeDIteration == AFFINE ) Pi->TypeDIteration = CENTRALISATION; + else { + /* En fin d'iteration de centralisation, mise a jour des variables */ + PI_Incrementation( Pi ); + Pi->NumeroDIteration++; + Pi->TypeDIteration = AFFINE; + } +} + +#if VERBOSE_PI + {int i; double copt; + for(copt=0,i=0;iNombreDeVariables;i++) { + copt+=Pi->L[i]*Pi->U[i]; + } + printf("Fin du point interieur a l iteration %d Cout optimal (valeur interne) %e \n",Pi->NumeroDIteration,copt); +} +#endif + +return; +} + + + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_reconstruire_matrice_a_resoudre.c b/src/ext/Sirius_Solver/pointInterieur/pi_reconstruire_matrice_a_resoudre.c new file mode 100644 index 0000000000..69ce0f5250 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_reconstruire_matrice_a_resoudre.c @@ -0,0 +1,143 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Construction de la matrice complete pour les besoins + du raffinement iteratif. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# include "lu_constantes_externes.h" +# include "lu_definition_arguments.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +/*-------------------------------------------------------------------------*/ + +void PI_ReconstruireLaMatriceDuSystemeAResoudre( PROBLEME_PI * Pi ) +{ +int Var; int Cnt ; int Colonne; int il; int ilMax ; int ilCourant; double X ; +char Type; double * Alpha; int NombreDeVariables; int NombreDeContraintes; +double * RegulVar; double * RegulContrainte; double * Qpar2; double * UnSurUkMoinsUmin; +double * UnSurUmaxMoinsUk; double * S1; double * S2; char * TypeDeVariable; double * Alpha2; +int * Ideb; int * Nonu; int * Indl; int * Cdeb;int * CNbTerm; int * NumeroDeContrainte; +int * Mdeb; int * NbTerm; int * Indcol; double * Elm; double * ACol; double * A; + +NombreDeVariables = Pi->NombreDeVariables; +NombreDeContraintes = Pi->NombreDeContraintes; + +RegulVar = Pi->RegulVar; +RegulContrainte = Pi->RegulContrainte; + +TypeDeVariable = Pi->TypeDeVariable; + +Qpar2 = Pi->Qpar2; +UnSurUkMoinsUmin = Pi->UnSurUkMoinsUmin; +UnSurUmaxMoinsUk = Pi->UnSurUmaxMoinsUk; +S1 = Pi->S1; +S2 = Pi->S2; + +Cdeb = Pi->Cdeb; +CNbTerm = Pi->CNbTerm; +ACol = Pi->ACol; +NumeroDeContrainte = Pi->NumeroDeContrainte; + +Mdeb = Pi->Mdeb; +NbTerm = Pi->NbTerm; +Indcol = Pi->Indcol; +A = Pi->A; + +Alpha = Pi->Alpha; +Alpha2 = Pi->Alpha2; + +/* RAZ des termes de regularisation */ + +Ideb = Pi->MatricePi->Ideb; +Nonu = Pi->MatricePi->Nonu; +Elm = Pi->MatricePi->Elm; +Indl = Pi->MatricePi->Indl; + +Pi->MatricePi->NombreDeColonnes = NombreDeVariables + NombreDeContraintes; + +ilCourant = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + Colonne = Var; + Ideb[Colonne] = ilCourant; + Nonu[Colonne] = 0; + /* Terme diagonal ( hessien ) */ + Type = TypeDeVariable[Var]; + if ( Type == BORNEE ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ) + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else if ( Type == BORNEE_INFERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUkMoinsUmin[Var] * S1[Var] ); + } + else if ( Type == BORNEE_SUPERIEUREMENT ) { + X = Qpar2[Var] + ( UnSurUmaxMoinsUk[Var] * S2[Var] ); + } + else { + X = Qpar2[Var]; + } + Elm [ilCourant] = ( X + RegulVar[Var] ) * Alpha2[Var]; + Indl[ilCourant] = Var; + Nonu[Colonne]++; + ilCourant++; + /* Partie matrice des contraintes, vision transposee */ + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + Elm [ilCourant] = ACol[il] * Alpha[Var]; + Indl[ilCourant] = NombreDeVariables + NumeroDeContrainte[il]; + Nonu[Colonne]++; + ilCourant++; + il++; + } +} + +/* Matrice des contraintes */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + Colonne = NombreDeVariables + Cnt; + Ideb[Colonne] = ilCourant; + Nonu[Colonne] = 0; + + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + Elm [ilCourant] = A[il] * Alpha[Var]; + Indl[ilCourant] = Var; + Nonu[Colonne]++; + ilCourant++; + il++; + } + /* Terme de regularisation si necessaire */ + Elm [ilCourant] = RegulContrainte[Cnt]; + Indl[ilCourant] = Colonne; + Nonu[Colonne]++; + ilCourant++; +} + +return; +} diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_resolution.c b/src/ext/Sirius_Solver/pointInterieur/pi_resolution.c new file mode 100644 index 0000000000..485a80604e --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_resolution.c @@ -0,0 +1,44 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution du systeme a chaque iteration de point interieur + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# include "lu_constantes_externes.h" +# include "lu_definition_arguments.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +/*--------------------------------------------------------------------------------*/ + +void PI_Resolution( PROBLEME_PI * Pi ) +{ + +PI_ResolutionSystemeAugmente( Pi ); + +return; +} diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_resolution_systeme_augmente.c b/src/ext/Sirius_Solver/pointInterieur/pi_resolution_systeme_augmente.c new file mode 100644 index 0000000000..83e9fcc3f2 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_resolution_systeme_augmente.c @@ -0,0 +1,208 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution du systeme a chaque iteration de point interieur + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# include "lu_constantes_externes.h" +# include "lu_definition_arguments.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pi_memoire.h" +# endif + +/*--------------------------------------------------------------------------------*/ + +void PI_ResolutionSystemeAugmente( PROBLEME_PI * Pi ) +{ +int CodeRetour; int ItRaff; char FaireDuRaffinement; +int NombreDeVariables; int NombreDeContraintes; int NombreDeColonnes; +int Cnt; int Var; char * TypeDeVariable; double * Qpar2; double * UnSurUkMoinsUmin; +double * S1; double * UnSurUmaxMoinsUk; double * S2; int itDebutRaffinement; +double * SecondMembre; double * DeltaU; double * DeltaLambda; +int * Cdeb; int * CNbTerm; int * NumeroDeContrainte; double * ACol; +int * Mdeb; int * NbTerm; int * Indcol; double * A; double * Alpha; +double * SecondMembreSV; double * Sec; int i; int il; int ilMax; double Xmx; int Lig; +char FaireDuGradientConjugue; int N; double X; +int * IndexDebutDesColonnes; int * NbTermesDesColonnes; +int * IndicesDeLigne; double * ValeurDesTermesDeLaMatrice; + +MATRICE_A_FACTORISER * Matrice; + +NombreDeVariables = Pi->NombreDeVariables; +NombreDeContraintes = Pi->NombreDeContraintes; +NombreDeColonnes = NombreDeVariables + NombreDeContraintes; +SecondMembre = Pi->SecondMembre; +DeltaU = Pi->DeltaU; +DeltaLambda = Pi->DeltaLambda; +TypeDeVariable = Pi->TypeDeVariable; +Qpar2 = Pi->Qpar2; +UnSurUkMoinsUmin = Pi->UnSurUkMoinsUmin; +S1 = Pi->S1; +UnSurUmaxMoinsUk = Pi->UnSurUmaxMoinsUk; +S2 = Pi->S2; + +Cdeb = Pi->Cdeb; +CNbTerm = Pi->CNbTerm; +ACol = Pi->ACol; +NumeroDeContrainte = Pi->NumeroDeContrainte; +Mdeb = Pi->Mdeb; +NbTerm = Pi->NbTerm; +A = Pi->A; +Indcol = Pi->Indcol; + +Alpha = Pi->Alpha; + +FaireDuGradientConjugue = NON_PI; +/* if ( Pi->NumeroDIteration > 50 ) FaireDuGradientConjugue = OUI_PI; */ + +if ( FaireDuGradientConjugue == OUI_PI ) { + /* Sauvegarde du second membre qui sera utilise par le gradient conjugue */ + memcpy( (char *) Pi->SecondMembreAffine, (char *) SecondMembre, ( NombreDeVariables + NombreDeContraintes ) * sizeof( double ) ); +} + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) DeltaU[Var] = 0.0; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) DeltaLambda[Cnt] = 0.0; + +Matrice = NULL; +ItRaff = 0; +itDebutRaffinement = ITERATION_DEBUT_RAFINEMENT_ITERATIF; + +N = Pi->NumeroDIteration / 2; + +if ( N * 2 == Pi->NumeroDIteration ) FaireDuRaffinement = OUI_PI; +else FaireDuRaffinement = NON_PI; + +if ( Pi->TypeDIteration == AFFINE ) FaireDuRaffinement = NON_PI; + +if ( FaireDuRaffinement == OUI_PI ) { + if ( Pi->NumeroDIteration >= itDebutRaffinement ) { + PI_ReconstruireLaMatriceDuSystemeAResoudre( Pi ); + ItRaff = 1; + Matrice = (MATRICE_A_FACTORISER *) Pi->Matrice; + Matrice->ValeurDesTermesDeLaMatrice = Pi->MatricePi->Elm; + Matrice->IndicesDeLigne = Pi->MatricePi->Indl; + Matrice->IndexDebutDesColonnes = Pi->MatricePi->Ideb; + Matrice->NbTermesDesColonnes = Pi->MatricePi->Nonu; + Matrice->NombreDeColonnes = Pi->MatricePi->NombreDeColonnes; + SecondMembreSV = (double *) malloc( Matrice->NombreDeColonnes * sizeof( double ) ); + Sec = (double *) malloc( Matrice->NombreDeColonnes * sizeof( double ) ); + for ( i = 0 ; i < Matrice->NombreDeColonnes ; i++ ) { + SecondMembreSV[i] = SecondMembre[i]; + Sec[i] = SecondMembre[i]; + } + } +} + +LU_LuSolv( (MATRICE *) Pi->MatriceFactorisee, + SecondMembre, /* Le vecteur du second membre et la solution */ + &CodeRetour, /* Le code retour ( 0 si tout s'est bien passe ) */ + Matrice, + ItRaff, + SEUIL_PARFAIT + ); + +/* Verification de la resolution */ +if ( FaireDuRaffinement == OUI_PI ) { + if ( Pi->NumeroDIteration >= itDebutRaffinement ) { + + IndexDebutDesColonnes = Matrice->IndexDebutDesColonnes; + NbTermesDesColonnes = Matrice->NbTermesDesColonnes; + IndicesDeLigne = Matrice->IndicesDeLigne; + ValeurDesTermesDeLaMatrice = Matrice->ValeurDesTermesDeLaMatrice; + + for ( i = 0 ; i < NombreDeColonnes ; i++ ) { + il = IndexDebutDesColonnes[i]; + ilMax = il + NbTermesDesColonnes[i]; + X = SecondMembre[i]; + while ( il < ilMax ) { + SecondMembreSV[IndicesDeLigne[il]]-= ValeurDesTermesDeLaMatrice[il] * X; + il++; + } + } + Xmx = -1; + for ( i = 0 ; i < NombreDeColonnes ; i++ ) { + X = fabs( SecondMembreSV[i] ); + if ( X > Xmx ) { + Xmx = X; + #if VERBOSE_PI + Lig = i; + #endif + } + } + #if VERBOSE_PI + if ( Lig < NombreDeVariables ) { + printf("-----> Plus gros ecart de resolution %e sur la variable %d RegulVar %e U %e S1 %e S2 %e\n", + Xmx,Lig,Pi->RegulVar[Lig],Pi->U[Lig],Pi->S1[Lig],Pi->S2[Lig]); + } + else { + printf("-----> Plus gros ecart de resolution %e sur la contrainte %d RegulContrainte %e\n",Xmx, + Lig-NombreDeVariables,Pi->RegulContrainte[Lig-NombreDeVariables]); + } + printf(" Xmx %e Second membre %e\n",Xmx,Sec[Lig]); + #endif + Pi->Resolution = BON; + if ( Xmx > SEUIL_APPROX ) Pi->Resolution = APPROX; + if ( Xmx < SEUIL_PARFAIT ) Pi->Resolution = PARFAIT; + + free ( SecondMembreSV ); + free ( Sec ); + } +} + +if ( CodeRetour == PRECISION_DE_RESOLUTION_NON_ATTEINTE ) { + /* Tant pis on continue quand-meme */ + CodeRetour = 0; +} + +if ( CodeRetour != 0 ) { + printf(" Erreur dans la resolution du systeme, numero d'erreur %d ",CodeRetour); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +/*-------------------------------------------------------*/ +/* Transfert de la solution vers les tables d'increments */ + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) DeltaU[Var]+= SecondMembre[Var]; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) DeltaLambda[Cnt]+= SecondMembre[NombreDeVariables + Cnt]; + +if ( FaireDuGradientConjugue == OUI_PI ) { + PI_GradientConjugue( Pi ); +} + +/*----------------------------------------------------------*/ + +/* Calcule de delta S1 et de delta S2 */ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) DeltaU[Var]*= Alpha[Var]; + +PI_Sos1s2( Pi ); + +return; +} diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_restitution_des_resultats.c b/src/ext/Sirius_Solver/pointInterieur/pi_restitution_des_resultats.c new file mode 100644 index 0000000000..286b51ce51 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_restitution_des_resultats.c @@ -0,0 +1,67 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/*********************************************************************************** + + FONCTION: + + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +/*------------------------------------------------------------------------*/ +/* Restitution des resultats dans la numerotation d'entree */ + +void PI_RestitutionDesResultats( PROBLEME_PI * Pi, + int NombreDeVariables_E , + double * U_E , + double * S1_E , + double * S2_E , + int NombreDeContraintes_E , + double * VariablesDualesDeContraintes ) +{ +int i; int Var_E; int Cnt_E; + +for ( i = 0 ; i < NombreDeVariables_E ; i++ ) { + Var_E = Pi->CorrespondanceVarEntreeVarPi[i]; + if ( Var_E >= 0 ) { + U_E[i] = Pi->U[Var_E]; + /* + S1_E[i] = Pi->S1[Var_E]; + S2_E[i] = Pi->S2[Var_E]; + */ + } +} + + +for ( i = 0 ; i < NombreDeContraintes_E ; i++ ) { + VariablesDualesDeContraintes[i] = 0; + Cnt_E = Pi->CorrespondanceCntEntreeCntPi[i]; + if ( Cnt_E >= 0 ) { + VariablesDualesDeContraintes[i] = Cnt_E; + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_scaling.c b/src/ext/Sirius_Solver/pointInterieur/pi_scaling.c new file mode 100644 index 0000000000..091faa4f6c --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_scaling.c @@ -0,0 +1,580 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************************** + + FONCTION: + + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pi_memoire.h" +# endif + +# define NOMBRE_MAX_DE_PASSES_DE_SCALING 20 /* 4 */ +# define FAIRE_SCALING_DES_COUTS OUI_PI /* Attention, ce n'est peut-etre pas la bonne option. En effet faire un + scaling des couts c'est faire un scaling du second membre dans le cas + lneaire */ +# define RAPPORT_DE_NEUTRALISATION 10. +# define ARRONDI_EN_PUISSANCES_DE_2 OUI_PI +# define SCALING_DES_BORNES OUI_PI + +# define ZERO_SC 1.e-12 + +/*------------------------------------------------------------------------*/ +/* Scaling */ + +void PI_CalculerLeScaling( PROBLEME_PI * Pi ) +{ +int i; int il; int ilMax; int k; double X; double UnSurX; +double PlusGrandTerme; double PlusPetitTerme; int NombreDeVariables; +char Flag; double Rapport; double RapportPrecedent; double SeuilRapport; +double * A; double * L; double * ScaleU; double * ScaleB; +double ScaleLigneDesCouts; double Zero; double * UnSurUmaxMoinsUmin; +char * TypeDeVariable; double * Umin; double * Umax; int NombreDeContraintes; +int * Mdeb; int * NbTerm; int * Cdeb; int * Csui; double ScaleLigneDesU; + +/* +printf("Attention pas de scaling dans le PI\n"); +return; +*/ + +Mdeb = Pi->Mdeb; +NbTerm = Pi->NbTerm; +Cdeb = Pi->Cdeb; +Csui = Pi->Csui; + +NombreDeVariables = Pi->NombreDeVariables; +NombreDeContraintes = Pi->NombreDeContraintes; + +Zero = ZERO_SC; + +A = (double *) malloc( Pi->NbTermesAllouesPourA * sizeof( double ) ); +L = (double *) malloc( NombreDeVariables * sizeof( double ) ); +ScaleU = (double *) malloc( NombreDeVariables * sizeof( double ) ); +ScaleB = (double *) malloc( NombreDeContraintes * sizeof( double ) ); + +UnSurUmaxMoinsUmin = (double *) malloc( NombreDeVariables * sizeof( double ) ); + +if ( A == NULL || L == NULL || ScaleU == NULL || ScaleB == NULL || UnSurUmaxMoinsUmin == NULL ) { + printf("Simplexe, sous-programme SPX_FaireScaling : \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} + +for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + A[il] = fabs( Pi->A[il] ); + il++; + } +} + +TypeDeVariable = Pi->TypeDeVariable; +Umin = Pi->Umin; +Umax = Pi->Umax; + +X = 0.0; +for ( i = 0 ; i < NombreDeVariables ; i++ ) { + L[i] = fabs( Pi->L[i] ); + X+= fabs( Pi->Q[i] ); + if ( SCALING_DES_BORNES == OUI_PI ) { + UnSurUmaxMoinsUmin[i] = 0.0; + if ( TypeDeVariable[i] == BORNEE ) UnSurUmaxMoinsUmin[i] = 1.0 /(Umax[i] - Umin[i]); + } +} + +if ( X != 0.0 ) Pi->PrendreEnCompteLesCoutsLineairesDansLeScaling = NON_PI; +else Pi->PrendreEnCompteLesCoutsLineairesDansLeScaling = FAIRE_SCALING_DES_COUTS; + +RapportPrecedent = 0.0; +SeuilRapport = 1.e-6; + +/* Analyse des donnees */ +PlusGrandTerme = -1.; +PlusPetitTerme = LINFINI_PI; + +if ( Pi->PrendreEnCompteLesCoutsLineairesDansLeScaling == OUI_PI ) { + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + X = L[i]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + } +} +if ( SCALING_DES_BORNES == OUI_PI ) { + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + X = UnSurUmaxMoinsUmin[i]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + } +} +for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + X = A[il]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + il++; + } +} + +Rapport = PlusGrandTerme/PlusPetitTerme; + +#if VERBOSE_PI + printf(" Avant scaling PlusPetitTerme %20.10lf PlusGrandTerme %20.10lf rapport %20.10lf \n", + PlusPetitTerme,PlusGrandTerme,Rapport); +#endif + +if ( Rapport < RAPPORT_DE_NEUTRALISATION ) goto FinCalculScaling; + +for ( k = 0 ; k < NOMBRE_MAX_DE_PASSES_DE_SCALING ; k++ ) { + /* Controle du conditionnement avant la passe de scaling */ + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_PI; + + if ( Pi->PrendreEnCompteLesCoutsLineairesDansLeScaling == OUI_PI ) { + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + X = L[i]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + } + } + if ( SCALING_DES_BORNES == OUI_PI ) { + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + X = UnSurUmaxMoinsUmin[i]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + } + } + for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + X = A[il]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + il++; + } + } + + Rapport = PlusGrandTerme/PlusPetitTerme; + + #if VERBOSE_PI + printf(" Avant passe de scaling PlusPetitTerme %e PlusGrandTerme %e rapport %e \n",PlusPetitTerme,PlusGrandTerme,Rapport); + #endif + + if ( k >= 1 ) { + if ( fabs ( RapportPrecedent - Rapport ) < SeuilRapport * RapportPrecedent ) { + break; + } + if ( RapportPrecedent < Rapport ) { + /* On recupere les coeff de l'etape precedente et on arrete */ + Pi->ScaleLigneDesCouts = ScaleLigneDesCouts; + Pi->ScaleLigneDesU = ScaleLigneDesU; + for ( i = 0 ; i < NombreDeVariables ; i++ ) Pi->ScaleU[i] = ScaleU[i]; + for ( i = 0 ; i < NombreDeContraintes ; i++ ) Pi->ScaleB[i] = ScaleB[i]; + break; + } + } + + RapportPrecedent = Rapport; + + /* Stockage du scaling precedent */ + ScaleLigneDesCouts = Pi->ScaleLigneDesCouts; + ScaleLigneDesU = Pi->ScaleLigneDesU; + for ( i = 0 ; i < NombreDeVariables ; i++ ) ScaleU[i] = Pi->ScaleU[i]; + for ( i = 0 ; i < NombreDeContraintes ; i++ ) ScaleB[i] = Pi->ScaleB[i]; + + /* Scaling des colonnes: attention dans le scaling des colonnes on ne tient pas comte + des couts quadratiques */ + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + Flag = 0; + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_PI; + if ( Pi->PrendreEnCompteLesCoutsLineairesDansLeScaling == OUI_PI ) { + X = L[i]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) { PlusGrandTerme = X; Flag = 1; } + if ( X < PlusPetitTerme ) { PlusPetitTerme = X; Flag = 1; } + } + } + /* */ + il = Cdeb[i]; + while ( il >= 0 ) { + X = A[il]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) { PlusGrandTerme = X; Flag = 1; } + if ( X < PlusPetitTerme ) { PlusPetitTerme = X; Flag = 1; } + } + il = Csui[il]; + } + /* */ + if ( SCALING_DES_BORNES == OUI_PI ) { + X = UnSurUmaxMoinsUmin[i]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) { PlusGrandTerme = X; Flag = 1; } + if ( X < PlusPetitTerme ) { PlusPetitTerme = X; Flag = 1; } + } + } + /* */ + X = 1.; + UnSurX = 1.; + if ( Flag == 1 ) { + X = PlusGrandTerme * PlusPetitTerme; + X = sqrt( X ); + UnSurX = 1. / X; + } + /* Arrondi en puissance de 2 */ + if ( ARRONDI_EN_PUISSANCES_DE_2 == OUI_PI ) PI_ArrondiEnPuissanceDe2( &UnSurX ); + /* */ + Pi->ScaleU[i]*= UnSurX; + /* Scaling du cout */ + if ( Pi->PrendreEnCompteLesCoutsLineairesDansLeScaling == OUI_PI ) L[i]*= UnSurX; + if ( SCALING_DES_BORNES == OUI_PI ) UnSurUmaxMoinsUmin[i]*= UnSurX; + /* Scaling de A */ + il = Cdeb[i]; + while ( il >= 0 ) { + A[il]*= UnSurX; + il = Csui[il]; + } + } + + /*-------------------- Scaling des lignes ------------------------*/ + + /* Objectif */ + if ( Pi->PrendreEnCompteLesCoutsLineairesDansLeScaling == OUI_PI ) { + Flag = 0; + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_PI; + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + X = L[i]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) { PlusGrandTerme = X; Flag = 1; } + if ( X < PlusPetitTerme ) { PlusPetitTerme = X; Flag = 1; } + } + } + X = 1.; + UnSurX = 1.; + if ( Flag == 1 ) { + X = PlusGrandTerme * PlusPetitTerme; + X = sqrt( X ); + UnSurX = 1. / X; + } + /* Arrondi en puissance de 2 */ + if ( ARRONDI_EN_PUISSANCES_DE_2 == OUI_PI ) PI_ArrondiEnPuissanceDe2( &UnSurX ); + /* */ + Pi->ScaleLigneDesCouts*= UnSurX; + for ( i = 0 ; i < NombreDeVariables ; i++ ) L[i]*= UnSurX; + } + /* Lignes */ + for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + Flag = 0; + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_PI; + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + X = A[il]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) { PlusGrandTerme = X; Flag = 1; } + if ( X < PlusPetitTerme ) { PlusPetitTerme = X; Flag = 1; } + } + il++; + } + X = 1.; + UnSurX = 1.; + if ( Flag == 1 ) { + X = PlusGrandTerme * PlusPetitTerme; + X = sqrt( X ); + UnSurX = 1. / X; + } + /* Arrondi en puissance de 2 */ + if ( ARRONDI_EN_PUISSANCES_DE_2 == OUI_PI ) PI_ArrondiEnPuissanceDe2( &UnSurX ); + /* */ + Pi->ScaleB[i]*= UnSurX; + /* Scaling de A */ + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + A[il]*= UnSurX; + il++; + } + } + /* Bornes */ + if ( SCALING_DES_BORNES == OUI_PI ) { + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + Flag = 0; + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_PI; + X = UnSurUmaxMoinsUmin[i]; + if( X > Zero ) { + if ( X > PlusGrandTerme ) { PlusGrandTerme = X; Flag = 1; } + if ( X < PlusPetitTerme ) { PlusPetitTerme = X; Flag = 1; } + } + } + X = 1.; + UnSurX = 1.; + if ( Flag == 1 ) { + X = PlusGrandTerme * PlusPetitTerme; + X = sqrt( X ); + UnSurX = 1. / X; + } + /* Arrondi en puissance de 2 */ + if ( ARRONDI_EN_PUISSANCES_DE_2 == OUI_PI ) PI_ArrondiEnPuissanceDe2( &UnSurX ); + /* */ + /*Pi->ScaleLigneDesU*= 1. / UnSurX;*/ + /* Il vaut mieux ne pas retriturer les bornes avec ScaleLigneDesU */ + Pi->ScaleLigneDesU = 1.; + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + UnSurUmaxMoinsUmin[i]*= UnSurX; + } + } +} + +FinCalculScaling: + +free( A ); +free( L ); +free( ScaleU ); +free( ScaleB ); +free( UnSurUmaxMoinsUmin ); + +return; +} + + +/*------------------------------------------------------------------------*/ +/* Scaling */ +/* Apres avoir calcule les matrices de scaling, on fait le scaling. */ + +void PI_Scaling( PROBLEME_PI * Pi ) +{ +int i; int il ; int ilMax; double X; double UnSurX ; double Rapport; +double PlusGrandTerme; double PlusPetitTerme ; double Zero ; +int NombreDeVariables; int NombreDeContraintes; int * Cdeb; int * Csui; +int * Mdeb; int * NbTerm; +double * ScaleU; double * L; double * Q; double * A; double * U; double * Umin; +double * Umax; double * ScaleB; double * B; +char * TypeDeVariable; + +Zero = ZERO_SC; + +NombreDeVariables = Pi->NombreDeVariables; +NombreDeContraintes = Pi->NombreDeContraintes; + +ScaleU = Pi->ScaleU; +ScaleB = Pi->ScaleB; +L = Pi->L; +Q = Pi->Q; +A = Pi->A; +U = Pi->U; +B = Pi->B; +Umin = Pi->Umin; +Umax = Pi->Umax; +Cdeb = Pi->Cdeb; +Csui = Pi->Csui; +Mdeb = Pi->Mdeb; +NbTerm = Pi->NbTerm; +TypeDeVariable = Pi->TypeDeVariable; + +/* Maintenant on fait le scaling effectif */ +for ( i = 0 ; i < NombreDeVariables ; i++ ) { + X = ScaleU[i]; + UnSurX = 1. / X; + /* Scaling du cout */ + L[i]*= X; + Q[i]*= X * X; + /* Scaling de la matrice des contraintes A */ + il = Cdeb[i]; + while ( il >= 0 ) { + A[il]*= X; + il = Csui[il]; + } + /* Scaling des variables */ + U[i]*= UnSurX; + if ( TypeDeVariable[i] != NON_BORNEE ) Umin[i]*= UnSurX; + if ( TypeDeVariable[i] == BORNEE ) Umax[i]*= UnSurX; +} + +X = Pi->ScaleLigneDesU; +for ( i = 0 ; i < Pi->NombreDeVariables ; i++ ) { + if ( TypeDeVariable[i] == BORNEE ) { + U [i]*= X; + Umin[i]*= X; + Umax[i]*= X; + } +} + +X = Pi->ScaleLigneDesCouts; +for ( i = 0 ; i < NombreDeVariables ; i++ ) { + L[i]*= X; +} + +for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + X = ScaleB[i]; + /* Scaling de B */ + B[i]*= X; + /* Scaling de A */ + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + A[il]*= X; + il++; + } +} + +#if VERBOSE_PI + +/* Verification */ + +printf("Verification apres application effective du scaling:\n"); + +PlusGrandTerme = -1.; +PlusPetitTerme = LINFINI_PI; + +if ( Pi->PrendreEnCompteLesCoutsLineairesDansLeScaling == OUI_PI ) { + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + X = fabs( L[i] ); + if( X > Zero ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + } +} + +for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + X = fabs( A[il] ); + if( X > Zero ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + il++; + } +} + +Rapport = PlusGrandTerme/PlusPetitTerme; + +printf(" PlusPetitTerme %20.10lf PlusGrandTerme %20.10lf rapport %20.10lf \n",PlusPetitTerme,PlusGrandTerme,Rapport); + +#endif + +return; +} + +/*------------------------------------------------------------------------*/ + +void PI_ArrondiEnPuissanceDe2( double * ValeurRetenue ) +{ +double PuissanceDe2 ; double X ; double ValeurPuissanceInferieure; +double ValeurPuissanceCourante ; int P2 ; double ValeurPuissanceSuperieure; +int i; double Y; double Y1 ; double Y2; double Y3; + +/* +X = *ValeurRetenue; +frexp( X , &P2 ); + +ValeurPuissanceInferieure = ldexp( 1. , P2-1 ); +ValeurPuissanceCourante = ldexp( 1. , P2 ); +ValeurPuissanceSuperieure = ldexp( 1. , P2+1 ); + +i = 0; +Y = LINFINI_PI;; +Y1 = fabs( X - ValeurPuissanceInferieure ); +Y2 = fabs( X - ValeurPuissanceCourante ); +Y3 = fabs( X - ValeurPuissanceSuperieure ); + +if ( Y1 < Y ) { Y = Y1; i = 1; } +if ( Y2 < Y ) { Y = Y2; i = 2; } +if ( Y3 < Y ) { Y = Y3; i = 3; } + +if ( i == 1 ) *ValeurRetenue = ValeurPuissanceInferieure; +else if ( i == 2 ) *ValeurRetenue = ValeurPuissanceCourante; +else if ( i == 3 ) *ValeurRetenue = ValeurPuissanceSuperieure; +else *ValeurRetenue = ValeurPuissanceCourante; +*/ + +X = *ValeurRetenue; +frexp( X , &P2 ); + +ValeurPuissanceInferieure = ldexp( 1. , P2-1 ); +ValeurPuissanceSuperieure = ldexp( 1. , P2 ); + +if ( fabs( X - ValeurPuissanceInferieure ) > fabs ( X - ValeurPuissanceSuperieure ) ) { + *ValeurRetenue = ValeurPuissanceSuperieure; +} +else { + *ValeurRetenue = ValeurPuissanceInferieure; +} + +return; +} + +/*------------------------------------------------------------------------*/ +/* UnScaling */ + +void PI_UnScaling( PROBLEME_PI * Pi ) +{ +int i; double * ScaleU; double * U; double * S1; double * S2; +double UnSurScaleLigneDesU ; char * TypeDeVariable; + +ScaleU = Pi->ScaleU; +U = Pi->U; +S1 = Pi->S1; +S2 = Pi->S2; + +UnSurScaleLigneDesU = 1. / Pi->ScaleLigneDesU; + +TypeDeVariable = Pi->TypeDeVariable; + +for ( i = 0 ; i < Pi->NombreDeVariables ; i++ ) { + U[i]*= ScaleU[i]; + + if ( TypeDeVariable[i] == BORNEE ) U[i]*= UnSurScaleLigneDesU; + + S1[i]/= ScaleU[i]; + S2[i]/= ScaleU[i]; +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_sos1s2.c b/src/ext/Sirius_Solver/pointInterieur/pi_sos1s2.c new file mode 100644 index 0000000000..19beed77b0 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_sos1s2.c @@ -0,0 +1,104 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/*********************************************************************** + + FONCTION: A chaque iteration de point interiuer, calcul de delta S1 + et delta S2 (ce calcul est fait apres celui de delta U). + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +/*-------------------------------------------------------------------------*/ + +void PI_Sos1s2( PROBLEME_PI * Pi ) +{ +int i; int NombreDeVariables; char * TypeDeVariable; double * DeltaS1; +double * DeltaS2; double * UnSurUkMoinsUmin ; double * UnSurUmaxMoinsUk; +double * S1; double * S2; double * DeltaU; double * DeltaUDeltaS1; +double * DeltaUDeltaS2; double Muk; char Type; + +NombreDeVariables = Pi->NombreDeVariables; +TypeDeVariable = Pi->TypeDeVariable; + +DeltaS1 = Pi->DeltaS1; +DeltaS2 = Pi->DeltaS2; + +UnSurUkMoinsUmin = Pi->UnSurUkMoinsUmin; +UnSurUmaxMoinsUk = Pi->UnSurUmaxMoinsUk; +S1 = Pi->S1; +S2 = Pi->S2; +DeltaU = Pi->DeltaU; +DeltaUDeltaS1 = Pi->DeltaUDeltaS1; +DeltaUDeltaS2 = Pi->DeltaUDeltaS2; + +if ( Pi->NumeroDIteration <= 1 ) { + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + DeltaS1[i] = 0.; + DeltaS2[i] = 0.; + } +} + +if ( Pi->TypeDIteration == AFFINE ) { + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + Type = TypeDeVariable[i]; + if ( Type == BORNEE ) { + DeltaS1[i] = ( - UnSurUkMoinsUmin[i] * S1[i] * DeltaU[i] ) - S1[i]; + DeltaS2[i] = ( UnSurUmaxMoinsUk[i] * S2[i] * DeltaU[i] ) - S2[i]; + } + else if ( Type == BORNEE_INFERIEUREMENT ) { + DeltaS1[i] = ( - UnSurUkMoinsUmin[i] * S1[i] * DeltaU[i] ) - S1[i]; + } + else if ( Type == BORNEE_SUPERIEUREMENT ) { + DeltaS2[i] = ( UnSurUmaxMoinsUk[i] * S2[i] * DeltaU[i] ) - S2[i]; + } + } +} +else { + Muk = Pi->Muk; + for ( i = 0 ; i < NombreDeVariables ; i++ ) { + Type = TypeDeVariable[i]; + if ( Type == BORNEE ) { + DeltaS1[i] = UnSurUkMoinsUmin[i] * ( Muk - ( S1[i] * DeltaU[i] ) - + DeltaUDeltaS1[i] ) - S1[i]; + DeltaS2[i] = UnSurUmaxMoinsUk[i] * ( Muk + ( S2[i] * DeltaU[i] ) + + DeltaUDeltaS2[i] ) - S2[i]; + } + else if ( Type == BORNEE_INFERIEUREMENT ) { + DeltaS1[i] = UnSurUkMoinsUmin[i] * ( Muk - ( S1[i] * DeltaU[i] ) - + DeltaUDeltaS1[i] ) - S1[i]; + } + else if ( Type == BORNEE_SUPERIEUREMENT ) { + DeltaS2[i] = UnSurUmaxMoinsUk[i] * ( Muk + ( S2[i] * DeltaU[i] ) + + DeltaUDeltaS2[i] ) - S2[i]; + } + } +} + +return; +} + + + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_split_colonnes.c b/src/ext/Sirius_Solver/pointInterieur/pi_split_colonnes.c new file mode 100644 index 0000000000..a5b285bdfd --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_split_colonnes.c @@ -0,0 +1,156 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/*********************************************************************************** + + FONCTION: Split des colonnes trop denses + + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +# ifdef PI_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "pi_memoire.h" +# endif + +# define SEUIL_TERMES_COLONNE 10 + +/*------------------------------------------------------------------------*/ +/* Initialisation */ + +void PI_SplitColonnes( PROBLEME_PI * Pi ) +{ +int Var; int Var1; int ic; int icMax; int il; int ilMax; int ilLibre; +int Cnt; int Count; int CNbTerm; int CNbLim; int i; int NbTerm; int ilDeb; +int * CntModifiees; int NbCntModifiees; char OnInverse; int il1; int Isv; int Xsv; +int NombreDeVariablesSV; + +return; + +PI_InitATransposee( Pi , COMPACT ); + +NbCntModifiees = 0; +CntModifiees = (int *) malloc( Pi->NombreDeContraintes * sizeof( int ) ); +if ( CntModifiees == NULL ) { + printf(" Point interieur, memoire insuffisante dans le sous programme PI_SplitColonnes \n"); + Pi->AnomalieDetectee = OUI_PI; + longjmp( Pi->Env , Pi->AnomalieDetectee ); +} + +Cnt = Pi->NombreDeContraintes - 1; +ilLibre = Pi->Mdeb[Cnt] + Pi->NbTerm[Cnt]; + +NombreDeVariablesSV = Pi->NombreDeVariables; +for ( Var = 0 ; Var < NombreDeVariablesSV ; Var++ ) { + CNbTerm = Pi->CNbTerm[Var]; + if ( CNbTerm >= SEUIL_TERMES_COLONNE ) { + /* On splitte la colonne */ + /* 1- Creation d'une variable de dedoublement supplementaire */ + Var1 = Pi->NombreDeVariables; + Pi->Q [Var1] = Pi->Q[Var]; + Pi->L [Var1] = Pi->L[Var]; + Pi->U [Var1] = Pi->U[Var]; + Pi->Umin [Var1] = Pi->Umin[Var]; + Pi->Umax [Var1] = Pi->Umax[Var]; + Pi->ScaleU[Var1] = Pi->ScaleU[Var]; + Pi->S1 [Var1] = Pi->S1[Var]; + Pi->S2 [Var1] = Pi->S2[Var]; + Pi->TypeDeVariable[Var1] = Pi->TypeDeVariable[Var]; + /* Incrementation du nombre de variables */ + Pi->NombreDeVariables++; + + /* 2- Modification des contraintes intervenant dans la colonne */ + ic = Pi->Cdeb[Var]; + CNbLim = (int) 0.5 * CNbTerm; + icMax = ic + CNbTerm; + Count = 0; + while ( ic < icMax ) { + Count++; + if ( Count > CNbLim ) { + Cnt = Pi->NumeroDeContrainte[ic]; + CntModifiees[NbCntModifiees] = Cnt; + il = Pi->Mdeb[Cnt]; + ilMax = il + Pi->NbTerm[Cnt]; + while (il < ilMax ) { + if ( Pi->Indcol[il] == Var ) { + Pi->Indcol[il] = Var1; + break; + } + il++; + } + } + ic++; + } + + /* Creation de la contrainte Var - Var1 = 0 */ + Pi->Mdeb [Pi->NombreDeContraintes] = ilLibre; + Pi->NbTerm[Pi->NombreDeContraintes] = 2; + Pi->B [Pi->NombreDeContraintes] = 0.0; + Pi->A [ilLibre] = 1; + Pi->Indcol[ilLibre] = Var; + ilLibre++; + Pi->A [ilLibre] = -1; + Pi->Indcol[ilLibre] = Var1; + ilLibre++; + Pi->NombreDeContraintes++; + + } +} + +/* Pour chaque contrainte modifiee, reclassement des termes */ +for ( i = 0 ; i < NbCntModifiees ; i++ ) { + Cnt = CntModifiees[i]; + OnInverse = OUI_PI; + ilDeb = Pi->Mdeb[Cnt]; + NbTerm = Pi->NbTerm[Cnt] - 1; + ilMax = ilDeb + NbTerm; + while ( OnInverse == OUI_PI ) { + OnInverse = NON_PI; + il = ilDeb; + while (il < ilMax ) { + il1 = il + 1; + if ( Pi->Indcol[il] > Pi->Indcol[il1] ) { + OnInverse = OUI_PI; + Isv = Pi->Indcol[il]; + Xsv = Pi->A[il]; + Pi->Indcol[il] = Pi->Indcol[il1]; + Pi->A [il] = Pi->A[il1]; + Pi->Indcol[il1] = Isv; + Pi->A [il1] = Xsv; + } + il++; + } + } +} + +free( CntModifiees ); +CntModifiees = NULL; + +if ( NbCntModifiees > 0 ) PI_InitATransposee( Pi , COMPACT ); + + +return; +} + + + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_split_contraintes.c b/src/ext/Sirius_Solver/pointInterieur/pi_split_contraintes.c new file mode 100644 index 0000000000..e021a693fb --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_split_contraintes.c @@ -0,0 +1,102 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/*********************************************************************************** + + FONCTION: + + + AUTEUR: R. GONZALEZ + +************************************************************************************/ + +# include "pi_sys.h" + +# include "pi_fonctions.h" +# include "pi_define.h" + +/*------------------------------------------------------------------------*/ +/* Initialisation */ + +void PI_SplitContraintes( PROBLEME_PI * Pi ) +{ +int i ; int NbCntTot; int NbTermes1; int NbTermes2; +int SvNuvar; int OldNbTerm ; double SvA ; int EmplacementLibreDansA; +int il ; + +int SeuilSplitContrainte; + +SeuilSplitContrainte = 100; + +/* Attention on suppose que les contraintes sont contigues en entree */ +EmplacementLibreDansA = Pi->Mdeb [Pi->NombreDeContraintes-1] + + Pi->NbTerm[Pi->NombreDeContraintes-1]; + +/* Matrice des contraintes */ +NbCntTot = Pi->NombreDeContraintes; +for ( i = 0 ; i < Pi->NombreDeContraintes ; i++ ) { + + if( Pi->NbTerm[i] >= (2 * SeuilSplitContrainte) ) { + + /* On split la contrainte en 2 */ + NbTermes1 = (int) (0.5 * Pi->NbTerm[i]); + NbTermes2 = Pi->NbTerm[i] - NbTermes1; + /* On cree une variable de couplage */ + Pi->NombreDeVariables++; + /* dont on initialisera les bornes apres */ + Pi->Umin [Pi->NombreDeVariables - 1] = -100; + Pi->Umax [Pi->NombreDeVariables - 1] = 100; + Pi->Q [Pi->NombreDeVariables - 1] = 0.; + Pi->L [Pi->NombreDeVariables - 1] = 0.; + + /* Remodelage de la contrainte i */ + SvNuvar = Pi->Indcol [ Pi->Mdeb[i] + NbTermes1 ]; + SvA = Pi->A [ Pi->Mdeb[i] + NbTermes1 ]; + OldNbTerm = Pi->NbTerm[i]; + + Pi->NbTerm[i] = NbTermes1 + 1; + Pi->Indcol[ Pi->Mdeb[i] + Pi->NbTerm[i] - 1 ] = Pi->NombreDeVariables - 1; + Pi->A [ Pi->Mdeb[i] + Pi->NbTerm[i] - 1 ] = 1.; + + /* On cree la contraintes de couplage */ + Pi->Mdeb [NbCntTot] = EmplacementLibreDansA; + Pi->NbTerm[NbCntTot] = NbTermes2 + 1; + Pi->B [NbCntTot] = 0.; + + Pi->A [EmplacementLibreDansA] = SvA; + Pi->Indcol[EmplacementLibreDansA] = SvNuvar; + EmplacementLibreDansA++; + for ( il = Pi->Mdeb[i] + Pi->NbTerm[i] ; il < Pi->Mdeb[i] + OldNbTerm ; il++ , EmplacementLibreDansA++) { + Pi->A [EmplacementLibreDansA] = Pi->A[il]; + Pi->Indcol[EmplacementLibreDansA] = Pi->Indcol[il]; + } + Pi->A [EmplacementLibreDansA] = -1; + Pi->Indcol[EmplacementLibreDansA] = Pi->NombreDeVariables - 1; + EmplacementLibreDansA++; + + NbCntTot++; + + } + +} + +Pi->NombreDeContraintes = NbCntTot; +printf(" Apres split NombreDeVariables %d NombreDeContraintes %d \n",Pi->NombreDeVariables,Pi->NombreDeContraintes); + +return; +} + diff --git a/src/ext/Sirius_Solver/pointInterieur/pi_sys.h b/src/ext/Sirius_Solver/pointInterieur/pi_sys.h new file mode 100644 index 0000000000..1d47671698 --- /dev/null +++ b/src/ext/Sirius_Solver/pointInterieur/pi_sys.h @@ -0,0 +1,28 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# include +# include +# include +# include +# include +/* # include */ +# include +# include +# include +# include + + diff --git a/src/ext/Sirius_Solver/presolve/prs_DM.c b/src/ext/Sirius_Solver/presolve/prs_DM.c new file mode 100644 index 0000000000..27e4b6d3e7 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_DM.c @@ -0,0 +1,545 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recherche d'une matrice carree permettant de calculer + des variables duales. + On cherche a resoudre u A1 = c1 ou A1 est la restiction + de A aux variables basique, u le vecteur des variables + duales, c1 la restriction du vecteur des couts aux variables + basiques. + On veut determiner le plus grand nombre possible de composantes + de u. + On forme la matrice B = 0 A1^t et on en fait une BTF. + A1 0 + En parcourant les blocs on resout [v u] B = [0 c1] en + prenant chaque bloc obtenu dans la decompsiton BTF. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if DUMALGE_MENDELSON == OUI_PNE + +# include "btf.h" +# include "btf_internal.h" + +# include "cs.h" + +# define MARGE 1.e-4 +# define INUTILE 255 + +# define LIGNE 1 +# define COLONNE 2 + +/*----------------------------------------------------------------------------*/ +/* Attention: dans le dual on n'a pas le droit de supprimer des contraintes en +regardant les colonnes non calculables car une colonne ne correspond pas toujours +a une contrainte entiere: il n'y a pas les termes des variables bornees des 2 cotes */ + +void PRS_DumalgeMendelson( PRESOLVE * Presolve ) +{ +int Var; int il; int ilMax; int ilAi; +int ic; int i; int j; int ccDeb; int ccFin; int rrDeb; int rrFin; +int NbIneg; char Flag; char CalculOK; +PROBLEME_PNE * Pne; +int * MdebTrav; int * NbTermTrav; int * NuvarTrav; double * ATrav; +int * NuCntDeNewVar; int * NuVarDeOldCnt; +int * NuVarDeNewCnt; int * NuCntDeOldVar; int NombreDeContraintesTrav; +double * C; int NombreDeVariablesAUtiliser; +char * ContrainteInactive; int * TypeDeBorneTrav; +int Cb; int C1; int C2; int C3; int IndexRR; int IndexCC; +int R1; int R2; int R3; int Rb; int NombreDeVariablesTrav; +int * Ligne; int * Colonne; int NbCntDuProblemeReduit; int NbVarDuProblemeReduit; +int NbIt; +MATRICE * MatriceFactorisee; void * MatriceAFactoriser; +double * Lambda; char * ConnaissanceDeLambda; +int NbCnt; int NbVar; int Cnt; +char CodeRet; char FactorisationOK; char MatriceSinguliere; +cs * A; csd * Csd; csi seed; char * TypeBorne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; +NombreDeContraintesTrav = Pne->NombreDeContraintesTrav; +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; +ATrav = Pne->ATrav; +ContrainteInactive = Presolve->ContrainteInactive; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; + +C = (double *) malloc( NombreDeVariablesTrav * sizeof( double ) ); +NuVarDeNewCnt = (int *) malloc( NombreDeVariablesTrav * sizeof( int ) ); +NuCntDeOldVar = (int *) malloc( NombreDeVariablesTrav * sizeof(int ) ); +TypeBorne = (char *) malloc( NombreDeVariablesTrav * sizeof( char ) ); +for ( Var = 0 ; Var < NombreDeVariablesTrav ; Var++ ) { + NuVarDeNewCnt[Var] = -1; + NuCntDeOldVar[Var] = -1; + C[Var] = Pne->LTrav[Var]; +} + +NbIt = 0; + +for ( Var = 0 ; Var < NombreDeVariablesTrav ; Var++ ) { + TypeBorne[Var] = INUTILE; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE /* || Presolve->TypeDeBorneSv[Var] == VARIABLE_NON_BORNEE */ ) { + TypeBorne[Var] = VARIABLE_NON_BORNEE; + continue; + } + /* + if ( Pne->UmaxTrav[Var] < Presolve->UmaxSv[Var]-MARGE && Pne->UminTrav[Var] > Presolve->UminSv[Var]+MARGE ) { + TypeBorne[Var] = VARIABLE_NON_BORNEE; + continue; + } + */ + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT /*|| Presolve->TypeDeBorneSv[Var] == VARIABLE_BORNEE_INFERIEUREMENT*/ ) { + TypeBorne[Var] = VARIABLE_BORNEE_INFERIEUREMENT; + continue; + } + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT /*|| Presolve->TypeDeBorneSv[Var] == VARIABLE_BORNEE_SUPERIEUREMENT*/ ) { + TypeBorne[Var] = VARIABLE_BORNEE_SUPERIEUREMENT; + continue; + } + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_DES_DEUX_COTES /*|| Presolve->TypeDeBorneSv[Var] == VARIABLE_BORNEE_DES_DEUX_COTES*/ ) { + /* + if ( Pne->UmaxTrav[Var] < Presolve->UmaxSv[Var]-MARGE ) { + continue; + TypeBorne[Var] = VARIABLE_BORNEE_INFERIEUREMENT; + continue; + } + if ( Pne->UminTrav[Var] > Presolve->UminSv[Var]+MARGE ) { + continue; + TypeBorne[Var] = VARIABLE_BORNEE_SUPERIEUREMENT; + continue; + } + */ + } +} + +/* Decompte du nombre de variables a prendre en compte : ce sera le nombre de contraintes */ +NombreDeVariablesAUtiliser = 0; +NbIneg = 0; +for ( Var = 0 ; Var < NombreDeVariablesTrav ; Var++ ) { + /* La variable est initialement bornee d'un seul ou des 2 cotes et on peut en faire une variable non bornee */ + /* Attention au cas des variables non bornees */ + if ( TypeBorne[Var] == VARIABLE_NON_BORNEE ) { + NuVarDeNewCnt[NombreDeVariablesAUtiliser] = Var; + NuCntDeOldVar[Var] = NombreDeVariablesAUtiliser; + NombreDeVariablesAUtiliser++; + continue; + } + if ( TypeBorne[Var] == VARIABLE_BORNEE_INFERIEUREMENT || TypeBorne[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + NuVarDeNewCnt[NombreDeVariablesAUtiliser] = Var; + NuCntDeOldVar[Var] = NombreDeVariablesAUtiliser; + NombreDeVariablesAUtiliser++; + NbIneg++; + } +} + +printf("\n\nNombre de variables a utiliser %d NbIneg %d\n",NombreDeVariablesAUtiliser,NbIneg); + +NbCnt = NombreDeVariablesAUtiliser; +printf("\n\nNombre de contraintes decoulant du nombre de variables retenues %d\n",NbCnt); + +NuVarDeOldCnt = (int *) malloc( NombreDeContraintesTrav * sizeof( int ) ); +NuCntDeNewVar = (int *) malloc( NombreDeContraintesTrav * sizeof( int ) ); + +/* Nombre de variables du probleme: c'est le nombre de contraintes dans lesquelles interviennent + des variables a prendre en compte. Decompte du nombre de termes a allouer. */ + +A = (cs *) malloc( sizeof( cs ) ); + +Debut: + + +for ( Cnt = 0 ; Cnt < NombreDeContraintesTrav ; Cnt++ ) { + NuCntDeNewVar[Cnt] = -1; + NuVarDeOldCnt[Cnt] = -1; +} + + +NbVar = 0; +A->nzmax = 0; +for ( Cnt = 0 ; Cnt < NombreDeContraintesTrav ; Cnt++ ) { + if ( ContrainteInactive[Cnt] == OUI_PNE ) continue; + if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_CONNU ) { + /* Il reste a modifier le second membre */ + continue; + } + Flag = 0; + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + if ( ATrav[il] != 0.0 ) { + Var = NuvarTrav[il]; + if ( NuCntDeOldVar[Var] >= 0 ) { + A->nzmax++; + Flag = 1; + } + } + il++; + } + if ( Flag == 1 ) { + NuCntDeNewVar[NbVar] = Cnt; + NuVarDeOldCnt[Cnt] = NbVar; + NbVar++; + } +} +printf("\n\nNombre de variables decoulant du nombre de variables retenues %d\n",NbVar); + +A->m = NbCnt; +A->n = NbVar; +A->n += NbIneg; +A->nzmax += NbIneg; + +A->p = (csi *) malloc( ( A->n + 1 )* sizeof( csi ) ); +A->i = (csi *) malloc( A->nzmax * sizeof( csi ) ); +A->x = (double *) malloc( A->nzmax * sizeof( double ) ); +A->nz = -1; /* compressed-col */ + +/* Remplissage de la matrice */ +ilAi = 0; +for ( Cnt = 0 ; Cnt < NombreDeContraintesTrav ; Cnt++ ) { + j = NuVarDeOldCnt[Cnt]; + if ( j < 0 ) continue; + A->p[j] = ilAi; + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + if ( ATrav[il] != 0.0 ) { + Var = NuvarTrav[il]; + if ( NuCntDeOldVar[Var] >= 0 ) { + A->i[ilAi] = NuCntDeOldVar[Var]; + if ( A->i[ilAi] < 0 || A->i[ilAi] >= A->m ) { + printf("A->i %d A->m %d\n",(int) A->i[ilAi],(int) A->m); + printf("NuvarTrav[il] %d \n",Var); + printf("NuCntDeOldVar %d \n",NuCntDeOldVar[Var]); + + exit(0); + } + A->x[ilAi] = ATrav[il]; + ilAi++; + } + } + il++; + } +} + +/* Ajout des logicals */ +j = NbVar; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( TypeBorne[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( ilAi >= A->nzmax ) { printf("ilAi %d A->nzmax %d VARIABLE_BORNEE_INFERIEUREMENT j - NbVar %d\n",ilAi,(int) A->nzmax,j-NbVar);exit(0);} + A->p[j] = ilAi; + A->i[ilAi] = NuCntDeOldVar[Var]; + if ( A->i[ilAi] < 0 || A->i[ilAi] >= A->m ) exit(0); + A->x[ilAi] = 1; + ilAi++; + j++; + continue; + } + if ( TypeBorne[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + if ( ilAi >= A->nzmax ) { printf("ilAi %d A->nzmax %d VARIABLE_BORNEE_SUPERIEUREMENT j - NbVar %d\n",ilAi,(int) A->nzmax,j-NbVar);exit(0);} + A->p[j] = ilAi; + A->i[ilAi] = NuCntDeOldVar[Var]; + if ( A->i[ilAi] < 0 || A->i[ilAi] >= A->m ) exit(0); + A->x[ilAi] = -1; + ilAi++; + j++; + continue; + } +} + +if ( A->n != j ) exit(0); + +A->p[A->n] = ilAi; +A->nz = -1; + +printf("Probleme soumis a dmperm: %d Variables et %d contraintes\n",j,(int) A->m); + +seed = 0; +Csd = cs_dmperm( A, seed ); + +/* A faire: verifier que toutes les colonnes de Rb sont dans C3 */ + +printf("\nDual\n"); +Cb = Csd->cc[1]; +printf("Nombre d'elements de CBarre : %d\n",Cb); +C1 = Csd->cc[2]-Csd->cc[1]; +printf("Nombre d'elements de C1 : %d\n",C1); +C2 = Csd->cc[3]-Csd->cc[2]; +printf("Nombre d'elements de C2 : %d\n",C2); +C3 = Csd->cc[4]-Csd->cc[3]; +printf("Nombre d'elements de C3 : %d\n",C3); + +printf("\n"); +R1 = Csd->rr[1]; +printf("Nombre d'elements de R1 : %d\n",R1); +R2 = Csd->rr[2]-Csd->rr[1]; +printf("Nombre d'elements de R2 : %d\n",R2); +R3 = Csd->rr[3]-Csd->rr[2]; +printf("Nombre d'elements de R3 : %d\n",R3); +Rb = Csd->rr[4]-Csd->rr[3]; +printf("Nombre d'elements de RBarre : %d\n",Rb); + +Ligne = (int *) malloc( (int) A->m * sizeof( int ) ); +Colonne = (int *) malloc( (int) A->n * sizeof( int ) ); + +FactorisationOK = 0; +MatriceSinguliere = 1; + + +if ( C3 != 0 ) { + + printf("C3 %d R3 %d\n",C3,R3); + NbVarDuProblemeReduit = C3; + NbCntDuProblemeReduit = C3; + IndexCC = 3; + IndexRR = 2; + + for ( i = 0 ; i < NbCnt ; i++ ) Ligne[i] = -1; + for ( i = 0 ; i < NbVar ; i++ ) Colonne[i] = -1; + + ccDeb = (int) Csd->cc[IndexCC]; + ccFin = (int) Csd->cc[IndexCC+1]; + rrDeb = (int) Csd->rr[IndexRR]; + rrFin = (int) Csd->rr[IndexRR+1]; + + MatriceFactorisee = (MATRICE * ) PRS_DumalgeFactoriserMatrice( Presolve, &MatriceAFactoriser, + NbVarDuProblemeReduit, + NbCntDuProblemeReduit, + ccDeb, + ccFin, + rrDeb, + rrFin, + (void *) Csd, + (void *) A, + Ligne, + Colonne, + &CodeRet, FactorisationOK, MatriceSinguliere ); + if ( CodeRet != MatriceSinguliere ) { + /* On essaie de calculer des variables duales */ + PRS_DumalgeResoudreDual( Presolve, (void *) MatriceFactorisee, (void *) MatriceAFactoriser, + NbVarDuProblemeReduit, NbCntDuProblemeReduit, + ccDeb, ccFin, rrDeb, rrFin, + (void *) Csd, (void *) A, + NuVarDeNewCnt, NuCntDeNewVar, C, &CalculOK ); + + C3 = 0; + } +} +if ( C2 != 0 && C3 == 0 ) { + printf("C2 %d R2 %d\n",C2,R2); + NbVarDuProblemeReduit = C2; + NbCntDuProblemeReduit = C2; + IndexCC = 2; + IndexRR = 1; + + for ( i = 0 ; i < NbCnt ; i++ ) Ligne[i] = -1; + for ( i = 0 ; i < NbVar ; i++ ) Colonne[i] = -1; + + ccDeb = (int) Csd->cc[IndexCC]; + ccFin = (int) Csd->cc[IndexCC+1]; + rrDeb = (int) Csd->rr[IndexRR]; + rrFin = (int) Csd->rr[IndexRR+1]; + + MatriceFactorisee = (MATRICE * ) PRS_DumalgeFactoriserMatrice( Presolve, &MatriceAFactoriser, + NbVarDuProblemeReduit, + NbCntDuProblemeReduit, + ccDeb, + ccFin, + rrDeb, + rrFin, + (void *) Csd, + (void *) A, + Ligne, + Colonne, + &CodeRet, FactorisationOK, MatriceSinguliere ); + + if ( CodeRet != MatriceSinguliere ) { + /* On essaie de calculer des variables duales */ + PRS_DumalgeResoudreDual( Presolve, (void *) MatriceFactorisee, (void *) MatriceAFactoriser, + NbVarDuProblemeReduit, NbCntDuProblemeReduit, + ccDeb, ccFin, rrDeb, rrFin, + (void *) Csd, (void *) A, + NuVarDeNewCnt, NuCntDeNewVar, C, &CalculOK ); + C2 = 0; + } +} + +if ( C1 != 0 && C2 == 0 && 0 ) { + /* Finalement la seule chose qu'on peut tirer de la resolution de C1 serait + une relation entre les variables duales donc on le fait pas */ + /* Sauf si Cbarre = 0 */ + NbVarDuProblemeReduit = C1; + NbCntDuProblemeReduit = C1; + IndexCC = 1; + IndexRR = 0; + for ( i = 0 ; i < NbCnt ; i++ ) Ligne[i] = -1; + for ( i = 0 ; i < NbVar ; i++ ) Colonne[i] = -1; + + if ( IndexCC == 0 ) ccDeb = 0; + else ccDeb = (int) Csd->cc[IndexCC]; + ccFin = (int) Csd->cc[IndexCC+1]; + if ( IndexRR == 0 ) rrDeb = 0; + else rrDeb = (int) Csd->rr[IndexRR]; + rrFin = (int) Csd->rr[IndexRR+1]; + + /* On suppose qu'on fixe a 0 les variables dans CBarre */ + printf("resolution de la partie C1/R1 C1 %d R1 %d\n",C1,R1); + printf("ccDeb %d ccFin %d rrDeb %d rrFin %d \n",ccDeb,ccFin,rrDeb,rrFin); + + MatriceFactorisee = (MATRICE * ) PRS_DumalgeFactoriserMatrice( Presolve, &MatriceAFactoriser, + NbVarDuProblemeReduit, + NbCntDuProblemeReduit, + ccDeb, + ccFin, + rrDeb, + rrFin, + (void *) Csd, + (void *) A, + Ligne, + Colonne, + &CodeRet, FactorisationOK, MatriceSinguliere ); + + + + /* Essais */ + if ( CodeRet != MatriceSinguliere ) { + /* On essaie de calculer des variables duales */ + PRS_DumalgeResoudreDual( Presolve, (void *) MatriceFactorisee, (void *) MatriceAFactoriser, + NbVarDuProblemeReduit, NbCntDuProblemeReduit, + ccDeb, ccFin, rrDeb, rrFin, + (void *) Csd, (void *) A, + NuVarDeNewCnt, NuCntDeNewVar, C, &CalculOK ); + } + + + /* Fin essais */ + + + if ( CodeRet != MatriceSinguliere || NbIt > 10 ) { + goto FIN; + C3 = 0; + } + else { + printf("Matrice singuliere\n"); + + } + +} + +free( TypeBorne ); + +TestProduitsScalaires: +printf("On teste les produits scalaires \n"); + +double psc; int NbcTot; int NbcValide; int NbFix; double CBarre; double a; + +Lambda = Presolve->Lambda; +ConnaissanceDeLambda = Presolve->ConnaissanceDeLambda; + +NbFix = 0; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + /* Pas de calcul pour les variables non bornees */ + if ( TypeDeBorneTrav[Var] == VARIABLE_FIXE ) continue; + /* + if ( TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) continue; + if ( Pne->UmaxTrav[Var] < Presolve->UmaxSv[Var]-1.e-6 && Pne->UminTrav[Var] > Presolve->UminSv[Var]+1.e-6 ) continue; + */ + psc = 0.0; + NbcTot = 0; + NbcValide = 0; + ic = Pne->CdebTrav[Var]; + while ( ic >= 0 ) { + NbcTot++; + Cnt = Pne->NumContrainteTrav[ic]; + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_CONNU ) { + NbcValide++; + psc += Pne->ATrav[ic] * Lambda[Cnt]; + } + else { + a = Pne->ATrav[ic]; + } + ic = Pne->CsuiTrav[ic]; + } + if ( NbcTot - NbcValide == 0 ) { + CBarre = Pne->LTrav[Var] - psc; + if ( CBarre > 0.0 ) { + + printf("cbarre[%d] = %e variable fixee a %e UmaxTrav = %e Cout %e\n",Var,CBarre,Pne->UminTrav[Var],Pne->UmaxTrav[Var],Pne->LTrav[Var]); + + NbFix++; + + Pne->UTrav[Var] = Pne->UminTrav[Var]; + Pne->UmaxTrav[Var] = Pne->UminTrav[Var]; + Pne->TypeDeBorneTrav[Var] = VARIABLE_FIXE; + Pne->TypeDeVariableTrav[Var] = REEL; + + } + else if ( CBarre < 0.0 ) { + + printf("cbarre[%d] = %e variable fixee a %e UminTrav = %e Cout %e\n",Var,CBarre,Pne->UmaxTrav[Var],Pne->UminTrav[Var],Pne->LTrav[Var]); + + NbFix++; + + Pne->UTrav[Var] = Pne->UmaxTrav[Var]; + Pne->UminTrav[Var] = Pne->UmaxTrav[Var]; + Pne->TypeDeBorneTrav[Var] = VARIABLE_FIXE; + Pne->TypeDeVariableTrav[Var] = REEL; + + } + } + else { + if ( NbcTot - NbcValide == 1 ) { + if ( Pne->TypeDeBorneTrav[Var] != VARIABLE_BORNEE_DES_DEUX_COTES ) { + printf("1- Possibilite d'affecter une borne sur une variable duale C[%d] = %e a = %e\n",Var,C[Var],a); + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) printf("La variable est non bornee\n"); + } + /* + if ( Presolve->TypeDeBorneSv[Var] != VARIABLE_BORNEE_DES_DEUX_COTES ) { + printf("2- Possibilite d'affecter une borne sur une variable duale C[%d] = %e a = %e\n",Var,C[Var],a); + } + */ + } + /*printf("Nb de valeurs manquantes %d NbcTot %d\n",NbcTot-NbcValide,NbcTot);*/ + } +} +printf("Nombre de variables que l'on a pu fixer %d\n",NbFix); + +FIN: + +return; +} + +# endif + diff --git a/src/ext/Sirius_Solver/presolve/prs_DM_A.c b/src/ext/Sirius_Solver/presolve/prs_DM_A.c new file mode 100644 index 0000000000..b97a709925 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_DM_A.c @@ -0,0 +1,439 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Mise sous forme coarse (Dumalge Mendelson) de la matrice + des contraintes + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if DUMALGE_MENDELSON == OUI_PNE + +# include "btf.h" +# include "btf_internal.h" + +# include "cs.h" + +# define LIGNE 1 +# define COLONNE 2 + +/*----------------------------------------------------------------------------*/ + +void PRS_DumalgeMendelsonPourLaMatriceDesContraintes( PRESOLVE * Presolve ) +{ +int Var; int il; int ilMax; int ilAi; int ic; int i; int j; char Flag; char Resolu; +PROBLEME_PNE * Pne; int * VarOldVarNew; int * VarNewVarOld; +int NbIneg; +int Cb; int C1; int C2; int C3; int IndexRR; int IndexCC; +int R1; int R2; int R3; int Rb; +int * Ligne; int * Colonne; int NbCntDuProblemeReduit; int NbVarDuProblemeReduit; +int ContrainteDepart; int ContrainteMx; + +int NbCntSupprimees; int NombreDeContraintesTrav; int NombreDeVariablesTrav; +char * CntSupprimee; +int * LigneIndeterminee; int NombreDeLignesIndeterminees; + +MATRICE * MatriceFactorisee; int NbVar0; int ccDeb; int ccFin; int rrDeb; int rrFin; +void * MatriceAFactoriser; +int NbCnt; int NbVar; int Cnt; double * B; int Cnt1; +int il1; int il1Max; +cs * A; double * Scatter; double Norme; double Norme1; double Pscal; double Cos; + +int * MdebTrav; int * NbTermTrav; int * NuvarTrav; double * ATrav; char * SensContrainteTrav; int * CdebTrav; int * CsuiTrav; int * NumContrainteTrav; +int * CntOldCntNew; char * ContrainteInactive; int * TypeDeBorneTrav; +int * CntNewCntOld; csd * Csd; csi seed; double S; char CodeRet; char FactorisationOK; char MatriceSinguliere; char Choix; + +printf("PRS_DumalgeMendelsonPourLaMatriceDesContraintes\n"); + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NombreDeVariablesTrav = Pne->NombreDeVariablesTrav; +NombreDeContraintesTrav = Pne->NombreDeContraintesTrav; + +ContrainteInactive = Presolve->ContrainteInactive; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; + +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; +ATrav = Pne->ATrav; +CdebTrav = Pne->CdebTrav; +CsuiTrav = Pne->CsuiTrav; +NumContrainteTrav = Pne->NumContrainteTrav; +SensContrainteTrav = Pne->SensContrainteTrav; + +CntSupprimee = (char *) malloc( NombreDeContraintesTrav * sizeof( char ) ); +memset( (char *) CntSupprimee, 0, NombreDeContraintesTrav * sizeof( char ) ); + +i = Pne->NombreDeContraintesTrav; + +B = (double *) malloc( i * sizeof( double ) ); +A = (cs *) malloc( sizeof( cs ) ); + +/* Decompte du nombre de variables: on enleve les colonnes sans terme */ + +CntOldCntNew = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); +CntNewCntOld = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) CntOldCntNew[Cnt] = -1; + +/* Decompte du nombre max de termes de la matrice */ +A->nzmax = 0; +NbCnt = 0; +NbIneg = 0; + +ContrainteDepart = 0; +if ( ContrainteDepart >= Pne->NombreDeContraintesTrav ) ContrainteDepart = 0; +ContrainteMx = Pne->NombreDeContraintesTrav; + +for ( Cnt = ContrainteDepart ; Cnt < ContrainteMx ; Cnt++ ) { + + S = Pne->BTrav[Cnt]; + Flag = 0; + /* + if ( ContrainteInactive[Cnt] == OUI_PNE ) goto DECOMPTE_CNT; + if ( CntSupprimee[Cnt] == 1 ) goto DECOMPTE_CNT; + */ + if ( ContrainteInactive[Cnt] == OUI_PNE ) goto DECOMPTE_CNT; + if ( SensContrainteTrav[Cnt] == '<' &&0) goto DECOMPTE_CNT; + if ( SensContrainteTrav[Cnt] != '=' &&0) goto DECOMPTE_CNT; + + + if ( SensContrainteTrav[Cnt] == '<' ) NbIneg++; + il = MdebTrav[Cnt]; + ilMax = il + NbTermTrav[Cnt]; + while ( il < ilMax ) { + if ( ATrav[il] != 0.0 ) { + Var = NuvarTrav[il]; + if ( TypeDeBorneTrav[Var] != VARIABLE_FIXE ) { + A->nzmax++; + Flag = 1; + } + else { + S -= ATrav[il] * Pne->UTrav[Var]; + } + } + il++; + } + DECOMPTE_CNT: + if ( Flag == 1 ) { + CntOldCntNew[Cnt] = NbCnt; + CntNewCntOld[NbCnt] = Cnt; + B[Cnt] = S; + NbCnt++; + } +} + +printf("NbCnt %d\n",NbCnt); +printf("Pne->NombreDeContraintesTrav %d\n",Pne->NombreDeContraintesTrav); + +A->nzmax += NbIneg; + +NbVar = NbIneg; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( TypeDeBorneTrav[Var] != VARIABLE_FIXE ) NbVar++; +} + +VarOldVarNew = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +VarNewVarOld = (int *) malloc( NbVar * sizeof( int ) ); +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) VarOldVarNew[Var] = -1; + +printf("A->nzmax %d\n",(int) A->nzmax); + +A->p = (csi *) malloc( ( NbVar + 1 ) * sizeof( csi ) ); +A->i = (csi *) malloc( A->nzmax * sizeof( csi ) ); +A->x = (double *) malloc( A->nzmax * sizeof( double ) ); +A->nz = -1; /* compressed-col */ + +/* Il faut recompter les variables et les contraintes */ +NbVar = 0; +ilAi = 0; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( TypeDeBorneTrav[Var] == VARIABLE_FIXE ) continue; + Flag = 0; + A->p[NbVar] = ilAi; + ic = CdebTrav[Var]; + while ( ic >= 0 ) { + i = CntOldCntNew[NumContrainteTrav[ic]]; + if ( ATrav[ic] != 0.0 && i >= 0 ) { + A->i[ilAi] = i; + A->x[ilAi] = ATrav[ic]; + ilAi++; + Flag = 1; + } + ic = CsuiTrav[ic]; + } + if ( Flag == 1 ) { + VarOldVarNew[Var] = NbVar; + VarNewVarOld[NbVar] = Var; + NbVar++; + } +} + +for ( Cnt = ContrainteDepart ; Cnt < ContrainteMx ; Cnt++ ) { + if ( SensContrainteTrav[Cnt] != '<' ) continue; + i = CntOldCntNew[Cnt]; + if ( i >= 0 ) { + A->p[NbVar] = ilAi; + A->i[ilAi] = i; + A->x[ilAi] = 1.0; + VarNewVarOld[NbVar] = Pne->NombreDeVariablesTrav + Cnt; + ilAi++; + NbVar++; + } +} + +printf("NbVar %d\n",NbVar); + + +NbVar0 = NbVar; +A->p[NbVar] = ilAi; +A->n = NbVar; +A->m = NbCnt; +A->p[NbVar] = ilAi; + +printf("NbCnt = %d\n",NbCnt); + + +A->nz = -1; +A->nzmax = ilAi; + + +seed = 0; +Csd = cs_dmperm( A, seed ); + +/* A faire: verifier que toutes les colonnes de Rb sont dans C3 */ + +printf("\nPrimal\n"); +Cb = Csd->cc[1]; +printf("Nombre d'elements de CBarre : %d\n",Cb); +C1 = Csd->cc[2]-Csd->cc[1]; +printf("Nombre d'elements de C1 : %d\n",C1); +C2 = Csd->cc[3]-Csd->cc[2]; +printf("Nombre d'elements de C2 : %d\n",C2); +C3 = Csd->cc[4]-Csd->cc[3]; +printf("Nombre d'elements de C3 : %d\n",C3); + +printf("\n"); +R1 = Csd->rr[1]; +printf("Nombre d'elements de R1 : %d\n",R1); +R2 = Csd->rr[2]-Csd->rr[1]; +printf("Nombre d'elements de R2 : %d\n",R2); +R3 = Csd->rr[3]-Csd->rr[2]; +printf("Nombre d'elements de R3 : %d\n",R3); +Rb = Csd->rr[4]-Csd->rr[3]; +printf("Nombre d'elements de RBarre : %d\n",Rb); + +Ligne = (int *) malloc( NbCnt * sizeof( int ) ); +Colonne = (int *) malloc( NbVar * sizeof( int ) ); + +FactorisationOK = 0; +MatriceSinguliere = 1; + +if ( Rb != 0 ) { + /* Il faut verifier que toutes les colonnes de R3 font partie de C3 */ + +} + +Resolu = OUI_PNE; +if ( C3 != 0 ) { + + printf("C3 %d R3 %d\n",C3,R3); + NbVarDuProblemeReduit = C3; + NbCntDuProblemeReduit = C3; + IndexCC = 3; + IndexRR = 2; + + for ( i = 0 ; i < NbCnt ; i++ ) Ligne[i] = -1; + for ( i = 0 ; i < NbVar ; i++ ) Colonne[i] = -1; + + ccDeb = (int) Csd->cc[IndexCC]; + ccFin = (int) Csd->cc[IndexCC+1]; + rrDeb = (int) Csd->rr[IndexRR]; + rrFin = (int) Csd->rr[IndexRR+1]; + + Resolu = NON_PNE; + MatriceFactorisee = (MATRICE * ) PRS_DumalgeFactoriserMatrice( Presolve, &MatriceAFactoriser, + NbVarDuProblemeReduit, + NbCntDuProblemeReduit, + ccDeb, + ccFin, + rrDeb, + rrFin, + (void *) Csd, + (void *) A, + Ligne, + Colonne, + &CodeRet, FactorisationOK, MatriceSinguliere ); + + if ( CodeRet != MatriceSinguliere ) { + /* On essaie de resoudre C3 */ + + PRS_DumalgeResoudrePrimal( Presolve, (void *) MatriceFactorisee, (void *) MatriceAFactoriser, + NbVarDuProblemeReduit, NbCntDuProblemeReduit, + + ccDeb, + ccFin, + rrDeb, + rrFin, + + (void *) Csd, + (void *) A, + + VarNewVarOld, + CntNewCntOld, + B, + &CodeRet, + FactorisationOK + ); + Resolu = OUI_PNE; + + } + else { + + } + + +} + + + +if ( C2 != 0 && Resolu ) { + printf("C2 %d R2 %d\n",C2,R2); + NbVarDuProblemeReduit = C2; + NbCntDuProblemeReduit = C2; + IndexCC = 2; + IndexRR = 1; + + for ( i = 0 ; i < NbCnt ; i++ ) Ligne[i] = -1; + for ( i = 0 ; i < NbVar ; i++ ) Colonne[i] = -1; + + ccDeb = (int) Csd->cc[IndexCC]; + ccFin = (int) Csd->cc[IndexCC+1]; + rrDeb = (int) Csd->rr[IndexRR]; + rrFin = (int) Csd->rr[IndexRR+1]; + + Resolu = NON_PNE; + MatriceFactorisee = (MATRICE * ) PRS_DumalgeFactoriserMatrice( Presolve, &MatriceAFactoriser, + NbVarDuProblemeReduit, + NbCntDuProblemeReduit, + ccDeb, + ccFin, + rrDeb, + rrFin, + (void *) Csd, + (void *) A, + Ligne, + Colonne, + &CodeRet, FactorisationOK, MatriceSinguliere ); + + if ( CodeRet != MatriceSinguliere ) { + + PRS_DumalgeResoudrePrimal( Presolve, (void *) MatriceFactorisee, (void *) MatriceAFactoriser, + NbVarDuProblemeReduit, NbCntDuProblemeReduit, + + ccDeb, + ccFin, + rrDeb, + rrFin, + + (void *) Csd, + (void *) A, + + VarNewVarOld, + CntNewCntOld, + B, + &CodeRet, + FactorisationOK + ); + + Resolu = OUI_PNE; + } +} +if ( C1 != 0 && Resolu == OUI_PNE && 0 ) { + NbVarDuProblemeReduit = C1; + NbCntDuProblemeReduit = C1; + IndexCC = 1; + IndexRR = 0; + for ( i = 0 ; i < NbCnt ; i++ ) Ligne[i] = -1; + for ( i = 0 ; i < NbVar ; i++ ) Colonne[i] = -1; + + if ( IndexCC == 0 ) ccDeb = 0; + else ccDeb = (int) Csd->cc[IndexCC]; + ccFin = (int) Csd->cc[IndexCC+1]; + if ( IndexRR == 0 ) rrDeb = 0; + else rrDeb = (int) Csd->rr[IndexRR]; + rrFin = (int) Csd->rr[IndexRR+1]; + + printf("resolution de la partie C1/R1 C1 %d R1 %d\n",C1,R1); + printf("ccDeb %d ccFin %d rrDeb %d rrFin %d \n",ccDeb,ccFin,rrDeb,rrFin); + MatriceFactorisee = (MATRICE * ) PRS_DumalgeFactoriserMatrice( Presolve, &MatriceAFactoriser, + NbVarDuProblemeReduit, + NbCntDuProblemeReduit, + ccDeb, + ccFin, + rrDeb, + rrFin, + (void *) Csd, + (void *) A, + Ligne, + Colonne, + &CodeRet, FactorisationOK, MatriceSinguliere ); + + if ( CodeRet == MatriceSinguliere ) { + + } + +} + +free( VarOldVarNew ); +free( VarNewVarOld ); + +free( CntOldCntNew ); +free( CntNewCntOld ); +free( Ligne ); +free( Colonne ); +free ( A->p ); +free ( A->i ); +free( A->x ); +free( A ); +free( B ); + +cs_dfree( Csd ); + +return; +} + +# endif + + diff --git a/src/ext/Sirius_Solver/presolve/prs_DM_factoriser_matrice.c b/src/ext/Sirius_Solver/presolve/prs_DM_factoriser_matrice.c new file mode 100644 index 0000000000..c6b6ec6b2e --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_DM_factoriser_matrice.c @@ -0,0 +1,165 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution d'un sous systeme issu de la decomposition + Dumalge-Mendelson + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if DUMALGE_MENDELSON == OUI_PNE + +# include "btf.h" +# include "btf_internal.h" + +# include "cs.h" + +/*----------------------------------------------------------------------------*/ + +void * PRS_DumalgeFactoriserMatrice( PRESOLVE * Presolve, + void ** MatriceAFactoriser, + int NbVarDuProblemeReduit, + int NbCntDuProblemeReduit, + int IndexCCdeb, + int IndexCCfin, + int IndexRRdeb, + int IndexRRfin, + void * Csd_in, + void * A_in, + int * Ligne, + int * Colonne, + char * CodeRet, + char FactorisationOK, + char MatriceSinguliere + ) +{ +int ic; int icMax; int icNew; csi ccDeb; csi ccFin; csi rrDeb; csi rrFin; +int i; int j; int l; csd * Csd; cs * A; int c; +PROBLEME_PNE * Pne; +MATRICE_A_FACTORISER * Matrice; MATRICE * MatriceFactorisee; + +*CodeRet = FactorisationOK; + +Csd = (csd *) Csd_in; +A = (cs *) A_in; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +ccDeb = (csi) IndexCCdeb; +ccFin = (csi) IndexCCfin; +rrDeb = (csi) IndexRRdeb; +rrFin = (csi) IndexRRfin; + +for ( j = 0 , i = ccDeb ; i < ccFin ; i++ ) { + /* Csd->q[i]: dans la numerotation du probleme soumis a dmperm */ + l = Csd->q[i]; + Colonne[l] = j; + j++; +} + +for ( j = 0 , i = rrDeb ; i < rrFin ; i++ ) { + /* Csd->p[i]: dans la numerotation du probleme soumis a dmperm */ + l = Csd->p[i]; + Ligne[l] = j; + j++; +} + +Matrice = (MATRICE_A_FACTORISER *) malloc( sizeof( MATRICE_A_FACTORISER ) ); +Matrice->NombreDeColonnes = NbVarDuProblemeReduit; +Matrice->IndexDebutDesColonnes = (int *) malloc( NbVarDuProblemeReduit * sizeof( int ) ); +Matrice->NbTermesDesColonnes = (int *) malloc( NbVarDuProblemeReduit * sizeof( int ) ); +Matrice->ValeurDesTermesDeLaMatrice = (double *) malloc( A->nzmax * sizeof( double ) ); +Matrice->IndicesDeLigne = (int *) malloc( A->nzmax * sizeof( int ) ); + +*MatriceAFactoriser = (void *) Matrice; + +icNew = 0; +for ( j = 0 , i = ccDeb ; i < ccFin ; i++ ) { + Matrice->IndexDebutDesColonnes[j] = icNew; + Matrice->NbTermesDesColonnes [j] = 0; + c = Csd->q[i]; + ic = A->p[c]; + icMax = A->p[c+1]; + /*printf("\nMatrice: c %d j %d i %d\n",c,j,i);*/ + while ( ic < icMax ) { + if ( Ligne[A->i[ic]] >= 0 ) { + Matrice->ValeurDesTermesDeLaMatrice[icNew] = A->x[ic]; + Matrice->IndicesDeLigne[icNew] = Ligne[A->i[ic]]; + Matrice->NbTermesDesColonnes[j]++; + /* + printf("ValeurDesTermesDeLaMatrice %e IndicesDeLigne %d A->i %d\n", + Matrice->ValeurDesTermesDeLaMatrice[icNew],Matrice->IndicesDeLigne[icNew],A->i[ic]); + */ + icNew++; + } + ic++; + } + j++; +} + +printf("DEBUT DE FACTORISATION\n"); +Matrice->ContexteDeLaFactorisation = LU_SIMPLEXE; +Matrice->UtiliserLesSuperLignes = NON_LU; +Matrice->FaireScalingDeLaMatrice = OUI_LU; + +Matrice->UtiliserLesValeursDePivotNulParDefaut = NON_LU; +Matrice->ValeurDuPivotMin = 1.e-10; +Matrice->ValeurDuPivotMinExtreme = 1.e-10; + +Matrice->SeuilPivotMarkowitzParDefaut = OUI_LU; +Matrice->FaireDuPivotageDiagonal = NON_LU; +Matrice->LaMatriceEstSymetriqueEnStructure = NON_LU; +Matrice->LaMatriceEstSymetrique = NON_LU; + +MatriceFactorisee = LU_Factorisation( Matrice ); + +printf("FIN DE FACTORISATION \n"); + +if ( MatriceFactorisee == NULL ) { + printf("PB factorisation \n"); + return( NULL ); +} + +if ( Matrice->ProblemeDeFactorisation == MATRICE_SINGULIERE ) { + printf("Matrice singuliere \n"); + *CodeRet = MatriceSinguliere; + return( (void *) MatriceFactorisee ); +} + +return( (void *) MatriceFactorisee ); + +} + +# endif + + diff --git a/src/ext/Sirius_Solver/presolve/prs_DM_resoudre_dual.c b/src/ext/Sirius_Solver/presolve/prs_DM_resoudre_dual.c new file mode 100644 index 0000000000..ae886ad76a --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_DM_resoudre_dual.c @@ -0,0 +1,222 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution d'un sous systeme issu de la decomposition + Dumalge-Mendelson + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if DUMALGE_MENDELSON == OUI_PNE + +# include "btf.h" +# include "btf_internal.h" + +# include "cs.h" + +/*----------------------------------------------------------------------------*/ + +void PRS_DumalgeResoudreDual( PRESOLVE * Presolve, + void * MatriceFact, + void * MatriceAFactoriser, + int NbVarDuProblemeReduit, + int NbCntDuProblemeReduit, + int IndexCCdeb, + int IndexCCfin, + int IndexRRdeb, + int IndexRRfin, + void * Csd_in, + void * A_in, + int * NuVarDeNewCnt, + int * NuCntDeNewVar, + double * C, + char * CalculOK + ) +{ +int Var; int YaErreur; int ic; int icMax; double X; int i; int j; int l; +csd * Csd; cs * A; csi ccDeb; csi ccFin; csi rrDeb; csi rrFin; int Cnt; +double * SecondMembreEtSolution; int CodeRetour; int NombreMaxIterationsDeRaffinement; +double ValeurMaxDesResidus; double * Verif; + +PROBLEME_PNE * Pne; +MATRICE_A_FACTORISER * Matrice; MATRICE * MatriceFactorisee; + +*CalculOK = OUI_PNE; + +Matrice = (MATRICE_A_FACTORISER *) MatriceAFactoriser; +MatriceFactorisee = (MATRICE *) MatriceFact; + +Csd = (csd *) Csd_in; +A = (cs *) A_in; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +ccDeb = (csi) IndexCCdeb; +ccFin = (csi) IndexCCfin; +rrDeb = (csi) IndexRRdeb; +rrFin = (csi) IndexRRfin; + +SecondMembreEtSolution = (double *) malloc( NbCntDuProblemeReduit * sizeof( double ) ); +Verif = (double *) malloc( NbCntDuProblemeReduit * sizeof( double ) ); + +for ( j = 0 , i = rrDeb ; i < rrFin ; i++ ) { + /* Csd->p[i]: dans la numerotation du probleme soumis a dmperm */ + l = Csd->p[i]; + Var = NuVarDeNewCnt[l]; + if ( Var < 0 || Var >= Pne->NombreDeVariablesTrav ) { + printf("Bug Resolution DM Var = %d\n",Var); + exit(0); + } + SecondMembreEtSolution[j] = C[Var]; + + /*if ( C[Var] != 0.0 ) printf("C[%d] = %e\n",Var,C[Var]);*/ + + j++; +} + +for ( l = 0 ; l < NbCntDuProblemeReduit ; l++ ) { + Verif[l] = SecondMembreEtSolution[l]; +} + +NombreMaxIterationsDeRaffinement = 2; +ValeurMaxDesResidus = 1.e-9; + +MatriceFactorisee->SauvegardeDuResultatIntermediaire = 0; +MatriceFactorisee->SecondMembreCreux = 0; + +LU_LuSolv( MatriceFactorisee, + SecondMembreEtSolution, /* Le vecteur du second membre et la solution */ + &CodeRetour, /* Le code retour ( 0 si tout s'est bien passe ) */ + Matrice, /* Peut etre NULL, dans ce cas on ne fait pas de raffinement */ + NombreMaxIterationsDeRaffinement, + ValeurMaxDesResidus /* En norme L infini i.e. le plus grand */ + ); + +printf("Fin de resolution CodeRetour %d\n",CodeRetour); + +for ( j = 0 ; j < NbVarDuProblemeReduit ; j++ ) { + ic = Matrice->IndexDebutDesColonnes[j]; + icMax = ic + Matrice->NbTermesDesColonnes[j]; + while ( ic < icMax ) { + i = Matrice->IndicesDeLigne[ic]; + Verif[i] -= Matrice->ValeurDesTermesDeLaMatrice[ic] * SecondMembreEtSolution[j]; + ic++; + } +} + +YaErreur = 0; +for ( i = 0 ; i < NbCntDuProblemeReduit ; i++ ) { + if ( fabs(Verif[i]) > 1.e-8 ) { + YaErreur = 1; + printf("Erreur[%d] = %e\n",i,Verif[i]); + } +} +YaErreur = 0; +if ( YaErreur == 0 ) printf("Pas d'erreur de resolution\n"); + +if ( YaErreur == 1 ) { + *CalculOK = NON_PNE; + return; +} + +YaErreur = 0; + +int Nb0; +Nb0 = 0; +for ( j = 0 , i = ccDeb ; i < ccFin ; i++ , j++) { + X = SecondMembreEtSolution[j]; + l = Csd->q[i]; + Cnt = NuCntDeNewVar[l]; + if ( Cnt < Pne->NombreDeContraintesTrav && Cnt >= 0 ) { + Presolve->Lambda[Cnt] = X; + Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_CONNU; + if ( Pne->SensContrainteTrav[Cnt] == '<' ) { + if ( Presolve->Lambda[Cnt] == 0.0 ) { + Nb0++; + /*printf("Contrainte d'inegalite %d : variable duale = %e\n",Cnt,Presolve->Lambda[Cnt]);*/ + Presolve->ContrainteInactive[Cnt] = OUI_PNE; + printf("Desactivation de la contrainte %d\n",Cnt); + } + if ( Presolve->Lambda[Cnt] > 1.e-9 ) { + /*printf("Contrainte d'inegalite %d : variable duale = %e signe positif\n",Cnt,Presolve->Lambda[Cnt]);*/ + } + } + else { + if ( Presolve->Lambda[Cnt] == 0.0 ) { + Nb0++; + + /*printf("Contrainte d'egalite %d : variable duale = %e\n",Cnt,Presolve->Lambda[Cnt]);*/ + + + } + } + + + /* Passer la colonne l dans le second membre */ + ic = A->p[l]; + icMax = A->p[l+1]; + while ( ic < icMax ) { + C[NuVarDeNewCnt[A->i[ic]]] -= A->x[ic] * X; + ic++; + } + + } + +} + +printf("Nombre de variables duales nulles %d\n",Nb0); + +if ( YaErreur == 1 ) exit(0); + +if ( YaErreur == 1 ) { + *CalculOK = NON_PNE; + return; +} + +LU_LibererMemoireLU( (MATRICE *) MatriceFactorisee ); + +free( Matrice->IndexDebutDesColonnes ); +free( Matrice->NbTermesDesColonnes ); +free( Matrice->ValeurDesTermesDeLaMatrice ); +free( Matrice->IndicesDeLigne ); +free( Matrice ); + +free( SecondMembreEtSolution ); +free( Verif ); + +return; +} + +# endif + + diff --git a/src/ext/Sirius_Solver/presolve/prs_DM_resoudre_primal.c b/src/ext/Sirius_Solver/presolve/prs_DM_resoudre_primal.c new file mode 100644 index 0000000000..3c39f8e380 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_DM_resoudre_primal.c @@ -0,0 +1,232 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution d'un sous systeme issu de la decomposition + Dumalge-Mendelson + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if DUMALGE_MENDELSON == OUI_PNE + +# include "btf.h" +# include "btf_internal.h" + +# include "cs.h" + +/*----------------------------------------------------------------------------*/ + +void PRS_DumalgeResoudrePrimal( PRESOLVE * Presolve, + void * MatriceFact, + void * MatriceAFactoriser, + int NbVarDuProblemeReduit, + int NbCntDuProblemeReduit, + int IndexCCdeb, + int IndexCCfin, + int IndexRRdeb, + int IndexRRfin, + void * Csd_in, + void * A_in, + int * VarNewVarOld, + int * CntNewCntOld, + double * B, + char * CodeRet, + char FactorisationOK + ) +{ +int Var; int YaErreur; int NbVarFix; +int ic; int icMax; double X; csi ccDeb; csi ccFin; csi rrDeb; csi rrFin; +int i; int j; int l; csd * Csd; cs * A; + +PROBLEME_PNE * Pne; + +MATRICE_A_FACTORISER * Matrice; MATRICE * MatriceFactorisee; + +int Cnt; + +double * SecondMembreEtSolution; int CodeRetour; int NombreMaxIterationsDeRaffinement; double ValeurMaxDesResidus; +double * Verif; + + +*CodeRet = FactorisationOK; + +Matrice = (MATRICE_A_FACTORISER *) MatriceAFactoriser; +MatriceFactorisee = (MATRICE *) MatriceFact; + +Csd = (csd *) Csd_in; +A = (cs *) A_in; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +ccDeb = (csi) IndexCCdeb; +ccFin = (csi) IndexCCfin; +rrDeb = (csi) IndexRRdeb; +rrFin = (csi) IndexRRfin; + +SecondMembreEtSolution = (double *) malloc( NbCntDuProblemeReduit * sizeof( double ) ); +Verif = (double *) malloc( NbCntDuProblemeReduit * sizeof( double ) ); + +for ( j = 0 , i = rrDeb ; i < rrFin ; i++ ) { + /* Csd->p[i]: dans la numerotation du probleme soumis a dmperm */ + l = Csd->p[i]; + Cnt = CntNewCntOld[l]; + if ( Cnt < 0 || Cnt >= Pne->NombreDeContraintesTrav ) { + printf("Bug Resolution DM Cnt = %d\n",Cnt); + exit(0); + } + SecondMembreEtSolution[j] = B[Cnt]; + + /*if ( B[Cnt] != 0.0 ) printf("B[%d] = %e\n",Cnt,B[Cnt]);*/ + + j++; +} + +for ( l = 0 ; l < NbCntDuProblemeReduit ; l++ ) { + Verif[l] = SecondMembreEtSolution[l]; +} + +NombreMaxIterationsDeRaffinement = 2; +ValeurMaxDesResidus = 1.e-9; + +MatriceFactorisee->SauvegardeDuResultatIntermediaire = 0; +MatriceFactorisee->SecondMembreCreux = 0; + +LU_LuSolv( MatriceFactorisee, + SecondMembreEtSolution, /* Le vecteur du second membre et la solution */ + &CodeRetour, /* Le code retour ( 0 si tout s'est bien passe ) */ + Matrice, /* Peut etre NULL, dans ce cas on ne fait pas de raffinement */ + NombreMaxIterationsDeRaffinement, + ValeurMaxDesResidus /* En norme L infini i.e. le plus grand */ + ); + +printf("Fin de resolution CodeRetour %d\n",CodeRetour); + +for ( j = 0 ; j < NbVarDuProblemeReduit ; j++ ) { + ic = Matrice->IndexDebutDesColonnes[j]; + icMax = ic + Matrice->NbTermesDesColonnes[j]; + while ( ic < icMax ) { + i = Matrice->IndicesDeLigne[ic]; + /* + printf("ValeurDesTermesDeLaMatrice colonne %d ligne %d NbTermesDesColonnes %d = %e\n",j,i, + Matrice->NbTermesDesColonnes[j],Matrice->ValeurDesTermesDeLaMatrice[ic]); + */ + Verif[i] -= Matrice->ValeurDesTermesDeLaMatrice[ic] * SecondMembreEtSolution[j]; + ic++; + } +} + +YaErreur = 0; +for ( i = 0 ; i < NbCntDuProblemeReduit ; i++ ) { + if ( fabs(Verif[i]) > 1.e-9 ) { + YaErreur = 1; + printf("Erreur[%d] = %e\n",i,Verif[i]); + } +} +if ( YaErreur == 0 ) printf("Pas d'erreur de resolution\n"); + +YaErreur = 0; +NbVarFix = 0; +for ( j = 0 , i = ccDeb ; i < ccFin ; i++ , j++) { + X = SecondMembreEtSolution[j]; + l = Csd->q[i]; + Var = VarNewVarOld[l]; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_FIXE ) { + printf("BUG variable %d est de type fixe\n",Var); + exit(0); + } + if ( Var < Pne->NombreDeVariablesTrav ) { + if ( X < Pne->UminTrav[Var] || X > Pne->UmaxTrav[Var] ) { + printf("Erreur Variable %d = %e Xmin %e Xmax %e\n",Var,X,Pne->UminTrav[Var],Pne->UmaxTrav[Var]); + YaErreur = 1; + } + + + printf("Fixation de la variable %d a %e Umin %e Umax %e\n",Var,X,Pne->UminTrav[Var],Pne->UmaxTrav[Var]); + + if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) { + printf("Variable entiere fixee\n"); + /* Verifier que c'est sur une borne sinon pas de solution */ + } + + + Pne->UTrav[Var] = X; + Pne->UminTrav[Var] = X; + Pne->UmaxTrav[Var] = X; + Pne->TypeDeBorneTrav[Var] = VARIABLE_FIXE; + Pne->TypeDeVariableTrav[Var] = REEL; + + + + NbVarFix++; + + /* Passer la colonne l dans le second membre */ + + ic = A->p[l]; + icMax = A->p[l+1]; + while ( ic < icMax ) { + B[CntNewCntOld[A->i[ic]]] -= A->x[ic] * X; + ic++; + } + + + } + else { + Cnt = Var - Pne->NombreDeVariablesTrav; + if ( X < 0.0 ) { + printf("Erreur Variable d'ecart contrainte %d %e \n",Cnt,SecondMembreEtSolution[j]); + YaErreur = 1; + } + Pne->SensContrainteTrav[Cnt] = '='; + } +} +if ( YaErreur == 1 ) exit(0); + +LU_LibererMemoireLU( (MATRICE *) MatriceFactorisee ); + +free( Matrice->IndexDebutDesColonnes ); +free( Matrice->NbTermesDesColonnes ); +free( Matrice->ValeurDesTermesDeLaMatrice ); +free( Matrice->IndicesDeLigne ); +free( Matrice ); + +free( SecondMembreEtSolution ); +free( Verif ); + +printf("Nombre de variables fixees par le primal %d\n",NbVarFix); + +return; +} + +# endif + + diff --git a/src/ext/Sirius_Solver/presolve/prs_DM_resoudre_systeme_transpose.c b/src/ext/Sirius_Solver/presolve/prs_DM_resoudre_systeme_transpose.c new file mode 100644 index 0000000000..0a423e6de1 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_DM_resoudre_systeme_transpose.c @@ -0,0 +1,296 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution d'un sous systeme issu de la decomposition + Dumalge-Mendelson + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if DUMALGE_MENDELSON == OUI_PNE + +# include "btf.h" +# include "btf_internal.h" + +# include "cs.h" + +/*----------------------------------------------------------------------------*/ + +void * PRS_DumalgeMendelsonResoudreSystemeTranspose( PRESOLVE * Presolve, + int NbVarDuProblemeReduit, + int NbCntDuProblemeReduit, + int IndexCCdeb, + int IndexCCfin, + int IndexRRdeb, + int IndexRRfin, + void * Csd_in, + void * A_in, + int * Ligne, + int * Colonne, + int * NuVarDeNewCnt, + int * NuCntDeNewVar, + double * C, + char * CodeRet, + char FactorisationOK, + char MatriceSinguliere + ) +{ +int Var; int il; int ilMax; int ilAi; int YaErreur; +int ic; int icMax; int icNew; double X; +int i; int j; int l; csd * Csd; cs * A; csi ccDeb; csi ccFin; csi rrDeb; csi rrFin; + +PROBLEME_PNE * Pne; long NombreDeVariables; + +MATRICE_A_FACTORISER * Matrice; MATRICE * MatriceFactorisee; + +int Cnt; + +int * MdebTrav; int * NbTermTrav; int * NuvarTrav; double * ATrav; +int c; + +*CodeRet = FactorisationOK; + +Csd = (csd *) Csd_in; +A = (cs *) A_in; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +ccDeb = (csi) IndexCCdeb; +ccFin = (csi) IndexCCfin; +rrDeb = (csi) IndexRRdeb; +rrFin = (csi) IndexRRfin; + +for ( j = 0 , i = ccDeb ; i < ccFin ; i++ ) { + /* Csd->q[i]: dans la numerotation du probleme soumis a dmperm */ + l = Csd->q[i]; + Colonne[l] = j; + j++; +} + +for ( j = 0 , i = rrDeb ; i < rrFin ; i++ ) { + /* Csd->p[i]: dans la numerotation du probleme soumis a dmperm */ + l = Csd->p[i]; + Ligne[l] = j; + j++; +} + +Matrice = (MATRICE_A_FACTORISER *) malloc( sizeof( MATRICE_A_FACTORISER ) ); +Matrice->NombreDeColonnes = NbVarDuProblemeReduit; +Matrice->IndexDebutDesColonnes = (int *) malloc( NbVarDuProblemeReduit * sizeof( int ) ); +Matrice->NbTermesDesColonnes = (int *) malloc( NbVarDuProblemeReduit * sizeof( int ) ); +Matrice->ValeurDesTermesDeLaMatrice = (double *) malloc( A->nzmax * sizeof( double ) ); +Matrice->IndicesDeLigne = (int *) malloc( A->nzmax * sizeof( int ) ); + +icNew = 0; +for ( j = 0 , i = ccDeb ; i < ccFin ; i++ ) { + Matrice->IndexDebutDesColonnes[j] = icNew; + Matrice->NbTermesDesColonnes [j] = 0; + c = Csd->q[i]; + ic = A->p[c]; + icMax = A->p[c+1]; + while ( ic < icMax ) { + if ( Ligne[A->i[ic]] >= 0 ) { + Matrice->ValeurDesTermesDeLaMatrice[icNew] = A->x[ic]; + Matrice->IndicesDeLigne[icNew] = Ligne[A->i[ic]]; + Matrice->NbTermesDesColonnes[j]++; + icNew++; + } + ic++; + } + j++; +} + +printf("DEBUT DE FACTORISATION\n"); +Matrice->ContexteDeLaFactorisation = LU_SIMPLEXE; +Matrice->UtiliserLesSuperLignes = NON_LU; +Matrice->FaireScalingDeLaMatrice = NON_LU; + +Matrice->UtiliserLesValeursDePivotNulParDefaut = NON_LU; +Matrice->ValeurDuPivotMin = 1.e-8; +Matrice->ValeurDuPivotMinExtreme = 1.e-8; + +Matrice->SeuilPivotMarkowitzParDefaut = OUI_LU; +Matrice->FaireDuPivotageDiagonal = NON_LU; +Matrice->LaMatriceEstSymetriqueEnStructure = NON_LU; +Matrice->LaMatriceEstSymetrique = NON_LU; + +MatriceFactorisee = LU_Factorisation( Matrice ); +if ( MatriceFactorisee == NULL ) { + printf("PB factorisation \n"); + exit(0); +} + +if ( Matrice->ProblemeDeFactorisation == MATRICE_SINGULIERE ) { + printf("Matrice singuliere \n"); + *CodeRet = MatriceSinguliere; + return( (void *) MatriceFactorisee ); +} + +printf("FIN DE FACTORISATION\n"); +return; + +double * SecondMembreEtSolution; int CodeRetour; int NombreMaxIterationsDeRaffinement; double ValeurMaxDesResidus; +double * Verif; + +SecondMembreEtSolution = (double *) malloc( NbCntDuProblemeReduit * sizeof( double ) ); +Verif = (double *) malloc( NbCntDuProblemeReduit * sizeof( double ) ); + +for ( j = 0 , i = rrDeb ; i < rrFin ; i++ , j++) { + /* Csd->p[i]: dans la numerotation du probleme soumis a dmperm */ + l = Csd->p[i]; + Var = NuVarDeNewCnt[l]; + if ( Var < 0 || Var >= Pne->NombreDeVariablesTrav ) { + printf("Bug Resolution DM Var = %d\n",Var); + exit(0); + } + SecondMembreEtSolution[j] = C[Var]; + + if ( C[Var] != 0.0 ) printf("C[%d] = %e\n",Var,C[Var]); + +} + +for ( l = 0 ; l < NbCntDuProblemeReduit ; l++ ) { + Verif[l] = SecondMembreEtSolution[l]; +} + +NombreMaxIterationsDeRaffinement = 0; +ValeurMaxDesResidus = 1.e-9; + +MatriceFactorisee->SauvegardeDuResultatIntermediaire = 0; +MatriceFactorisee->SecondMembreCreux = 0; + +LU_LuSolv( MatriceFactorisee, + SecondMembreEtSolution, /* Le vecteur du second membre et la solution */ + &CodeRetour, /* Le code retour ( 0 si tout s'est bien passe ) */ + Matrice, /* Peut etre NULL, dans ce cas on ne fait pas de raffinement */ + NombreMaxIterationsDeRaffinement, + ValeurMaxDesResidus /* En norme L infini i.e. le plus grand */ + ); + +printf("Fin de resolution CodeRetour %d\n",CodeRetour); + +for ( j = 0 ; j < NbVarDuProblemeReduit ; j++ ) { + ic = Matrice->IndexDebutDesColonnes[j]; + icMax = ic + Matrice->NbTermesDesColonnes[j]; + while ( ic < icMax ) { + i = Matrice->IndicesDeLigne[ic]; + Verif[i] -= Matrice->ValeurDesTermesDeLaMatrice[ic] * SecondMembreEtSolution[j]; + ic++; + } +} + +YaErreur = 0; +for ( i = 0 ; i < NbCntDuProblemeReduit ; i++ ) { + if ( fabs(Verif[i]) > 1.e-8 ) { + YaErreur = 1; + printf("Erreur[%d] = %e\n",i,Verif[i]); + } +} +if ( YaErreur == 0 ) printf("Pas d'erreur de resolution\n"); + +YaErreur = 0; + +int Nb0; +Nb0 = 0; +for ( j = 0 , i = ccDeb ; i < ccFin ; i++ , j++) { + X = SecondMembreEtSolution[j]; + l = Csd->q[i]; + Cnt = NuCntDeNewVar[l]; + if ( Cnt < Pne->NombreDeContraintesTrav ) { + /* + if ( X < Pne->UminTrav[Var] || X > Pne->UmaxTrav[Var] ) { + printf("Erreur Variable %d = %e Xmin %e Xmax %e\n",Var,X,Pne->UminTrav[Var],Pne->UmaxTrav[Var]); + YaErreur = 1; + } + */ + /* printf("u %e \n",X); */ + + Presolve->Lambda[Cnt] = X; + Presolve->LambdaEstConnu[Cnt] = OUI_PNE; + if ( Pne->SensContrainteTrav[Cnt] == '<' ) { + if ( Presolve->Lambda[Cnt] == 0.0 ) { + Nb0++; + printf("Contrainte d'inegalite %d : variable duale = %e\n",Cnt,Presolve->Lambda[Cnt]); + if ( Presolve->LaContrainteEstBornante[Cnt] != OUI_PNE || 1 ) { + Presolve->ContrainteInactive[Cnt] = OUI_PNE; + printf("Desactivation de la contrainte %d\n",Cnt); + } + } + } + else { + if ( Presolve->Lambda[Cnt] == 0.0 ) { + Nb0++; + /* + printf("Contrainte d'egalite %d : variable duale = %e\n",Cnt,Presolve->Lambda[Cnt]); + if ( Presolve->LaContrainteEstBornante[Cnt] != OUI_PNE || 1 ) { + Presolve->ContrainteInactive[Cnt] = OUI_PNE; + printf("Desactivation de la contrainte %d\n",Cnt); + } + */ + } + } + + + /* Passer la colonne l dans le second membre */ + ic = A->p[l]; + icMax = A->p[l+1]; + while ( ic < icMax ) { + C[NuVarDeNewCnt[A->i[ic]]] -= A->x[ic] * X; + ic++; + } + + } + +} + +printf("Nombre de variables duales nulles %d\n",Nb0); + +if ( YaErreur == 1 ) exit(0); + +LU_LibererMemoireLU( (MATRICE *) MatriceFactorisee ); + +free( Matrice->IndexDebutDesColonnes ); +free( Matrice->NbTermesDesColonnes ); +free( Matrice->ValeurDesTermesDeLaMatrice ); +free( Matrice->IndicesDeLigne ); +free( Matrice ); + +free( SecondMembreEtSolution ); +free( Verif ); + +return; +} + +# endif + + diff --git a/src/ext/Sirius_Solver/presolve/prs_alloc_reductions.c b/src/ext/Sirius_Solver/presolve/prs_alloc_reductions.c new file mode 100644 index 0000000000..7b9732c157 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_alloc_reductions.c @@ -0,0 +1,107 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Alloc des structures pour les operations de reduction du + presolve. + + RQ: transfere dans pne + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ +void PRS_AllocTablesDeSubstitution( void * ProblemePne ) +{ +int NombreDeVariables; int ilMax; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) ProblemePne; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +ilMax = Pne->TailleAlloueePourLaMatriceDesContraintes; + +Pne->IndexLibreVecteurDeSubstitution = 0; +Pne->NbVariablesSubstituees = 0; + +Pne->NumeroDesVariablesSubstituees = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->NumeroDesVariablesSubstituees == NULL ) return; + +Pne->ValeurDeLaConstanteDeSubstitution = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->ValeurDeLaConstanteDeSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); + return; +} + +Pne->IndiceDebutVecteurDeSubstitution = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->IndiceDebutVecteurDeSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + return; +} + +Pne->NbTermesVecteurDeSubstitution = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->NbTermesVecteurDeSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); + return; +} + +Pne->CoeffDeSubstitution = (double *) malloc( ilMax * sizeof( double ) ); +if ( Pne->CoeffDeSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); free( Pne->NbTermesVecteurDeSubstitution ); + return; +} + +Pne->NumeroDeVariableDeSubstitution = (int *) malloc( ilMax * sizeof( int ) ); +if ( Pne->NumeroDeVariableDeSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); free( Pne->NbTermesVecteurDeSubstitution ); + free( Pne->CoeffDeSubstitution ); + return; +} + +Pne->CoutDesVariablesSubstituees = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->CoutDesVariablesSubstituees == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); free( Pne->NbTermesVecteurDeSubstitution ); + free( Pne->CoeffDeSubstitution ); free( Pne->NumeroDeVariableDeSubstitution ); + return; +} + +Pne->ContrainteDeLaSubstitution = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->ContrainteDeLaSubstitution == NULL ) { + free( Pne->NumeroDesVariablesSubstituees ); free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); free( Pne->NbTermesVecteurDeSubstitution ); + free( Pne->CoeffDeSubstitution ); free( Pne->NumeroDeVariableDeSubstitution ); + free( Pne->CoutDesVariablesSubstituees ); + return; +} + +return; +} + diff --git a/src/ext/Sirius_Solver/presolve/prs_allocations.c b/src/ext/Sirius_Solver/presolve/prs_allocations.c new file mode 100644 index 0000000000..aab6d430d0 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_allocations.c @@ -0,0 +1,427 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Allocation des structures pour le Presolve-> + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" + +# include "pne_define.h" + +# include "prs_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PRS_AllocationsStructure( PRESOLVE * Presolve ) +{ +int Var; int NbCntAlloc; PROBLEME_PNE * Pne; int NombreDeVariables; int NombreDeContraintes; +int NbT; int ic; int * ParColonnePremiereVariable; int * ParColonneVariableSuivante; int * Cdeb; +int * Csui; double * A; int * NumContrainte; char * ContrainteInactive; int * TypeDeBornePourPresolve; +int MxTrm; int il; int ilMax; int Cnt; int * ParLignePremiereContrainte; int * ParLigneContrainteSuivante; +int * Mdeb; int * NbTerm; int * Nuvar; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NbCntAlloc = Pne->NombreDeContraintesAllouees; +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; + +Presolve->MinContrainte = (double *) malloc( NbCntAlloc * sizeof( double ) ); +Presolve->MaxContrainte = (double *) malloc( NbCntAlloc * sizeof( double ) ); +Presolve->MinContrainteCalcule = (char *) malloc( NbCntAlloc * sizeof( char ) ); +Presolve->MaxContrainteCalcule = (char *) malloc( NbCntAlloc * sizeof( char ) ); + +Presolve->Lambda = (double *) malloc( NbCntAlloc * sizeof( double ) ); +Presolve->LambdaMin = (double *) malloc( NbCntAlloc * sizeof( double ) ); +Presolve->LambdaMax = (double *) malloc( NbCntAlloc * sizeof( double ) ); +Presolve->ConnaissanceDeLambda = (char *) malloc( NbCntAlloc * sizeof( char ) ); + +Presolve->ContrainteInactive = (char *) malloc( NbCntAlloc * sizeof( char ) ); + +Presolve->ContrainteBornanteSuperieurement = (int *) malloc( NombreDeVariables * sizeof( int ) ); +Presolve->ContrainteBornanteInferieurement = (int *) malloc( NombreDeVariables * sizeof( int ) ); +/* Indicateurs pour obliger a conserver les bornes du presolve. Cela peut etre necessaire lorsqu'on supprime une + contrainte bornante */ +Presolve->ConserverLaBorneSupDuPresolve = (char *) malloc( NombreDeVariables * sizeof( char ) ); +Presolve->ConserverLaBorneInfDuPresolve = (char *) malloc( NombreDeVariables * sizeof( char ) ); + +Presolve->ParColonnePremiereVariable = (int *) malloc( (NombreDeContraintes+1) * sizeof( int ) ); +Presolve->ParColonneVariableSuivante = (int *) malloc( NombreDeVariables * sizeof( int ) ); + +Presolve->ParLignePremiereContrainte = (int *) malloc( (NombreDeVariables+1) * sizeof( int ) ); +Presolve->ParLigneContrainteSuivante = (int *) malloc( NombreDeContraintes * sizeof( int ) ); + +Presolve->VariableEquivalente = (int *) malloc( NombreDeVariables * sizeof( int ) ); + +/* Les bornes inf pour presolve et type de borne pour presolve sont toujours egales ou plus + resserees que les valeurs natives */ +Presolve->ValeurDeXPourPresolve = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Presolve->BorneInfPourPresolve = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Presolve->BorneSupPourPresolve = (double *) malloc( NombreDeVariables * sizeof( double ) ); +Presolve->TypeDeBornePourPresolve = (int *) malloc( NombreDeVariables * sizeof( int ) ); +Presolve->TypeDeValeurDeBorneInf = (char *) malloc( NombreDeVariables * sizeof( int ) ); +Presolve->TypeDeValeurDeBorneSup = (char *) malloc( NombreDeVariables * sizeof( int ) ); + +if ( Presolve->MinContrainte == NULL || Presolve->MaxContrainte == NULL || + Presolve->MinContrainteCalcule == NULL || Presolve->MaxContrainteCalcule == NULL || + Presolve->Lambda == NULL || Presolve->LambdaMin == NULL || + Presolve->LambdaMax == NULL || Presolve->ConnaissanceDeLambda == NULL || + Presolve->ContrainteInactive == NULL || Presolve->ContrainteBornanteSuperieurement == NULL || + Presolve->ParColonnePremiereVariable == NULL || Presolve->ParColonneVariableSuivante == NULL || + Presolve->ParLignePremiereContrainte == NULL || Presolve->ParLigneContrainteSuivante == NULL || + Presolve->VariableEquivalente == NULL || + Presolve->ContrainteBornanteInferieurement == NULL || Presolve->ConserverLaBorneSupDuPresolve == NULL || + Presolve->ConserverLaBorneInfDuPresolve == NULL || Presolve->ValeurDeXPourPresolve == NULL || + Presolve->BorneInfPourPresolve == NULL || Presolve->BorneSupPourPresolve == NULL || + Presolve->TypeDeBornePourPresolve == NULL || Presolve->TypeDeValeurDeBorneInf == NULL || + Presolve->TypeDeValeurDeBorneSup == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PRS_AllocationsStructure \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} + +memset( (char *) Presolve->ConnaissanceDeLambda , LAMBDA_NON_INITIALISE, NombreDeContraintes * sizeof( char ) ); +memset( (char *) Presolve->ContrainteInactive, NON_PNE, NombreDeContraintes * sizeof( char ) ); +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + Presolve->LambdaMin[Cnt] = -LINFINI_PNE; + Presolve->LambdaMax[Cnt] = LINFINI_PNE; +} + +memset( (char *) Presolve->ConserverLaBorneSupDuPresolve, NON_PNE, NombreDeVariables * sizeof( char ) ); +memset( (char *) Presolve->ConserverLaBorneInfDuPresolve, NON_PNE, NombreDeVariables * sizeof( char ) ); + +memset( (char *) Presolve->VariableEquivalente, 0, NombreDeVariables * sizeof( int ) ); + +memcpy( (char *) Presolve->ValeurDeXPourPresolve, (char *) Pne->UTrav, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) Presolve->BorneInfPourPresolve, (char *) Pne->UminTrav, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) Presolve->BorneSupPourPresolve, (char *) Pne->UmaxTrav, NombreDeVariables * sizeof( double ) ); +memcpy( (char *) Presolve->TypeDeBornePourPresolve, (char *) Pne->TypeDeBorneTrav, NombreDeVariables * sizeof( int ) ); + +memset( (char *) Presolve->TypeDeValeurDeBorneInf, VALEUR_NATIVE, NombreDeVariables * sizeof( char ) ); +memset( (char *) Presolve->TypeDeValeurDeBorneSup, VALEUR_NATIVE, NombreDeVariables * sizeof( char ) ); + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + Presolve->ContrainteBornanteSuperieurement[Var] = -1; + Presolve->ContrainteBornanteInferieurement[Var] = -1; +} + +/* Classement des colonnes en fonction du nombre de termes */ +ParColonnePremiereVariable = Presolve->ParColonnePremiereVariable; +ParColonneVariableSuivante = Presolve->ParColonneVariableSuivante; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ContrainteInactive = Presolve->ContrainteInactive; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +A = Pne->ATrav; +NumContrainte = Pne->NumContrainteTrav; +for ( NbT = 0 ; NbT <= NombreDeContraintes ; NbT++ ) ParColonnePremiereVariable[NbT] = -1; +MxTrm = -1; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) continue; + NbT = 0; + ic = Cdeb[Var]; + while ( ic >= 0 ) { + if ( A[ic] != 0 ) { + if ( ContrainteInactive[NumContrainte[ic]] != OUI_PNE ) NbT++; + } + ic = Csui[ic]; + } + if ( NbT > MxTrm ) MxTrm = NbT; + ic = ParColonnePremiereVariable[NbT]; + ParColonnePremiereVariable[NbT] = Var; + ParColonneVariableSuivante[Var] = ic; +} +Presolve->NbMaxTermesDesColonnes = MxTrm; + +/* Classement des lignes en fonction du nombre de termes */ +ParLignePremiereContrainte = Presolve->ParLignePremiereContrainte; +ParLigneContrainteSuivante = Presolve->ParLigneContrainteSuivante; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +for ( NbT = 0 ; NbT <= NombreDeVariables ; NbT++ ) ParLignePremiereContrainte[NbT] = -1; +MxTrm = -1; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteInactive[Cnt] == OUI_PNE ) continue; + NbT = 0; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( A[il] != 0 ) { + if ( TypeDeBornePourPresolve[Nuvar[il]] != VARIABLE_FIXE ) NbT++; + } + il++; + } + if ( NbT > MxTrm ) MxTrm = NbT; + il = ParLignePremiereContrainte[NbT]; + + ParLignePremiereContrainte[NbT] = Cnt; + ParLigneContrainteSuivante[Cnt] = il; + +} +Presolve->NbMaxTermesDesLignes = MxTrm; + + +return; + +/* Partie transferee dans pne */ + +/* Preparation des infos sur les reductions qui seront utilisees dans le postsolve */ +if ( Pne->NombreDOperationsDePresolve != 0 ) { + printf("************ Nouveau presolve apres variable probing *************************\n"); + return; +} + +Pne->NombreDOperationsDePresolve = 0; +Pne->TailleTypeDOperationDePresolve = NombreDeVariables + NombreDeContraintes; + +Pne->TypeDOperationDePresolve = (char *) malloc( Pne->TailleTypeDOperationDePresolve * sizeof( char ) ); +if ( Pne->TypeDOperationDePresolve == NULL ) return; +Pne->IndexDansLeTypeDOperationDePresolve = (int *) malloc( Pne->TailleTypeDOperationDePresolve * sizeof( int ) ); +if ( Pne->IndexDansLeTypeDOperationDePresolve == NULL ) return; + +/* Colonnes colineaires */ +Pne->NbCouplesDeVariablesColineaires = 0; +Pne->PremiereVariable = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->PremiereVariable == NULL ) return; +Pne->XminPremiereVariable = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->XminPremiereVariable == NULL ) return; +Pne->XmaxPremiereVariable = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->XmaxPremiereVariable == NULL ) return; + +Pne->DeuxiemeVariable = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( Pne->DeuxiemeVariable == NULL ) return; +Pne->XminDeuxiemeVariable = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->XminDeuxiemeVariable == NULL ) return; +Pne->XmaxDeuxiemeVariable = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->XmaxDeuxiemeVariable == NULL ) return; + +Pne->ValeurDeNu = (double *) malloc( NombreDeVariables * sizeof( double ) ); +if ( Pne->ValeurDeNu == NULL ) return; + +/* Variables non bornees substituees car colonne singleton ou variables substituees a + l'aide d'un doubleton */ +PRS_AllocTablesDeSubstitution( (void *) Pne ); + +/* Contraintes singleton */ +Pne->NbLignesSingleton = 0; +Pne->NumeroDeLaContrainteSingleton = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->NumeroDeLaContrainteSingleton == NULL ) return; +Pne->VariableDeLaContrainteSingleton = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->VariableDeLaContrainteSingleton == NULL ) return; +Pne->SecondMembreDeLaContrainteSingleton = (double *) malloc( NombreDeContraintes * sizeof( double ) ); +if ( Pne->SecondMembreDeLaContrainteSingleton == NULL ) return; + +/* Forcing constraints */ +Pne->NbForcingConstraints = 0; +Pne->NumeroDeLaForcingConstraint = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->NumeroDeLaForcingConstraint == NULL ) return; + +/* Contraintes colineaires */ +Pne->NbSuppressionsDeContraintesColineaires = 0; +Pne->ContrainteConservee = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->ContrainteConservee == NULL ) return; +Pne->ContrainteSupprimee = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->ContrainteSupprimee == NULL ) return; + +/* Contraintes desactivees */ +Pne->NombreDeContraintesInactives = 0; +Pne->NumeroDesContraintesInactives = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +if ( Pne->NumeroDesContraintesInactives == NULL ) return; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_LiberationStructure( PRESOLVE * Presolve ) +{ +PROBLEME_PNE * Pne; int ilMax; int NombreDeVariables; + +if ( Presolve == NULL ) return; + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + if ( Pne != NULL ) Pne->ProblemePrsDuSolveur = NULL; + MEM_Quit( Presolve->Tas ); + return; +# endif + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; +if ( Pne != NULL ) Pne->ProblemePrsDuSolveur = NULL; +else return; + +free( Presolve->MinContrainte ); +free( Presolve->MaxContrainte ); +free( Presolve->MinContrainteCalcule ); +free( Presolve->MaxContrainteCalcule ); +free( Presolve->Lambda ); +free( Presolve->LambdaMin ); +free( Presolve->LambdaMax ); +free( Presolve->ConnaissanceDeLambda ); +free( Presolve->ContrainteInactive ); +free( Presolve->ContrainteBornanteSuperieurement ); +free( Presolve->ContrainteBornanteInferieurement ); +free( Presolve->ConserverLaBorneSupDuPresolve ); +free( Presolve->ConserverLaBorneInfDuPresolve ); +free( Presolve->ParColonnePremiereVariable ); +free( Presolve->ParColonneVariableSuivante ); +free( Presolve->ParLignePremiereContrainte ); +free( Presolve->ParLigneContrainteSuivante ); +free( Presolve->VariableEquivalente ); +free( Presolve->ValeurDeXPourPresolve ); +free( Presolve->BorneInfPourPresolve ); +free( Presolve->BorneSupPourPresolve ); +free( Presolve->TypeDeBornePourPresolve ); +free( Presolve->TypeDeValeurDeBorneInf ); +free( Presolve->TypeDeValeurDeBorneSup ); + +free( Presolve ); + +return; + +/* Partie transferee dans pne */ + +/* Recuperation de la place des reductions du presolve */ + +if ( Pne->NombreDOperationsDePresolve != 0 ) { + Pne->TailleTypeDOperationDePresolve = Pne->NombreDOperationsDePresolve; + Pne->TypeDOperationDePresolve = (char *) realloc( Pne->TypeDOperationDePresolve, Pne->TailleTypeDOperationDePresolve * sizeof( char ) ); + Pne->IndexDansLeTypeDOperationDePresolve = (int *) realloc( Pne->IndexDansLeTypeDOperationDePresolve, Pne->TailleTypeDOperationDePresolve * sizeof( int ) ); +} + +if ( Pne->NumeroDesVariablesSubstituees != NULL ) { + NombreDeVariables = Pne->NbVariablesSubstituees; + ilMax = Pne->IndexLibreVecteurDeSubstitution; + Pne->NumeroDesVariablesSubstituees = (int *) realloc( Pne->NumeroDesVariablesSubstituees, NombreDeVariables * sizeof( int ) ); + Pne->CoutDesVariablesSubstituees = (double *) realloc( Pne->CoutDesVariablesSubstituees, NombreDeVariables * sizeof( double ) ); + Pne->ContrainteDeLaSubstitution = (int *) realloc( Pne->ContrainteDeLaSubstitution, NombreDeVariables * sizeof( int ) ); + Pne->ValeurDeLaConstanteDeSubstitution = (double *) realloc( Pne->ValeurDeLaConstanteDeSubstitution, NombreDeVariables * sizeof( double ) ); + Pne->IndiceDebutVecteurDeSubstitution = (int *) realloc( Pne->IndiceDebutVecteurDeSubstitution, NombreDeVariables * sizeof( int ) ); + Pne->NbTermesVecteurDeSubstitution = (int *) realloc( Pne->NbTermesVecteurDeSubstitution, NombreDeVariables * sizeof( int ) ); + Pne->CoeffDeSubstitution = (double *) realloc( Pne->CoeffDeSubstitution, ilMax * sizeof( double ) ); + Pne->NumeroDeVariableDeSubstitution = (int *) realloc( Pne->NumeroDeVariableDeSubstitution, ilMax * sizeof( int ) ); +} +else { + free( Pne->NumeroDesVariablesSubstituees ); + free( Pne->CoutDesVariablesSubstituees ); + free( Pne->ContrainteDeLaSubstitution ); + free( Pne->ValeurDeLaConstanteDeSubstitution ); + free( Pne->IndiceDebutVecteurDeSubstitution ); + free( Pne->NbTermesVecteurDeSubstitution ); + free( Pne->CoeffDeSubstitution ); + free( Pne->NumeroDeVariableDeSubstitution ); + Pne->NumeroDesVariablesSubstituees = NULL; + Pne->CoutDesVariablesSubstituees = NULL; + Pne->ContrainteDeLaSubstitution = NULL; + Pne->ValeurDeLaConstanteDeSubstitution = NULL; + Pne->IndiceDebutVecteurDeSubstitution = NULL; + Pne->NbTermesVecteurDeSubstitution = NULL; + Pne->CoeffDeSubstitution = NULL; + Pne->NumeroDeVariableDeSubstitution = NULL; +} + +if ( Pne->NbCouplesDeVariablesColineaires != 0 ) { + NombreDeVariables = Pne->NbCouplesDeVariablesColineaires; + Pne->PremiereVariable = (int *) realloc( Pne->PremiereVariable , NombreDeVariables * sizeof( int ) ); + Pne->XminPremiereVariable = (double *) realloc( Pne->XminPremiereVariable, NombreDeVariables * sizeof( double ) ); + Pne->XmaxPremiereVariable = (double *) realloc( Pne->XmaxPremiereVariable, NombreDeVariables * sizeof( double ) ); + Pne->DeuxiemeVariable = (int *) realloc( Pne->DeuxiemeVariable , NombreDeVariables * sizeof( int ) ); + Pne->XminDeuxiemeVariable = (double *) realloc( Pne->XminDeuxiemeVariable, NombreDeVariables * sizeof( double ) ); + Pne->XmaxDeuxiemeVariable = (double *) realloc( Pne->XmaxDeuxiemeVariable, NombreDeVariables * sizeof( double ) ); + Pne->ValeurDeNu = (double *) realloc( Pne->ValeurDeNu , NombreDeVariables * sizeof( double ) ); +} +else { + free( Pne->PremiereVariable ); + free( Pne->XminPremiereVariable ); + free( Pne->XmaxPremiereVariable ); + free( Pne->DeuxiemeVariable ); + free( Pne->XminDeuxiemeVariable ); + free( Pne->XmaxDeuxiemeVariable ); + free( Pne->ValeurDeNu ); + Pne->PremiereVariable = NULL; + Pne->XminPremiereVariable = NULL; + Pne->XmaxPremiereVariable = NULL; + Pne->DeuxiemeVariable = NULL; + Pne->XminDeuxiemeVariable = NULL; + Pne->XmaxDeuxiemeVariable = NULL; + Pne->ValeurDeNu = NULL; +} + +/* Contraintes singleton */ +if ( Pne->NbLignesSingleton != 0 ) { + ilMax = Pne->NbLignesSingleton; + Pne->NumeroDeLaContrainteSingleton = (int *) realloc( Pne->NumeroDeLaContrainteSingleton , ilMax * sizeof( int ) ); + Pne->VariableDeLaContrainteSingleton = (int *) realloc( Pne->VariableDeLaContrainteSingleton , ilMax * sizeof( int ) ); + Pne->SecondMembreDeLaContrainteSingleton = (double *) realloc( Pne->SecondMembreDeLaContrainteSingleton , ilMax * sizeof( double ) ); +} +else { + free( Pne->NumeroDeLaContrainteSingleton ); + free( Pne->VariableDeLaContrainteSingleton ); + free( Pne->SecondMembreDeLaContrainteSingleton ); + Pne->NumeroDeLaContrainteSingleton = NULL; + Pne->VariableDeLaContrainteSingleton = NULL; + Pne->SecondMembreDeLaContrainteSingleton = NULL; +} + +/* Forcing constraints */ +if ( Pne->NbForcingConstraints != 0 ) { + ilMax = Pne->NbForcingConstraints; + Pne->NumeroDeLaForcingConstraint = (int *) realloc( Pne->NumeroDeLaForcingConstraint, ilMax * sizeof( int ) ); +} +else { + free( Pne->NumeroDeLaForcingConstraint ); + Pne->NumeroDeLaForcingConstraint = NULL; +} + +/* Contraintes colineaires */ +if ( Pne->NbSuppressionsDeContraintesColineaires > 0 ) { + ilMax = Pne->NbSuppressionsDeContraintesColineaires; + Pne->ContrainteConservee = (int *) realloc( Pne->ContrainteConservee, ilMax * sizeof( int ) ); + Pne->ContrainteSupprimee = (int *) realloc( Pne->ContrainteSupprimee, ilMax * sizeof( int ) ); +} +else { + free( Pne->ContrainteConservee ); + free( Pne->ContrainteSupprimee ); + Pne->ContrainteConservee = NULL; + Pne->ContrainteSupprimee = NULL; +} + +/* Contraintes inactives */ +if ( Pne->NombreDeContraintesInactives != 0 ) { + ilMax = Pne->NombreDeContraintesInactives; + Pne->NumeroDesContraintesInactives = (int *) realloc( Pne->NumeroDesContraintesInactives, ilMax * sizeof( int ) ); +} +else { + free( Pne->NumeroDesContraintesInactives ); + Pne->NumeroDesContraintesInactives = NULL; +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/presolve/prs_ameliorer_bornes.c b/src/ext/Sirius_Solver/presolve/prs_ameliorer_bornes.c new file mode 100644 index 0000000000..f93f41d435 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_ameliorer_bornes.c @@ -0,0 +1,316 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Amelioration des bornes + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" + +# include "pne_define.h" + +# include "prs_define.h" + +# define EPS_UMAX_UMIN 1.e-5 + +# define TRACES 0 +# define MAX_ITER 10 +# define COEFF_MIN 1.e-15 + +/*----------------------------------------------------------------------------*/ +/* On regarde si on peut fixer des variables entieres ou + resserer des bornes sur les variables */ + +void PRS_AmeliorerLesBornes( PRESOLVE * Presolve, int * BorneAmelioree ) +{ +int Var; int NbBornesAmeliorees; int Nb; int NbIter; int * TypeDeBornePourPresolve; +int NombreDeVariables; int NbModifs; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NbBornesAmeliorees = 0; +NombreDeVariables = Pne->NombreDeVariablesTrav; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; + +*BorneAmelioree = NON_PNE; + +NbIter = 0; +while ( NbIter < MAX_ITER ) { + NbIter++; + Nb = NbBornesAmeliorees; + + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) continue; + PRS_AmeliorerBorneSurVariable( Presolve, Var, &NbBornesAmeliorees ); + if ( Pne->YaUneSolution == PROBLEME_INFAISABLE ) { + *BorneAmelioree = NON_PNE; + return; + } + } + + if ( NbBornesAmeliorees == Nb ) break; + + PRS_CalculerLesBornesDeToutesLesContraintes( Presolve , &NbModifs ); + if ( Pne->YaUneSolution != OUI_PNE ) break; + +} + +#if VERBOSE_PRS + printf("-> Nombre de bornes amelioree: %d\n",NbBornesAmeliorees); +#endif + +if ( NbBornesAmeliorees != 0 ) *BorneAmelioree = OUI_PNE; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_AmeliorerBorneSurVariable( PRESOLVE * Presolve, int Var, int * Nbs ) +{ +int il; int Cnt; double CoeffDeVar; double Smin; double Smax; double AxiMin; +double AxiMax; double XiMin; double XiMax; double InfDesXiMax; +double SupDesXiMin; char InfDesXiMaxEstInitialise; double * A; int TypeBrn; +char SupDesXiMinEstInitialise; char SminEstValide; char SmaxEstValide; char XiMinEstValide; +char XiMaxEstValide; int ContrainteBornanteSup; int ContrainteBornanteInf; +char * MinContrainteCalcule; double * BorneSupPourPresolve; +char * MaxContrainteCalcule; char * ContrainteInactive; int * Cdeb; int * Csui; +int * NumContrainte; char * SensContrainte; double * B; double * MinContrainte; double * MaxContrainte; +int * TypeDeBornePourPresolve; +double Xmx; double Xmn; int * TypeDeVariable; double * BorneInfPourPresolve; PROBLEME_PNE * Pne; +double * ValeurDeXPourPresolve; char BorneAmelioree; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; + +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +MinContrainteCalcule = Presolve->MinContrainteCalcule; +MaxContrainteCalcule = Presolve->MaxContrainteCalcule; +MinContrainte = Presolve->MinContrainte; +MaxContrainte = Presolve->MaxContrainte; +ContrainteInactive = Presolve->ContrainteInactive; + +A = Pne->ATrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +NumContrainte = Pne->NumContrainteTrav; +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; + +InfDesXiMaxEstInitialise = NON_PNE; +SupDesXiMinEstInitialise = NON_PNE; +ContrainteBornanteSup = -1; +ContrainteBornanteInf = -1; + +/* Pour eviter les warning de compilation */ +Smin = 0.; +Smax = 0.; +XiMin = 0.; +SupDesXiMin = 0.; +XiMax = 0.; +InfDesXiMax = 0.; +CoeffDeVar = 1.; + +TypeBrn = TypeDeBornePourPresolve[Var]; +Xmx = BorneSupPourPresolve[Var]; +Xmn = BorneInfPourPresolve[Var]; + +il = Cdeb[Var]; +while ( il >= 0 ) { + + Cnt = NumContrainte[il]; + if ( ContrainteInactive[Cnt] == OUI_PNE ) goto ContrainteSuivante; + + CoeffDeVar = A[il]; + if ( fabs( CoeffDeVar ) < PIVOT_MIN_POUR_UN_CALCUL_DE_BORNE ) goto ContrainteSuivante; + + SmaxEstValide = OUI_PNE; + SminEstValide = OUI_PNE; + XiMinEstValide = OUI_PNE; + XiMaxEstValide = OUI_PNE; + + if ( SensContrainte[Cnt] == '=' ) { + /* Dans le cas d'une contrainte d'egalite on peut calculer une borne + min et une borne max */ + if ( CoeffDeVar > ZERO_PRESOLVE ) { + /* Coeff positif */ + if ( TypeBrn == VARIABLE_NON_BORNEE || TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT || MaxContrainteCalcule[Cnt] == NON_PNE ) { + SmaxEstValide = NON_PNE; + } + else { + if ( fabs( CoeffDeVar * Xmx ) < COEFF_MIN * fabs( MaxContrainte[Cnt] ) ) SmaxEstValide = NON_PNE; + Smax = MaxContrainte[Cnt] - ( CoeffDeVar * Xmx ); + } + + if ( TypeBrn == VARIABLE_NON_BORNEE || TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT || MinContrainteCalcule[Cnt] == NON_PNE ) { + SminEstValide = NON_PNE; + } + else { + if ( fabs( CoeffDeVar * Xmn ) < COEFF_MIN * fabs( MinContrainte[Cnt] ) ) SminEstValide = NON_PNE; + Smin = MinContrainte[Cnt] - ( CoeffDeVar * Xmn ); + } + + AxiMin = B[Cnt] - Smax; + AxiMax = B[Cnt] - Smin; + + if ( SmaxEstValide == NON_PNE ) XiMinEstValide = NON_PNE; + else XiMin = AxiMin / CoeffDeVar; + if ( SminEstValide == NON_PNE ) XiMaxEstValide = NON_PNE; + else XiMax = AxiMax / CoeffDeVar; + } + else if ( CoeffDeVar < -ZERO_PRESOLVE ) { + /* Coeff negatif */ + if ( TypeBrn == VARIABLE_NON_BORNEE || TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT || MaxContrainteCalcule[Cnt] == NON_PNE ) { + SmaxEstValide = NON_PNE; + } + else { + if ( fabs( CoeffDeVar * Xmn ) < COEFF_MIN * fabs( MaxContrainte[Cnt] ) ) SmaxEstValide = NON_PNE; + Smax = MaxContrainte[Cnt] - ( CoeffDeVar * Xmn ); + } + + if ( TypeBrn == VARIABLE_NON_BORNEE || TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT || MinContrainteCalcule[Cnt] == NON_PNE ) { + SminEstValide = NON_PNE; + } + else { + if ( fabs( CoeffDeVar * Xmx ) < COEFF_MIN * fabs( MinContrainte[Cnt] ) ) SminEstValide = NON_PNE; + Smin = MinContrainte[Cnt] - ( CoeffDeVar * Xmx ); + } + + AxiMin = B[Cnt] - Smax; + AxiMax = B[Cnt] - Smin; + + if ( SminEstValide == NON_PNE ) XiMinEstValide = NON_PNE; + else XiMin = AxiMax / CoeffDeVar; + if ( SmaxEstValide == NON_PNE ) XiMaxEstValide = NON_PNE; + else XiMax = AxiMin / CoeffDeVar; + } + else return; /* Car evaluation impossible */ + if ( XiMinEstValide == OUI_PNE ) { + if ( SupDesXiMinEstInitialise == OUI_PNE ) { + if ( XiMin > SupDesXiMin ) { SupDesXiMin = XiMin; ContrainteBornanteInf = Cnt; } + } + else { + SupDesXiMin = XiMin; + SupDesXiMinEstInitialise = OUI_PNE; + ContrainteBornanteInf = Cnt; + } + } + if ( XiMaxEstValide == OUI_PNE ) { + if ( InfDesXiMaxEstInitialise == OUI_PNE ) { + if ( XiMax < InfDesXiMax ) { InfDesXiMax = XiMax; ContrainteBornanteSup = Cnt; } + } + else { + InfDesXiMax = XiMax; + InfDesXiMaxEstInitialise = OUI_PNE; + ContrainteBornanteSup = Cnt; + } + } + } + else { + /* Dans le cas d'une contrainte d'inegalite on ne peut calculer qu'un seul type de borne */ + if ( CoeffDeVar > ZERO_PRESOLVE ) { + /* Coeff positif */ + if ( TypeBrn == VARIABLE_NON_BORNEE || TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT || MinContrainteCalcule[Cnt] == NON_PNE ) { + SminEstValide = NON_PNE; + } + else { + if ( fabs( CoeffDeVar * Xmn ) < COEFF_MIN * fabs( MinContrainte[Cnt] ) ) SminEstValide = NON_PNE; + } + if ( SminEstValide == OUI_PNE ) { + Smin = MinContrainte[Cnt] - ( CoeffDeVar * Xmn ); + AxiMax = B[Cnt] - Smin; + XiMax = AxiMax / CoeffDeVar; + if ( InfDesXiMaxEstInitialise == OUI_PNE ) { + if ( XiMax < InfDesXiMax ) { InfDesXiMax = XiMax; ContrainteBornanteSup = Cnt; } + } + else { + InfDesXiMax = XiMax; + InfDesXiMaxEstInitialise = OUI_PNE; + ContrainteBornanteSup = Cnt; + } + } + } + else if ( CoeffDeVar < -ZERO_PRESOLVE ) { + /* Coeff negatif */ + if ( TypeBrn == VARIABLE_NON_BORNEE || TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT || MinContrainteCalcule[Cnt] == NON_PNE ) { + SminEstValide = NON_PNE; + } + else { + if ( fabs( CoeffDeVar * Xmx ) < COEFF_MIN * fabs( MinContrainte[Cnt] ) ) SminEstValide = NON_PNE; + } + if ( SminEstValide == OUI_PNE ) { + Smin = MinContrainte[Cnt] - ( CoeffDeVar * Xmx ); + AxiMax = B[Cnt] - Smin; + XiMin = AxiMax / CoeffDeVar; + if ( SupDesXiMinEstInitialise == OUI_PNE ) { + if ( XiMin > SupDesXiMin ) { SupDesXiMin = XiMin; ContrainteBornanteInf = Cnt; } + } + else { + SupDesXiMin = XiMin; + SupDesXiMinEstInitialise = OUI_PNE; + ContrainteBornanteInf = Cnt; + } + } + } + else return; /* Car evaluation impossible */ + } + ContrainteSuivante: + il = Csui[il]; + +} + +if ( InfDesXiMaxEstInitialise == OUI_PNE ) { + if ( fabs( InfDesXiMax ) > VALEUR_DE_BORNE_DEBILE ) { + /* Nouvelle borne refusee */ + InfDesXiMaxEstInitialise = NON_PNE; + } +} +if ( SupDesXiMinEstInitialise == OUI_PNE ) { + if ( fabs( SupDesXiMin ) > VALEUR_DE_BORNE_DEBILE ) { + /* Nouvelle borne refusee */ + SupDesXiMinEstInitialise = NON_PNE; + } +} + +/* Analyse des bornes eventuellement calculees pour la variable */ +if ( InfDesXiMaxEstInitialise == NON_PNE && SupDesXiMinEstInitialise == NON_PNE ) return; + +/* Si InfDesXiMaxEstInitialise = OUI_PNE on a une borne Sup */ +/* Si SupDesXiMinEstInitialise = OUI_PNE on a une borne Inf */ + +PRS_MettreAJourLesBornesDUneVariable( Presolve, Var, SupDesXiMinEstInitialise, SupDesXiMin, + ContrainteBornanteInf, InfDesXiMaxEstInitialise, InfDesXiMax, + ContrainteBornanteSup, &BorneAmelioree ); + +if ( BorneAmelioree == OUI_PNE ) *Nbs = *Nbs + 1; + +return; + +} + + + + diff --git a/src/ext/Sirius_Solver/presolve/prs_ameliorer_coefficients.c b/src/ext/Sirius_Solver/presolve/prs_ameliorer_coefficients.c new file mode 100644 index 0000000000..d865aef320 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_ameliorer_coefficients.c @@ -0,0 +1,170 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Amelioration des coefficients des variables entieres + (cas des variables binaires uniquement). + La description de la methode se trouve dans l'article: + "Computational Integer Programming and cutting planes" + Armin Fugenschuh & Alexander Martin, page 6, 2001. + Mais on peut aussi la trouver dans d'autres articles. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PRS_AmeliorerLesCoefficientsDesVariablesBinaires( PRESOLVE * Presolve ) + +{ +int Var; int Cnt; int il; double Smax; int ilEntier; int NombreDeVariables; double Coeff; +char * ContrainteInactive; int * TypeDeVariable; int * Cdeb; int * Csui; int * NumContrainte; +char * SensContrainte; int * Mdeb; int * NbTerm; int * Nuvar; int * TypeDeBornePourPresolve; +double a; double * B; double * A; double * BorneInfPourPresolve; double * BorneSupPourPresolve; +int NbIter; char CoeffModifie; PROBLEME_PNE * Pne; int NbModifications; int NbC; +double * MaxContrainte; char * MaxContrainteCalcule; double Marge; double PlusPetitTerme; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +if ( Pne->YaDesVariablesEntieres != OUI_PNE ) return; + +Marge = MARGE_REDUCTION; +PlusPetitTerme = Pne->PlusPetitTerme; +NbC = 0; + +PRS_CalculerLesBornesDeToutesLesContraintes( Presolve, &NbModifications ); + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + + +NombreDeVariables = Pne->NombreDeVariablesTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; + +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; + +ContrainteInactive = Presolve->ContrainteInactive; +MaxContrainteCalcule = Presolve->MaxContrainteCalcule; +MaxContrainte = Presolve->MaxContrainte; + +NbIter = 0; +Debut: +CoeffModifie = NON_PNE; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeVariable[Var] != ENTIER ) continue; + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) continue; + + il = Cdeb[Var]; + while ( il >= 0 ) { + Cnt = NumContrainte[il]; + if ( ContrainteInactive[Cnt] == OUI_PNE ) goto ContrainteSuivante; + if ( SensContrainte[Cnt] == '=' ) goto ContrainteSuivante; + /* La contrainte est donc de type < , calcul du max du membre de gauche */ + ilEntier = il; + Coeff = A[ilEntier]; + if ( MaxContrainteCalcule[Cnt] == OUI_PNE ) Smax = MaxContrainte[Cnt]; + else goto ContrainteSuivante; + + if ( Smax <= B[Cnt] ) goto ContrainteSuivante; /* Contrainte redondante */ + + if ( Coeff < 0.0 ) { + if ( Smax + Coeff < B[Cnt] - EPS_COEFF_REDUCTION ) { + /* On peut diminuer le coeff de la variable entiere */ + a = B[Cnt] - Smax - Marge; + if ( fabs( a ) < PlusPetitTerme ) { + goto ContrainteSuivante; + a = -PlusPetitTerme; + } + if ( a < Coeff ) goto ContrainteSuivante; + if ( fabs( a ) < fabs( Coeff) - DELTA_MIN_REDUCTION ) { + # if TRACES == 1 + printf(" Variable entiere %d contrainte %d, remplacement de son coefficient %e par %e \n",Var,Cnt,Coeff,a); + # endif + /* Mise a jour de MaxContrainte[Cnt] */ + MaxContrainte[Cnt] -= Coeff * BorneInfPourPresolve[Var]; + MaxContrainte[Cnt] += a * BorneInfPourPresolve[Var]; /* Meme si on sait que borne inf = 0 */ + /* Modif du coefficient */ + A[ilEntier] = a; + CoeffModifie = OUI_PNE; + NbC++; + } + } + } + else if ( Coeff > 0.0 ) { + if ( Smax - Coeff < B[Cnt] - EPS_COEFF_REDUCTION ) { + /* On peut diminuer le coeff de la variable entiere */ + a = Smax - B[Cnt] + Marge; + if ( fabs( a ) < PlusPetitTerme ) { + goto ContrainteSuivante; + a = PlusPetitTerme; + } + if ( a > Coeff ) goto ContrainteSuivante; + if ( fabs( a ) < fabs( Coeff) - DELTA_MIN_REDUCTION ) { + # if TRACES == 1 + printf(" Variable entiere %d contrainte %d, remplacement de son coefficient %e par %e et B %e par %e\n",Var,Cnt,Coeff,a, + B[Cnt],Smax-Coeff+Marge); + # endif + /* Mise a jour de MaxContrainte[Cnt] */ + MaxContrainte[Cnt] -= Coeff * BorneSupPourPresolve[Var]; + MaxContrainte[Cnt] += a * BorneSupPourPresolve[Var]; + /* Modif du coefficient */ + A[ilEntier] = a; + B[Cnt] = Smax - Coeff + Marge; + CoeffModifie = OUI_PNE; + NbC++; + } + } + } + ContrainteSuivante: + il = Csui[il]; + } +} +if ( CoeffModifie == OUI_PNE ) { + # if TRACES == 1 + printf("AmeliorerLesCoefficientsDesVariablesBinaires : NbIter %d\n",NbIter); + # endif + NbIter++; + if ( NbIter < NB_ITER_MX_REDUCTION ) goto Debut; +} + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + if ( NbC != 0 ) printf("%d binary coefficient(s) reduced\n",NbC); +} + +return; +} + diff --git a/src/ext/Sirius_Solver/presolve/prs_ameliorer_contraintes_de_bornes_variables.c b/src/ext/Sirius_Solver/presolve/prs_ameliorer_contraintes_de_bornes_variables.c new file mode 100644 index 0000000000..44fb6234f3 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_ameliorer_contraintes_de_bornes_variables.c @@ -0,0 +1,144 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Presolve, amelioration des coefficients des contraintes + de type "variable upper/lower bound". + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +/*----------------------------------------------------------------------------*/ + +void PRS_AmeliorerCoeffDesContraintesDeBornesVariables( PRESOLVE * Presolve, int * NbModifications ) +{ +int Cnt; int il1; int il2; double A1; double A2; int Var1; int Var2; PROBLEME_PNE * Pne; +int NombreDeContraintes; char * SensContrainte; int * Mdeb; int * NbTerm; +int * Nuvar; double * A; double * B; int * TypeDeBornePourPresolve; +int * TypeDeVariable; double * BorneInfPourPresolve; double * BorneSupPourPresolve; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +TypeDeVariable = Pne->TypeDeVariableTrav; + +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; + +*NbModifications = 0; + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( SensContrainte[Cnt] != '<' ) continue; + if ( NbTerm[Cnt] != 2 ) continue; + if ( B[Cnt] != 0.0 ) continue; + il1 = Mdeb[Cnt]; + Var1 = Nuvar[il1]; + A1 = A[il1]; + if ( A1 == 0.0 ) continue; + if ( TypeDeBornePourPresolve[Var1] == VARIABLE_FIXE ) continue; + il2 = il1 + 1; + Var2 = Nuvar[il2]; + A2 = A[il2]; + if ( A2 == 0.0 ) continue; + if ( TypeDeBornePourPresolve[Var2] == VARIABLE_FIXE ) continue; + + if ( TypeDeVariable[Var1] != ENTIER && TypeDeVariable[Var2] == ENTIER ) { + if ( A1 > 0.0 ) { + A2/= A1; + A1 = 1.0; + #if VERBOSE_PRS + /*printf("A1 creel= %e entier= %e lim %e\n",A1,A2,Pne->UmaxTrav[Var1]);*/ + #endif + if ( -A2 > BorneSupPourPresolve[Var1] ) { + #if VERBOSE_PRS + /*printf("possibilite %e -> %e\n",-A2,-Pne->UmaxTrav[Var1]);*/ + #endif + A[il1] = 1.0; + A[il2] = -BorneSupPourPresolve[Var1]; + *NbModifications = *NbModifications + 1; + } + } + else if ( fabs( A1 ) > ZERO_PRESOLVE ) { + A2/= fabs( A1 ); + A1 = -1.0; + #if VERBOSE_PRS + /*printf("A1 creel= %e centier= %e lim %e\n",A1,A2,Pne->UminTrav[Var1]);*/ + #endif + if ( A2 < BorneInfPourPresolve[Var1] ) { + #if VERBOSE_PRS + /*printf("possibilite %e -> %e\n",A2,Pne->UminTrav[Var1]);*/ + #endif + A[il1] = -1.0; + A[il2] = BorneInfPourPresolve[Var1]; + *NbModifications = *NbModifications + 1; + } + } + } + else if ( TypeDeVariable[Var1] == ENTIER && TypeDeVariable[Var2] != ENTIER ) { + if ( A2 > 0.0 ) { + A1/= A2; + A2 = 1.0; + #if VERBOSE_PRS + /*printf("A2 creel= %e centier= %e lim %e\n",A2,A1,Pne->UmaxTrav[Var2]);*/ + #endif + if ( -A1 > BorneSupPourPresolve[Var2] ) { + #if VERBOSE_PRS + /*printf("possibilite %e -> %e\n",-A1,-Pne->UmaxTrav[Var2]);*/ + #endif + A[il1] = -BorneSupPourPresolve[Var2]; + A[il2] = 1.0; + *NbModifications = *NbModifications + 1; + } + } + else if ( fabs( A2 ) > ZERO_PRESOLVE ){ + A1/= fabs( A2 ); + A2 = -1.0; + #if VERBOSE_PRS + /*printf("A2 creel= %e centier= %e lim %e\n",A2,A1,Pne->UminTrav[Var2]);*/ + #endif + if ( A1 < BorneInfPourPresolve[Var2] ) { + #if VERBOSE_PRS + /*printf("possibilite %e -> %e\n",A1,Pne->UminTrav[Var2]);*/ + #endif + A[il1] = BorneInfPourPresolve[Var2]; + A[il2] = -1.0; + *NbModifications = *NbModifications + 1; + } + } + } + +} + +return; +} + diff --git a/src/ext/Sirius_Solver/presolve/prs_calcul_borne_sur_variable_avec_une_contrainte.c b/src/ext/Sirius_Solver/presolve/prs_calcul_borne_sur_variable_avec_une_contrainte.c new file mode 100644 index 0000000000..77bf0a6d94 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_calcul_borne_sur_variable_avec_une_contrainte.c @@ -0,0 +1,213 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On essaie de calculer des bornes sur une variable a partir + d'une contrainte. Utilise pour borner des variables a + l'aide de contraintes avec des variables dont toutes les + bornes sont connues sauf une. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ +/* VarTest est la variable que l'on veut essayer de borner implicitement */ + +void PRS_CalculeBorneSurVariableEnFonctionDeLaContrainte( PRESOLVE * Presolve, int Cnt, int VarTest, + char * BorneInfCalculee, double * BorneInf, + char * BorneSupCalculee, double * BorneSup ) +{ +int il; int ilMax; int Var; long double Smin; long double Smax; long double S; int * Nuvar; +double * A; int * TypeDeBornePourPresolve; long double CoeffDeVarTest; PROBLEME_PNE * Pne; +char SminCalcule; char SmaxCalcule; int * Mdeb; int * NbTerm; double * ValeurDeXPourPresolve; +char TypeBrn; double * BorneInfPourPresolve; double * BorneSupPourPresolve; long double B; +char SensContrainte; char SeulementSminEstUtile; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +SensContrainte = Pne->SensContrainteTrav[Cnt]; +B = (long double) Pne->BTrav[Cnt]; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; + +*BorneInfCalculee = NON_PNE; +*BorneSupCalculee = NON_PNE; + +Smin = 0.; +Smax = 0.; +SminCalcule = OUI_PNE; +SmaxCalcule = OUI_PNE; +CoeffDeVarTest = 1.; + +if ( SensContrainte == '<' ) SeulementSminEstUtile = OUI_PNE; +else SeulementSminEstUtile = NON_PNE;; + +il = Mdeb[Cnt]; +ilMax = il + NbTerm[Cnt]; +if ( SeulementSminEstUtile == OUI_PNE ) { + while ( il < ilMax ) { + if ( A[il] == 0.0 ) goto NextIl1; + Var = Nuvar[il]; + if ( Var == VarTest ) { + CoeffDeVarTest = (long double) A[il]; + if ( fabs( CoeffDeVarTest ) < PIVOT_MIN_POUR_UN_CALCUL_DE_BORNE ) return; + goto NextIl1; + } + TypeBrn = TypeDeBornePourPresolve[Var]; + + if ( TypeBrn == VARIABLE_NON_BORNEE ) return; + else if ( TypeBrn == VARIABLE_FIXE ) { + S = (long double) A[il] * (long double) ValeurDeXPourPresolve[Var]; + Smax += S; + Smin += S; + } + else { + if ( A[il] > 0. ) { + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + /*SminCalcule = NON_PNE;*/ + return; + } + else Smin += (long double) A[il] * (long double) BorneInfPourPresolve[Var]; + } + else { + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + /*SminCalcule = NON_PNE;*/ + return; + } + else Smin += (long double) A[il] * (long double) BorneSupPourPresolve[Var]; + } + } + NextIl1: + il++; + } +} +else { + while ( il < ilMax ) { + if ( A[il] == 0.0 ) goto NextIl2; + Var = Nuvar[il]; + if ( Var == VarTest ) { + CoeffDeVarTest = (long double) A[il]; + if ( fabs( CoeffDeVarTest ) < PIVOT_MIN_POUR_UN_CALCUL_DE_BORNE ) return; + goto NextIl2; + } + TypeBrn = TypeDeBornePourPresolve[Var]; + + if ( TypeBrn == VARIABLE_NON_BORNEE ) return; + else if ( TypeBrn == VARIABLE_FIXE ) { + S = (long double) A[il] * (long double) ValeurDeXPourPresolve[Var]; + Smax += S; + Smin += S; + } + else { + if ( A[il] > 0. ) { + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + SmaxCalcule = NON_PNE; + if ( SminCalcule == NON_PNE ) return; + } + else Smax += (long double) A[il] * (long double) BorneSupPourPresolve[Var]; + + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + SminCalcule = NON_PNE; + if ( SmaxCalcule == NON_PNE ) return; + } + else Smin += (long double) A[il] * (long double) BorneInfPourPresolve[Var]; + } + else { + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + SmaxCalcule = NON_PNE; + if ( SminCalcule == NON_PNE ) return; + } + else Smax += (long double) A[il] * (long double) BorneInfPourPresolve[Var]; + + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + SminCalcule = NON_PNE; + if ( SmaxCalcule == NON_PNE ) return; + } + else Smin += (long double) A[il] * (long double) BorneSupPourPresolve[Var]; + } + } + NextIl2: + il++; + } +} + +if ( SensContrainte == '=' ) { + /* Dans le cas d'une contrainte d'egalite on peut calculer une borne + min et une borne max */ + if ( CoeffDeVarTest > 0.0 ) { + if ( SminCalcule == OUI_PNE ) { + *BorneSupCalculee = OUI_PNE; + *BorneSup = (double) ( ( B - Smin ) / CoeffDeVarTest ); + if ( fabs( *BorneSup ) > VALEUR_DE_BORNE_DEBILE ) *BorneSupCalculee = NON_PNE; + } + if ( SmaxCalcule == OUI_PNE ) { + *BorneInfCalculee = OUI_PNE; + *BorneInf = (double) ( ( B - Smax ) / CoeffDeVarTest ); + if ( fabs( *BorneInf ) > VALEUR_DE_BORNE_DEBILE ) *BorneInfCalculee = NON_PNE; + } + } + else { + if ( SmaxCalcule == OUI_PNE ) { + *BorneSupCalculee = OUI_PNE; + *BorneSup = (double) ( ( B - Smax ) / CoeffDeVarTest ); + if ( fabs( *BorneSup ) > VALEUR_DE_BORNE_DEBILE ) *BorneSupCalculee = NON_PNE; + } + if ( SminCalcule == OUI_PNE ) { + *BorneInfCalculee = OUI_PNE; + *BorneInf = (double) ( ( B - Smin ) / CoeffDeVarTest ); + if ( fabs( *BorneInf ) > VALEUR_DE_BORNE_DEBILE ) *BorneInfCalculee = NON_PNE; + } + } +} +else { + /* Toutes les contraintes d'inegalite ont ete transformees en <= */ + if ( CoeffDeVarTest > 0.0 ) { + if ( SminCalcule == OUI_PNE ) { + *BorneSupCalculee = OUI_PNE; + *BorneSup = (double) ( ( B - Smin ) / CoeffDeVarTest ); + if ( fabs( *BorneSup ) > VALEUR_DE_BORNE_DEBILE ) *BorneSupCalculee = NON_PNE; + } + } + else { + if ( SminCalcule == OUI_PNE ) { + *BorneInfCalculee = OUI_PNE; + *BorneInf = (double) ( ( B - Smin ) / CoeffDeVarTest ); + if ( fabs( *BorneInf ) > VALEUR_DE_BORNE_DEBILE ) *BorneInfCalculee = NON_PNE; + } + } +} + +return; +} diff --git a/src/ext/Sirius_Solver/presolve/prs_calcul_borne_sur_variable_duale_avec_une_variable.c b/src/ext/Sirius_Solver/presolve/prs_calcul_borne_sur_variable_duale_avec_une_variable.c new file mode 100644 index 0000000000..fb0fd98371 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_calcul_borne_sur_variable_duale_avec_une_variable.c @@ -0,0 +1,236 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On essaie de calculer des bornes sur une variable duale a + partir d'une variable. Utilise pour borner des variables + duale a l'aide de variables dont les contraintes qui entrent + dans le calcul du cout reduit on des variables duales + connues ou bornees sauf une. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ +/* VarTest est la variable que l'on veut essayer de borner implicitement */ + +void PRS_CalculeBorneSurVariableDualeEnFonctionDeLaVariable( PRESOLVE * Presolve, int CntTest, int Var, + char TypeBrn, + char * BorneInfCalculee, double * BorneInf, + char * BorneSupCalculee, double * BorneSup ) +{ +int ic; double C; double CoeffDeCntTest; double X; int Cnt; double Smin; double Smax; +int * Cdeb; int * Csui; int * NumContrainte; double * A; double * LambdaMin; +double * LambdaMax; double * Lambda; char * ConnaissanceDeLambda; char * ContrainteInactive; +char SminCalcule; char SmaxCalcule; char SensCoutReduit; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +*BorneInfCalculee = NON_PNE; +*BorneSupCalculee = NON_PNE; + +if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) SensCoutReduit = '>'; +else if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) SensCoutReduit = '<'; +else if ( TypeBrn == VARIABLE_NON_BORNEE ) SensCoutReduit = '='; +else return; + +C = Pne->LTrav[Var]; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; + +LambdaMin = Presolve->LambdaMin; +LambdaMax = Presolve->LambdaMax; +Lambda = Presolve->Lambda; +ConnaissanceDeLambda = Presolve->ConnaissanceDeLambda; +ContrainteInactive = Presolve->ContrainteInactive; + +Smin = 0.; +Smax = 0.; +SminCalcule = OUI_PNE; +SmaxCalcule = OUI_PNE; +CoeffDeCntTest = 1.; + +ic = Cdeb[Var]; +while ( ic >= 0 ) { + + if ( A[ic] == 0.0 ) goto NextIc; + Cnt = NumContrainte[ic]; + + if ( ContrainteInactive[Cnt] == OUI_PNE ) goto NextIc; + + if ( Cnt == CntTest ) { + CoeffDeCntTest = A[ic]; + if ( fabs( CoeffDeCntTest ) < PIVOT_MIN_POUR_UN_CALCUL_DE_BORNE ) return; + goto NextIc; + } + + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_CONNU ) { + X = A[ic] * Lambda[Cnt]; + Smin += X; + Smax += X; + } + else { + if ( A[ic] > 0.0 ) { + /* MaxSommeDesAiFoisLambda */ + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + Smax += A[ic] * LambdaMax[Cnt]; + } + else SmaxCalcule = NON_PNE; + /* MinSommeDesAiFoisLambda */ + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + Smin += A[ic] * LambdaMin[Cnt]; + } + else SminCalcule = NON_PNE; + + } + else { + /* A[ic] < 0 */ + /* MaxSommeDesAiFoisLambda */ + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + Smax += A[ic] * LambdaMin[Cnt]; + } + else SmaxCalcule = NON_PNE; + /* MinSommeDesAiFoisLambda */ + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + Smin += A[ic] * LambdaMax[Cnt]; + } + else SminCalcule = NON_PNE; + } + } + NextIc: + if ( SminCalcule == NON_PNE && SmaxCalcule == NON_PNE ) break; + ic = Csui[ic]; +} + +if ( SensCoutReduit == '=' ) { + /* Dans le cas d'une contrainte d'egalite on peut calculer une borne min et une borne max */ + /* On a uA = c */ + if ( CoeffDeCntTest > 0.0 ) { + if ( SminCalcule == OUI_PNE ) { + *BorneSupCalculee = OUI_PNE; + *BorneSup = ( C - Smin ) / CoeffDeCntTest ; + + # if TRACES == 1 + printf("Calcul d'une BorneSup sur la variable duale de la contrainte %d: %e\n",CntTest,*BorneSup); + # endif + + if ( fabs( *BorneSup ) > VALEUR_DE_BORNE_DEBILE ) *BorneSupCalculee = NON_PNE; + } + if ( SmaxCalcule == OUI_PNE ) { + *BorneInfCalculee = OUI_PNE; + *BorneInf = ( C - Smax ) / CoeffDeCntTest; + + # if TRACES == 1 + printf("Calcul d'une BorneInf sur la variable duale de la contrainte %d: %e\n",CntTest,*BorneInf); + # endif + + if ( fabs( *BorneInf ) > VALEUR_DE_BORNE_DEBILE ) *BorneInfCalculee = NON_PNE; + } + } + else { + if ( SmaxCalcule == OUI_PNE ) { + *BorneSupCalculee = OUI_PNE; + *BorneSup = ( C - Smax ) / CoeffDeCntTest; + + # if TRACES == 1 + printf("Calcul d'une BorneSup sur la variable duale de la contrainte %d: %e\n",CntTest,*BorneSup); + # endif + + if ( fabs( *BorneSup ) > VALEUR_DE_BORNE_DEBILE ) *BorneSupCalculee = NON_PNE; + } + if ( SminCalcule == OUI_PNE ) { + *BorneInfCalculee = OUI_PNE; + *BorneInf = ( C - Smin ) / CoeffDeCntTest; + + # if TRACES == 1 + printf("Calcul d'une BorneInf sur la variable duale de la contrainte %d: %e\n",CntTest,*BorneInf); + # endif + + if ( fabs( *BorneInf ) > VALEUR_DE_BORNE_DEBILE ) *BorneInfCalculee = NON_PNE; + } + } +} +else if ( SensCoutReduit == '>' ) { + /* On doit avoir c-uA >= 0 <=> uA <= c */ + if ( CoeffDeCntTest > 0.0 ) { + if ( SminCalcule == OUI_PNE ) { + *BorneSupCalculee = OUI_PNE; + *BorneSup = ( C - Smin ) / CoeffDeCntTest; + + # if TRACES == 1 + printf("Calcul d'une BorneSup sur la variable duale de la contrainte %d: %e\n",CntTest,*BorneSup); + # endif + + if ( fabs( *BorneSup ) > VALEUR_DE_BORNE_DEBILE ) *BorneSupCalculee = NON_PNE; + } + } + else { + if ( SminCalcule == OUI_PNE ) { + *BorneInfCalculee = OUI_PNE; + *BorneInf = ( C - Smin ) / CoeffDeCntTest; + + # if TRACES == 1 + printf("Calcul d'une BorneInf sur la variable duale de la contrainte %d: %e\n",CntTest,*BorneInf); + # endif + + if ( fabs( *BorneInf ) > VALEUR_DE_BORNE_DEBILE ) *BorneInfCalculee = NON_PNE; + } + } +} +else if ( SensCoutReduit == '<' ) { + /* On doit avoir c-uA <= 0 <=> uA >= c */ + if ( CoeffDeCntTest > 0.0 ) { + if ( SmaxCalcule == OUI_PNE ) { + *BorneInfCalculee = OUI_PNE; + *BorneInf = ( C - Smax ) / CoeffDeCntTest; + + # if TRACES == 1 + printf("Calcul d'une BorneInf sur la variable duale de la contrainte %d: %e\n",CntTest,*BorneInf); + # endif + + if ( fabs( *BorneInf ) > VALEUR_DE_BORNE_DEBILE ) *BorneInfCalculee = NON_PNE; + } + } + else { + if ( SmaxCalcule == OUI_PNE ) { + *BorneSupCalculee = OUI_PNE; + *BorneSup = ( C - Smax ) / CoeffDeCntTest; + + # if TRACES == 1 + printf("Calcul d'une BorneSup sur la variable duale de la contrainte %d: %e\n",CntTest,*BorneSup); + # endif + + if ( fabs( *BorneSup ) > VALEUR_DE_BORNE_DEBILE ) *BorneSupCalculee = NON_PNE; + } + } +} + +return; +} diff --git a/src/ext/Sirius_Solver/presolve/prs_calculer_bornes_contraintes.c b/src/ext/Sirius_Solver/presolve/prs_calculer_bornes_contraintes.c new file mode 100644 index 0000000000..114cf66429 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_calculer_bornes_contraintes.c @@ -0,0 +1,334 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul des bornes des contraintes. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define VALEUR_DE_BORNE_DEBILE_POUR_LES_CONTRAINTES 1.e+20 /*+15*/ +# define ZERO_CONTRAINTE 1.e-6 +# define SEUIL_FORCING_CONTRAINTE 1.e-7 +# define SEUIL_PETIT_COEFFICIENT 1.e-9 + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PRS_CalculerLesBornesDeToutesLesContraintes( PRESOLVE * Presolve, int * NbModifications ) +{ +int Cnt; char CalculDeForcingConstraints; int NbCntSuppr; int NbVarSuppr; +PROBLEME_PNE * Pne; char * ContrainteInactive; + +*NbModifications = 0; /* Prend une valeur non nulle si forcing constraintes */ + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +ContrainteInactive = Presolve->ContrainteInactive; + +NbCntSuppr = 0; +NbVarSuppr = 0; + +CalculDeForcingConstraints = OUI_PNE; + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + if ( ContrainteInactive[Cnt] != OUI_PNE ) { + PRS_CalculerLesBornesDuneContrainte( Presolve, Cnt, CalculDeForcingConstraints, + &NbCntSuppr, &NbVarSuppr ); + } +} + +#if VERBOSE_PRS == 1 + printf("-> Nombre de contraintes supprimees par forcing %d\n",NbCntSuppr); + printf("-> Nombre de variable supprimees par forcing %d\n",NbVarSuppr); + fflush(stdout); +#endif + +*NbModifications = NbCntSuppr + NbVarSuppr; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_CalculerLesBornesDuneContrainte( PRESOLVE * Presolve, int Cnt, + char CalculDeForcingConstraints, + int * NbCntSuppr, int * NbVarSuppr ) +{ +int il; int ilMax; int Var; double Smin; double Smax; double S; +char FixerLesVariablesSurMinContrainte; char FixerLesVariablesSurMaxContrainte; +int * Nuvar; double * A; double * BorneInfPourPresolve; double * BorneSupPourPresolve; +int * TypeDeBornePourPresolve; int * Mdeb; int * NbTerm; char * ContrainteInactive; +char * MinContrainteCalcule; char * MaxContrainteCalcule; double * ValeurDeXPourPresolve; +double * MinContrainte; double * MaxContrainte; char * SensContrainte; double * B; +PROBLEME_PNE * Pne; double ValeurDeX; char MinCntCalcule; char MaxCntCalcule; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +MinContrainteCalcule = Presolve->MinContrainteCalcule; +MaxContrainteCalcule = Presolve->MaxContrainteCalcule; +MinContrainte = Presolve->MinContrainte; +MaxContrainte = Presolve->MaxContrainte; +ContrainteInactive = Presolve->ContrainteInactive; + +MinCntCalcule = OUI_PNE; +MaxCntCalcule = OUI_PNE; + +MinContrainteCalcule[Cnt] = MinCntCalcule; +MaxContrainteCalcule[Cnt] = MaxCntCalcule; + +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; + +Smin = 0.; +Smax = 0.; +il = Mdeb[Cnt]; +ilMax = il + NbTerm[Cnt]; +while ( il < ilMax ) { + + Var = Nuvar[il]; + + if ( TypeDeBornePourPresolve[Var] == VARIABLE_NON_BORNEE ) { + MinContrainteCalcule[Cnt] = NON_PNE; + MaxContrainteCalcule[Cnt] = NON_PNE; + MinContrainte[Cnt] = -LINFINI_PNE; + MaxContrainte[Cnt] = LINFINI_PNE; + return; + } + else if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) { + S = A[il] * ValeurDeXPourPresolve[Var]; + Smax += S; + Smin += S; + } + else if ( A[il] != 0 ) { + if ( A[il] > 0. ) { + if ( TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + MaxCntCalcule = NON_PNE; + if ( MinCntCalcule == NON_PNE ) break; + } + else Smax += A[il] * BorneSupPourPresolve[Var]; + if ( TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + MinCntCalcule = NON_PNE; + if ( MaxCntCalcule == NON_PNE ) break; + } + else Smin += A[il] * BorneInfPourPresolve[Var]; + } + else { + if ( TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + MaxCntCalcule = NON_PNE; + if ( MinCntCalcule == NON_PNE ) break; + } + else Smax += A[il] * BorneInfPourPresolve[Var]; + if ( TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + MinCntCalcule = NON_PNE; + if ( MaxCntCalcule == NON_PNE ) break; + } + else Smin += A[il] * BorneSupPourPresolve[Var]; + } + } + il++; +} + +MinContrainteCalcule[Cnt] = MinCntCalcule; +MaxContrainteCalcule[Cnt] = MaxCntCalcule; + +MinContrainte[Cnt] = Smin; +MaxContrainte[Cnt] = Smax; + +if ( MinContrainteCalcule[Cnt] == OUI_PNE ) { + if ( fabs( MinContrainte[Cnt] ) > VALEUR_DE_BORNE_DEBILE_POUR_LES_CONTRAINTES ) MinContrainteCalcule[Cnt] = NON_PNE; +} + +if ( MaxContrainteCalcule[Cnt] == OUI_PNE ) { + if ( fabs( MaxContrainte[Cnt] ) > VALEUR_DE_BORNE_DEBILE_POUR_LES_CONTRAINTES ) MaxContrainteCalcule[Cnt] = NON_PNE; +} + +if ( SensContrainte[Cnt] == '=' ) { + if ( MaxContrainteCalcule[Cnt] == OUI_PNE ) { + if ( MaxContrainte[Cnt] < B[Cnt] - ZERO_CONTRAINTE ) { + # if TRACES == 1 + printf("Probleme infaisable a cause de la contraintes %d MaxContrainte %e B %e sens %c\n",Cnt,MaxContrainte[Cnt],B[Cnt],SensContrainte[Cnt]); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + } + if ( MinContrainteCalcule[Cnt] == OUI_PNE ) { + if ( MinContrainte[Cnt] > B[Cnt] + ZERO_CONTRAINTE ) { + # if TRACES == 1 + printf("Probleme infaisable a cause de la contraintes %d MinContrainte %e B %e sens %c (MaxContrainte %e)\n",Cnt,MinContrainte[Cnt],B[Cnt],SensContrainte[Cnt],MaxContrainte[Cnt]); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + } +} +else if ( SensContrainte[Cnt] == '<' ) { + if ( MinContrainteCalcule[Cnt] == OUI_PNE ) { + if ( MinContrainte[Cnt] > B[Cnt] + ZERO_CONTRAINTE ) { + # if TRACES == 1 + printf("Probleme infaisable a cause de la contraintes %d MinContrainte %e B %e sens %c\n",Cnt,MinContrainte[Cnt],B[Cnt],SensContrainte[Cnt]); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + } +} +else if ( SensContrainte[Cnt] == '>' ) { + if ( MaxContrainteCalcule[Cnt] == OUI_PNE ) { + if ( MaxContrainte[Cnt] < B[Cnt] - ZERO_CONTRAINTE ) { + # if TRACES == 1 + printf("Probleme infaisable a cause de la contraintes %d MaxContrainte %e B %e sens %c\n",Cnt,MaxContrainte[Cnt],B[Cnt],SensContrainte[Cnt]); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + } +} + +if ( CalculDeForcingConstraints == NON_PNE ) return; + +/* Forcing constraints */ +FixerLesVariablesSurMinContrainte = NON_PNE; +FixerLesVariablesSurMaxContrainte = NON_PNE; +if ( SensContrainte[Cnt] == '<' ) { + if ( MinContrainteCalcule[Cnt] == OUI_PNE ) { + if ( fabs( MinContrainte[Cnt] - B[Cnt] ) <= SEUIL_FORCING_CONTRAINTE ) { + # if TRACES == 1 + printf("Forcing contrainte inegalite %d \n",Cnt); + # endif + FixerLesVariablesSurMinContrainte = OUI_PNE; + } + } +} +else { + /* Contrainte d'egalite */ + if ( MinContrainteCalcule[Cnt] == OUI_PNE ) { + if ( fabs( MinContrainte[Cnt] - B[Cnt] ) <= SEUIL_FORCING_CONTRAINTE ) { + # if TRACES == 1 + printf("Forcing contrainte egalite %d MinContrainte %lf BTrav %lf\n",Cnt,MinContrainte[Cnt],B[Cnt]); + # endif + + FixerLesVariablesSurMinContrainte = OUI_PNE; + } + } + if ( MaxContrainteCalcule[Cnt] == OUI_PNE ) { + if ( fabs( MaxContrainte[Cnt] - B[Cnt] ) <= SEUIL_FORCING_CONTRAINTE ) { + + # if TRACES == 1 + printf("Forcing contrainte egalite %d MaxContrainte %lf BTrav %lf\n",Cnt,MaxContrainte[Cnt],B[Cnt]); + # endif + + FixerLesVariablesSurMaxContrainte = OUI_PNE; + } + } +} + +if ( FixerLesVariablesSurMinContrainte == NON_PNE && FixerLesVariablesSurMaxContrainte == NON_PNE ) return; + +if ( Pne->NbForcingConstraints >= Pne-> NombreDeContraintesTrav ) return; +if ( Pne->NombreDOperationsDePresolve >= Pne->TailleTypeDOperationDePresolve ) return; + +/* Il faut verifier qu'il n'y a aucun coefficient nul (trop petit) parmi les variables non fixes sinon il + est trop risque de se prononcer a cause des imprecisions numeriques possibles */ + +il = Mdeb[Cnt]; +ilMax = il + NbTerm[Cnt]; +while ( il < ilMax ) { + if ( TypeDeBornePourPresolve[Nuvar[il]] != VARIABLE_FIXE && A[il] != 0.0 ) { + if ( fabs( A[il] ) < SEUIL_PETIT_COEFFICIENT ) return; + } + il++; +} + +/* Fixation des variables */ +il = Mdeb[Cnt]; +ilMax = il + NbTerm[Cnt]; +if ( FixerLesVariablesSurMinContrainte == OUI_PNE ) { + while ( il < ilMax ) { + Var = Nuvar[il]; + if ( TypeDeBornePourPresolve[Var] != VARIABLE_FIXE && A[il] != 0. ) { + + if ( A[il] > 0. ) ValeurDeX = BorneInfPourPresolve[Var]; + else ValeurDeX = BorneSupPourPresolve[Var]; + + # if TRACES == 1 + printf(" forcing constrainte Var %d fixee a %e \n",Var,ValeurDeX); + # endif + + PRS_FixerUneVariableAUneValeur( Presolve, Var, ValeurDeX ); + *NbVarSuppr = *NbVarSuppr + 1; + + } + il++; + } +} +else { + while ( il < ilMax ) { + Var = Nuvar[il]; + if ( TypeDeBornePourPresolve[Var] != VARIABLE_FIXE && A[il] != 0. ) { + + if ( A[il] > 0. ) ValeurDeX = BorneSupPourPresolve[Var]; + else ValeurDeX = BorneInfPourPresolve[Var]; + + # if TRACES == 1 + printf(" forcing contrainte Var %d fixee a %e \n",Var,ValeurDeX); + # endif + + PRS_FixerUneVariableAUneValeur( Presolve, Var, ValeurDeX ); + *NbVarSuppr = *NbVarSuppr + 1; + + } + il++; + } +} + +/* Desactivation de la contrainte: on peut la desactiver meme si elle est bornante + car on fixe toutes les variables de la contrainte */ +PRS_DesactiverContrainte( Presolve, Cnt ); +*NbCntSuppr = *NbCntSuppr + 1; + +/* Mise a jour des infos pour le postsolve */ +Pne->TypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = SUPPRESSION_FORCING_CONSTRAINT; +Pne->IndexDansLeTypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = Pne->NbForcingConstraints; +Pne->NombreDOperationsDePresolve++; + +Pne->NumeroDeLaForcingConstraint[Pne->NbForcingConstraints] = Pne->CorrespondanceCntPneCntEntree[Cnt]; +Pne->NbForcingConstraints++; + +return; +} + diff --git a/src/ext/Sirius_Solver/presolve/prs_colonnes_colineaires.c b/src/ext/Sirius_Solver/presolve/prs_colonnes_colineaires.c new file mode 100644 index 0000000000..5a4e199662 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_colonnes_colineaires.c @@ -0,0 +1,595 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recherche des colonnes colineaires. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# define ZERO_COLINEAIRE 1.e-12 +# define SEUIL_POUR_DELTAC_NON_NUL 1.e-7 /* Pour affirmer que DeltaC est non nul */ +# define SEUIL_POUR_DELTAC_NUL 1.e-9 /* Pour affirmer que DeltaC est nul */ +# define MARGE_EGALITE_BORNE_MIN_ET_MAX 1.e-8 +# define MAX_NBTMX 1000000000 /*10000*/ + +# define COLONNE_A_ETUDIER 0 +# define COLONNE_A_EVITER 1 + +void PRS_ComparerVariables( PRESOLVE * , int , int , double * , char * , int , char * , int * , int * ); + +void PRS_ColonneColineairesDeltaCNonNul( PROBLEME_PNE * , PRESOLVE * , int , int , double , double , char * , int * , int * ); + +void PRS_ColonneColineairesDeltaCNul( PROBLEME_PNE * , PRESOLVE * , int , int , double , char * , int * , int * ); + +/*----------------------------------------------------------------------------*/ + +void PRS_ColonnesColineaires( PRESOLVE * Presolve, int * NbColonnesSupprimees ) +{ +int NombreDeVariables; int NombreDeContraintes; int * Mdeb; int * NbTerm; +int * Nuvar; double * A; int Cnt; int il1; char InitV; int Var1; int ic; +int * Cdeb; int * Csui; int * NumContrainte; int ilMax; char * SensContrainte; +double * B; int HashVar; int NbVarDeCnt; int il; char * Buffer; int * TypeDeVariable; +int * TypeDeBornePourPresolve; int NbT; int Var; int * NumVarDeCnt; char * Flag; +double * V; int LallocTas; char * ContrainteInactive; char * T; char * pt; +int * HashCode; int CntDeVar; int * ParLignePremiereContrainte; int * ParLigneContrainteSuivante; +int * TypeDeBorneNative; double * BorneInfPourPresolve; +double * BorneSupPourPresolve; double * BorneInfNative; double * BorneSupNative; +char * ConserverLaBorneInfDuPresolve; char * ConserverLaBorneSupDuPresolve; +int * VariableEquivalente; int NbComparaisons; int * NbTermesUtilesDeVar; +int NbTermesUtiles; int icPrec; int NbVarDispo; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +*NbColonnesSupprimees = 0; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorneNative = Pne->TypeDeBorneTrav; +BorneInfNative = Pne->UminTrav; +BorneSupNative = Pne->UmaxTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +B = Pne->BTrav; +SensContrainte = Pne->SensContrainteTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; + +ParLignePremiereContrainte = Presolve->ParLignePremiereContrainte; +ParLigneContrainteSuivante = Presolve->ParLigneContrainteSuivante; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +ConserverLaBorneInfDuPresolve = Presolve->ConserverLaBorneInfDuPresolve; +ConserverLaBorneSupDuPresolve = Presolve->ConserverLaBorneSupDuPresolve; +ContrainteInactive = Presolve->ContrainteInactive; +VariableEquivalente = Presolve->VariableEquivalente; + +LallocTas = 0; +LallocTas += NombreDeContraintes * sizeof( double ); /* V */ +LallocTas += NombreDeContraintes * sizeof( char ); /* T */ +LallocTas += NombreDeVariables * sizeof( char ); /* Flag */ +LallocTas += NombreDeVariables * sizeof( int ); /* HashCode */ +LallocTas += NombreDeVariables * sizeof( int ); /* NumVarDeCnt */ +LallocTas += NombreDeVariables * sizeof( int ); /* NbTermesUtilesDeVar */ + +Buffer = (char *) malloc( LallocTas ); +if ( Buffer == NULL ) { + printf(" Solveur PNE , memoire insuffisante dans le presolve. Sous-programme: PRS_ColonnesColineaires \n"); + return; +} + +pt = Buffer; +V = (double *) pt; +pt += NombreDeContraintes * sizeof( double ); +T = (char *) pt; +pt += NombreDeContraintes * sizeof( char ); +Flag = (char *) pt; +pt += NombreDeVariables * sizeof( char ); +HashCode = (int *) pt; +pt += NombreDeVariables * sizeof( int ); +NumVarDeCnt = (int *) pt; +pt += NombreDeVariables * sizeof( int ); +NbTermesUtilesDeVar = (int *) pt; +pt += NombreDeVariables * sizeof( int ); + +memset( (char *) T, 0, NombreDeContraintes * sizeof( char ) ); + +NbVarDispo = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + /* On ne prend pas en compte ni les variables entieres ni les variables fixes */ + if ( TypeDeVariable[Var] == ENTIER || TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) { + Flag[Var] = COLONNE_A_EVITER; + continue; + } + /* Il faut eviter d'utiliser les variables equivalentes car leurs bornes sont des resultats + d'autres calculs et ca peut entrainer des problemes de precision numerique */ + if ( VariableEquivalente[Var] > 5 ) { + Flag[Var] = COLONNE_A_EVITER; + continue; + } + + Flag[Var] = COLONNE_A_ETUDIER; + NbVarDispo++; + + /* Calcul d'un hashcode */ + /* On en profite pour dechainer les lignes qui correspondent a des contraintes inactives */ + NbT = 0; + il = 0; + ic = Cdeb[Var]; + icPrec = -1; + while ( ic >= 0 ) { + Cnt = NumContrainte[ic]; + if ( ContrainteInactive[Cnt] != OUI_PNE && A[ic] != 0.0 ) { + NbT++; + il += Cnt; + } + else { + /* On en profite pour dechainer les lignes qui correspondent a des contraintes inactives */ + ic = Csui[ic]; + if ( icPrec >= 0 ) { + Csui[icPrec] = ic; + continue; + } + else { + Cdeb[Var] = ic; + if ( ic < 0 ) break; /* Attention s'il ne reste plus rien dans la ligne il faut sortir */ + } + } + + icPrec = ic; + ic = Csui[ic]; + } + HashCode[Var] = ( il + NbT ) % NombreDeContraintes; + NbTermesUtilesDeVar[Var] = NbT; +} + +/* On balaye les lignes dans l'ordre croissant du nombre de termes et on ne compare que les + les colonnes qui ont un terme dans cette ligne */ + +for ( NbT = 2 ; NbT <= Presolve->NbMaxTermesDesLignes ; NbT++ ) { + if ( NbVarDispo <= 0 ) goto FinComparaisons; + Cnt = ParLignePremiereContrainte[NbT]; + while ( Cnt >= 0 ) { + if ( NbVarDispo <= 0 ) goto FinComparaisons; + /*********************************************/ + if ( ContrainteInactive[Cnt] != NON_PNE ) goto NextCnt; + /* On prepare la table des colonnes a explorer */ + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + NbVarDeCnt = 0; + while ( il < ilMax ) { + if ( A[il] != 0 ) { + if ( Flag[Nuvar[il]] == COLONNE_A_ETUDIER ) { + NumVarDeCnt[NbVarDeCnt] = Nuvar[il]; + NbVarDeCnt++; + } + } + il++; + } + NbComparaisons = 0; + for ( il = 0 ; il < NbVarDeCnt ; il++ ) { + if ( NbVarDispo <= 0 ) goto FinComparaisons; + Var = NumVarDeCnt[il]; + if ( Flag[Var] == COLONNE_A_EVITER ) continue; + NbTermesUtiles = NbTermesUtilesDeVar[Var]; + HashVar = HashCode[Var]; + InitV = NON_PNE; + NbComparaisons++; + if ( NbComparaisons > MAX_NBTMX ) break; + + /* On compare a Var toutes les variables suivantes de la contrainte */ + for ( il1 = il + 1 ; il1 < NbVarDeCnt ; il1++ ) { + if ( NbVarDispo <= 0 ) goto FinComparaisons; + Var1 = NumVarDeCnt[il1]; + if ( Flag[Var1] == COLONNE_A_EVITER ) continue; + if ( HashCode[Var1] != HashVar ) continue; + if ( NbTermesUtilesDeVar[Var1] != NbTermesUtiles ) continue; + /* Comparaison de Var a Var1 et suppression eventuelle de Var1 */ + if ( InitV == NON_PNE ) { + /* Preparation des tables pour la variable Var */ + NbTermesUtiles = 0; + ic = Cdeb[Var]; + while ( ic >= 0 ) { + CntDeVar = NumContrainte[ic]; + V[CntDeVar] = A[ic]; + T[CntDeVar] = 1; + NbTermesUtiles++; + ic = Csui[ic]; + } + InitV = OUI_PNE; + } + + PRS_ComparerVariables( Presolve, Var, NbTermesUtiles, V, T, Var1, Flag, NbColonnesSupprimees, &NbVarDispo ); + + /* Si le Flag de Var a change on passe a la variable suivante */ + if ( Flag[Var] == COLONNE_A_EVITER ) goto NextColonne; + + } + /* RAZ de V et T avant de passer a la variable suivante */ + Flag[Var] = COLONNE_A_EVITER; + NbVarDispo--; + NextColonne: + if ( InitV == OUI_PNE ) { + ic = Cdeb[Var]; + while ( ic >= 0 ) { + V[NumContrainte[ic]] = 0.0; + T[NumContrainte[ic]] = 0; + ic = Csui[ic]; + } + } + } + /*********************************************/ + NextCnt: + Cnt = ParLigneContrainteSuivante[Cnt]; + } +} + +FinComparaisons: + +free( Buffer ); + +# if VERBOSE_PRS == 1 + printf("-> Nombre de colonnes supprimees par colinearite %d\n",*NbColonnesSupprimees); + fflush(stdout); +# endif + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_ComparerVariables( PRESOLVE * Presolve, int Var, int NbTermesUtilesDeVar, + double * V, char * T, int Var1, char * Flag, + int * NbColonnesSupprimees, int * NbVarDispo ) +{ +int Nb; int ic1; int * Cdeb; int * Csui; double Nu; int Cnt1; int * NumContrainte; +double * A; double DeltaC; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; + +Nu = 1.; /* Juste pour eviter les warning de compilation */ +Nb = NbTermesUtilesDeVar; +/* Determination du rapport */ +ic1 = Cdeb[Var1]; +Cnt1 = NumContrainte[ic1]; +if ( T[Cnt1] == 0 ) return; /* Pas de terme correspondant dans la ligne */ +Nu = A[ic1] / V[Cnt1]; +Nb--; +ic1 = Csui[ic1]; + +/* On poursuit l'analyse de la variable Var1 */ +while ( ic1 >= 0 ) { + Cnt1 = NumContrainte[ic1]; + if ( T[Cnt1] == 0 ) return; /* Pas de terme correspondant dans la ligne */ + if ( fabs( A[ic1] - (Nu * V[Cnt1] ) ) > ZERO_COLINEAIRE ) return; + Nb--; + ic1 = Csui[ic1]; +} + +if ( Nb == 0 ) { + DeltaC = Pne->LTrav[Var1] - ( Nu * Pne->LTrav[Var] ); + if ( fabs( DeltaC ) > SEUIL_POUR_DELTAC_NON_NUL ) { + PRS_ColonneColineairesDeltaCNonNul( Pne, Presolve, Var, Var1, Nu, DeltaC, Flag, NbColonnesSupprimees, NbVarDispo ); + if ( Flag[Var1] == COLONNE_A_ETUDIER ) { + /* On essaie a nouveau mais en inversant le role de Var et de Var1 */ + Nu = 1. / Nu; + DeltaC = Pne->LTrav[Var] - ( Nu * Pne->LTrav[Var1] ); + PRS_ColonneColineairesDeltaCNonNul( Pne, Presolve, Var1, Var, Nu, DeltaC, Flag, NbColonnesSupprimees, NbVarDispo ); + } + } + else if ( fabs( DeltaC ) < SEUIL_POUR_DELTAC_NUL ) { + PRS_ColonneColineairesDeltaCNul( Pne, Presolve, Var, Var1, Nu, Flag, NbColonnesSupprimees, NbVarDispo ); + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Cas ou la combinaison lineaire des couts n'est pas nulle */ +void PRS_ColonneColineairesDeltaCNonNul( PROBLEME_PNE * Pne, PRESOLVE * Presolve, + int Var, int Var1, double Nu, double DeltaC, + char * Flag, int * NbColonnesSupprimees, int * NbVarDispo ) +{ +char TypeBnrVar1; char TypeBrnVar; + +TypeBrnVar = PRS_ChoisirLaBorneLaPlusContraignantePourLesVariablesDuales( + Pne->TypeDeBorneTrav[Var], Presolve->TypeDeBornePourPresolve[Var], + Presolve->BorneInfPourPresolve[Var], Pne->UminTrav[Var], + Presolve->BorneSupPourPresolve[Var], Pne->UmaxTrav[Var], + Presolve->ConserverLaBorneInfDuPresolve[Var], Presolve->ConserverLaBorneSupDuPresolve[Var], + Presolve->TypeDeValeurDeBorneInf[Var], Presolve->TypeDeValeurDeBorneSup[Var] ); + + +/* +TypeBrnVar = (char) Presolve->TypeDeBornePourPresolve[Var]; +Presolve->ConserverLaBorneSupDuPresolve[Var] = OUI_PNE; +Presolve->ConserverLaBorneInfDuPresolve[Var] = OUI_PNE; +*/ + +TypeBnrVar1 = (char) Presolve->TypeDeBornePourPresolve[Var1]; + +if ( TypeBrnVar == VARIABLE_BORNEE_INFERIEUREMENT ) { + /* Le cout reduit doit etre positif ou nul */ + if ( Nu > 0 ) { + if ( DeltaC > SEUIL_POUR_DELTAC_NON_NUL ) { + /* Le cout reduit de Var1 est strictement positif */ + /* Variable Var1 sur borne inf */ + if ( TypeBnrVar1 == VARIABLE_NON_BORNEE || TypeBnrVar1 == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + *NbColonnesSupprimees = *NbColonnesSupprimees + 1; + Flag[Var1] = COLONNE_A_EVITER; + *NbVarDispo = *NbVarDispo - 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var1, Presolve->BorneInfPourPresolve[Var1] ); + } + } + else { + if ( DeltaC < -SEUIL_POUR_DELTAC_NON_NUL ) { + /* Variable Var1 sur borne sup */ + if ( TypeBnrVar1 == VARIABLE_NON_BORNEE || TypeBnrVar1 == VARIABLE_BORNEE_INFERIEUREMENT ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + *NbColonnesSupprimees = *NbColonnesSupprimees + 1; + Flag[Var1] = COLONNE_A_EVITER; + *NbVarDispo = *NbVarDispo - 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var1, Presolve->BorneSupPourPresolve[Var1] ); + } + } +} +else if ( TypeBrnVar == VARIABLE_BORNEE_SUPERIEUREMENT ) { + /* Le cout reduit doit etre negatif ou nul */ + if ( Nu > 0 ) { + if ( DeltaC < -SEUIL_POUR_DELTAC_NON_NUL ) { + /* Variable Var1 sur borne sup */ + if ( TypeBnrVar1 == VARIABLE_NON_BORNEE || TypeBnrVar1 == VARIABLE_BORNEE_INFERIEUREMENT ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + *NbColonnesSupprimees = *NbColonnesSupprimees + 1; + Flag[Var1] = COLONNE_A_EVITER; + *NbVarDispo = *NbVarDispo - 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var1, Presolve->BorneSupPourPresolve[Var1] ); + } + } + else { + if ( DeltaC > SEUIL_POUR_DELTAC_NON_NUL ) { + /* Variable Var1 sur borne inf */ + if ( TypeBnrVar1 == VARIABLE_NON_BORNEE || TypeBnrVar1 == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + *NbColonnesSupprimees = *NbColonnesSupprimees + 1; + Flag[Var1] = COLONNE_A_EVITER; + *NbVarDispo = *NbVarDispo - 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var1, Presolve->BorneInfPourPresolve[Var1] ); + } + } +} +else if ( TypeBrnVar == VARIABLE_NON_BORNEE ) { + if ( DeltaC > SEUIL_POUR_DELTAC_NON_NUL ) { + /* Variable Var1 sur borne inf */ + if ( TypeBnrVar1 == VARIABLE_NON_BORNEE || TypeBnrVar1 == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + *NbColonnesSupprimees = *NbColonnesSupprimees + 1; + Flag[Var1] = COLONNE_A_EVITER; + *NbVarDispo = *NbVarDispo - 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var1, Presolve->BorneInfPourPresolve[Var1] ); + } + else if ( DeltaC < -SEUIL_POUR_DELTAC_NON_NUL ) { + /* Variable Var1 sur borne sup */ + if ( TypeBnrVar1 == VARIABLE_NON_BORNEE || TypeBnrVar1 == VARIABLE_BORNEE_INFERIEUREMENT ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + *NbColonnesSupprimees = *NbColonnesSupprimees + 1; + Flag[Var1] = COLONNE_A_EVITER; + *NbVarDispo = *NbVarDispo - 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var1, Presolve->BorneSupPourPresolve[Var1] ); + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Cas ou la combinaison lineaire des couts est nulle: On remplace les variables + Var et Var1 par une autre variable dont on ajuste les bornes. Cette nouvelle + variable prend le numero Var */ +void PRS_ColonneColineairesDeltaCNul( PROBLEME_PNE * Pne, PRESOLVE * Presolve, + int Var, int Var1, double Nu, + char * Flag, int * NbColonnesSupprimees, int * NbVarDispo ) +{ +long double XminDeVar; long double XmaxDeVar; long double XminDeVar1; long double XmaxDeVar1; +long double Xmin; long double Xmax; int * TypeDeBornePourPresolve; char XminDeVarValide; +char XmaxDeVarValide; char XminDeVar1Valide; char XmaxDeVar1Valide; char XminValide; +char XmaxValide; char * ConserverLaBorneInfDuPresolve; char * ConserverLaBorneSupDuPresolve; +double * BorneInfPourPresolve; double * BorneSupPourPresolve; int * Cdeb; int * Csui; +int ic1; double * A; char * TypeDeValeurDeBorneInf; int * ContrainteBornanteInferieurement; +int * ContrainteBornanteSuperieurement; + +if ( Pne->NbCouplesDeVariablesColineaires >= Pne->NombreDeVariablesTrav ) return; +if ( Pne->NombreDOperationsDePresolve >= Pne->TailleTypeDOperationDePresolve ) return; + +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +TypeDeValeurDeBorneInf = Presolve->TypeDeValeurDeBorneInf; +ConserverLaBorneInfDuPresolve = Presolve->ConserverLaBorneInfDuPresolve; +ConserverLaBorneSupDuPresolve = Presolve->ConserverLaBorneSupDuPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +ContrainteBornanteInferieurement = Presolve->ContrainteBornanteInferieurement; +ContrainteBornanteSuperieurement = Presolve->ContrainteBornanteSuperieurement; + +XminDeVarValide = NON_PNE; +XmaxDeVarValide = NON_PNE; +XminDeVar1Valide = NON_PNE; +XmaxDeVar1Valide = NON_PNE; +XminValide = NON_PNE; +XmaxValide = NON_PNE; +Xmin = -LINFINI_PNE; +Xmax = LINFINI_PNE; +XminDeVar = (long double) BorneInfPourPresolve[Var]; +XminDeVar1 = (long double) BorneInfPourPresolve[Var1]; +XmaxDeVar = (long double) BorneSupPourPresolve[Var]; +XmaxDeVar1 = (long double) BorneSupPourPresolve[Var1]; + +if ( TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + XminDeVarValide = OUI_PNE; + XmaxDeVarValide = OUI_PNE; +} +else if ( TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + XminDeVarValide = OUI_PNE; +} +else if ( TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + XmaxDeVarValide = OUI_PNE; +} + +if ( TypeDeBornePourPresolve[Var1] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + XminDeVar1Valide = OUI_PNE; + XmaxDeVar1Valide = OUI_PNE; +} +else if ( TypeDeBornePourPresolve[Var1] == VARIABLE_BORNEE_INFERIEUREMENT ) { + XminDeVar1Valide = OUI_PNE; +} +else if ( TypeDeBornePourPresolve[Var1] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + XmaxDeVar1Valide = OUI_PNE; +} + +if ( Nu > 0 ) { + if ( XminDeVarValide == OUI_PNE && XminDeVar1Valide == OUI_PNE ) { + Xmin = XminDeVar + ( (long double ) Nu * XminDeVar1 ); + XminValide = OUI_PNE; + } + if ( XmaxDeVarValide == OUI_PNE && XmaxDeVar1Valide == OUI_PNE ) { + Xmax = XmaxDeVar + ( (long double ) Nu * XmaxDeVar1 ); + XmaxValide = OUI_PNE; + } +} +else { + if ( XminDeVarValide == OUI_PNE && XmaxDeVar1Valide == OUI_PNE ) { + Xmin = XminDeVar + ( (long double ) Nu * XmaxDeVar1 ); + XminValide = OUI_PNE; + } + if ( XmaxDeVarValide == OUI_PNE && XminDeVar1Valide == OUI_PNE ) { + Xmax = XmaxDeVar + ( (long double ) Nu * XminDeVar1 ); + XmaxValide = OUI_PNE; + } +} + +/* La nouvelle variable prend le numero Var */ + +/* Var1 devient fixe mais on met sa valeur a 0 */ +*NbColonnesSupprimees = *NbColonnesSupprimees + 1; +Flag[Var1] = COLONNE_A_EVITER; +*NbVarDispo = *NbVarDispo - 1; +PRS_FixerUneVariableAUneValeur( Presolve, Var1, 0.0 ); + +/* On change les bornes de Var */ +Flag[Var] = COLONNE_A_EVITER; +*NbVarDispo = *NbVarDispo - 1; + +if ( XminValide == OUI_PNE ) { + TypeDeBornePourPresolve[Var] = VARIABLE_BORNEE_INFERIEUREMENT; + if ( XmaxValide == OUI_PNE ) { + TypeDeBornePourPresolve[Var] = VARIABLE_BORNEE_DES_DEUX_COTES; + } +} +else { /* Xmin moins l'infini */ + if ( XmaxValide == OUI_PNE ) { + TypeDeBornePourPresolve[Var] = VARIABLE_BORNEE_SUPERIEUREMENT; + } + else { + TypeDeBornePourPresolve[Var] = VARIABLE_NON_BORNEE; + } +} + +BorneInfPourPresolve[Var] = (double) Xmin; +BorneSupPourPresolve[Var] = (double) Xmax; +ContrainteBornanteInferieurement[Var] = -1; +ContrainteBornanteSuperieurement[Var] = -1; +ConserverLaBorneInfDuPresolve[Var] = OUI_PNE; +ConserverLaBorneSupDuPresolve[Var] = OUI_PNE; +TypeDeValeurDeBorneInf[Var] = VALEUR_NATIVE; + +Presolve->VariableEquivalente[Var]++; + +/*printf("Xmin %e Xmax %e Var %d\n",(double) Xmin,(double) Xmax,Var);*/ + +/***************************************************************************************************/ +/* Attention modif temporaire: on ecrase UminTrav et UmaxTrav car il peut y avoir des incoherences */ +Pne->UminTrav[Var] = (double) Xmin; +Pne->UmaxTrav[Var] = (double) Xmax; +Pne->TypeDeBorneTrav[Var] = TypeDeBornePourPresolve[Var]; +/***************************************************************************************************/ + +/* On met des 0 dans la colonne de Var1 */ +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +A = Pne->ATrav; +ic1 = Cdeb[Var1]; +while ( ic1 >= 0 ) { + A[ic1] = 0.0; + ic1 = Csui[ic1]; +} + +/* Infos pour le postsolve */ +Pne->TypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = SUPPRESSION_COLONNE_COLINEAIRE; +Pne->IndexDansLeTypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = Pne->NbCouplesDeVariablesColineaires; +Pne->NombreDOperationsDePresolve++; + +Pne->PremiereVariable [Pne->NbCouplesDeVariablesColineaires] = Var; +Pne->XminPremiereVariable[Pne->NbCouplesDeVariablesColineaires] = (double) XminDeVar; +Pne->XmaxPremiereVariable[Pne->NbCouplesDeVariablesColineaires] = (double) XmaxDeVar; + +Pne->DeuxiemeVariable [Pne->NbCouplesDeVariablesColineaires] = Var1; +Pne->XminDeuxiemeVariable[Pne->NbCouplesDeVariablesColineaires] = (double) XminDeVar1; +Pne->XmaxDeuxiemeVariable[Pne->NbCouplesDeVariablesColineaires] = (double) XmaxDeVar1; + +Pne->ValeurDeNu [Pne->NbCouplesDeVariablesColineaires] = Nu; +Pne->NbCouplesDeVariablesColineaires++; +/* Fin infos pour le postsolve */ + +return; + +} + diff --git a/src/ext/Sirius_Solver/presolve/prs_combinaisons_de_contraintes.c b/src/ext/Sirius_Solver/presolve/prs_combinaisons_de_contraintes.c new file mode 100644 index 0000000000..707f9a73da --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_combinaisons_de_contraintes.c @@ -0,0 +1,399 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: La procedure consiste a chercher des contraintes de meme + support et a en calculer une combinaison lineaire pour + faire disparaitre une des variables d'une des contraintes. + On augmente ainsi le creux de la matrice des contraintes. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# define TRACES 0 + +# define MAX_NBTMX 100 /*100*/ /* Nb max de contraintes examinees pour chqie colonne */ +# define MAX_TERMES_UTILES 20 /* 20 */ /* Nb max de termes de la colonne pivot */ +# define EPSILON_POUR_ANNULATION 1.e-16 /*1.e-16*/ + +void PRS_ComparerContraintesADeuxTermesUtiles( PRESOLVE * , int , char , double , int * , int , + double * , char * , int , char * , int * ); + +/*----------------------------------------------------------------------------*/ + +void PRS_CombinaisonDeContraintes( PRESOLVE * Presolve, int * NbModifications ) +{ +int il; int ic; int ilDebCnt; int ilMaxCnt; int ic1; int NombreDeContraintes; +int NombreDeVariables; int Cnt; int Cnt1; double * V; char * T; int LallocTas; +double BCnt; double * B; int * Mdeb; int * NbTerm; int * Nuvar; double * A; +int * NumContrainte; double S; char * Flag; char * pt; +char * ContrainteInactive; int * Cdeb; int * Csui; int * TypeDeBornePourPresolve; +int Var; int NbT; int * ParColonnePremiereVariable; int * ParColonneVariableSuivante; +char * Buffer; char * SensContrainte; double * ValeurDeXPourPresolve; +int NbCntDeVar; int * NumCntDeVar; char SensCnt; int VarDeCnt; +int * IndexIlDeVar; int * NbTermesUtilesDeCnt; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +*NbModifications = 0; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; + +B = Pne->BTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +SensContrainte = Pne->SensContrainteTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; + +ContrainteInactive = Presolve->ContrainteInactive; +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ParColonnePremiereVariable = Presolve->ParColonnePremiereVariable; +ParColonneVariableSuivante = Presolve->ParColonneVariableSuivante; + +LallocTas = 0; +LallocTas += NombreDeVariables * sizeof( double ); /* V */ +LallocTas += NombreDeVariables * sizeof( char ); /* T */ +LallocTas += NombreDeContraintes * sizeof( char ); /* Flag */ +LallocTas += NombreDeContraintes * sizeof( int ); /* NumCntDeVar */ +LallocTas += NombreDeContraintes * sizeof( int ); /* IndexIlDeVar */ +LallocTas += NombreDeContraintes * sizeof( int ); /* NbTermesUtilesDeCnt */ + +Buffer = (char *) malloc( LallocTas ); +if ( Buffer == NULL ) { + printf(" Solveur PNE , memoire insuffisante dans le presolve. Sous-programme: PRS_CombinaisonDeContraintes \n"); + return; +} + +pt = Buffer; +V = (double *) pt; +pt += NombreDeVariables * sizeof( double ); +T = (char *) pt; +pt += NombreDeVariables * sizeof( char ); +Flag = (char *) pt; +pt += NombreDeContraintes * sizeof( char ); +NumCntDeVar = (int *) pt; +pt += NombreDeContraintes * sizeof( int ); +IndexIlDeVar = (int *) pt; +pt += NombreDeContraintes * sizeof( int ); +NbTermesUtilesDeCnt = (int *) pt; +pt += NombreDeContraintes * sizeof( int ); + +memset( (char *) T, 0, NombreDeVariables * sizeof( char ) ); + +/* Flag = 0 s'il faut prendre en compte la contrainte */ + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteInactive[Cnt] == OUI_PNE ) Flag[Cnt] = 1; + else Flag[Cnt] = 0; + /* Calcul d'un hashcode */ + NbT = 0; + ic = 0; + il = Mdeb[Cnt]; + ilMaxCnt = il + NbTerm[Cnt]; + while ( il < ilMaxCnt ) { + if ( A[il] != 0.0 ) { + if ( TypeDeBornePourPresolve[Nuvar[il]] != VARIABLE_FIXE ) NbT++; + } + il++; + } + NbTermesUtilesDeCnt[Cnt] = NbT; +} + +/* On balaye les colonnes dans l'ordre decroissant du nombre de termes et on ne compare que les + les lignes qui ont un terme dans cette colonne */ + +/*for ( NbT = 2 ; NbT <= Presolve->NbMaxTermesDesColonnes ; NbT++ ) {*/ + +/*printf("NbMaxTermesDesColonnes %d\n", Presolve->NbMaxTermesDesColonnes);*/ + +for ( NbT = Presolve->NbMaxTermesDesColonnes ; NbT >=2 ; NbT-- ) { + Var = ParColonnePremiereVariable[NbT]; + while ( Var >= 0 ) { + /*********************************************/ + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) goto NextVar; + /* On prepare la table des contraintes a explorer */ + NbCntDeVar = 0; + ic = Cdeb[Var]; + while ( ic >= 0 ) { + if ( fabs( A[ic] ) > ZERO_PRESOLVE ) { + Cnt = NumContrainte[ic]; + if ( Flag[Cnt] == 0 && NbTermesUtilesDeCnt[Cnt] <= MAX_TERMES_UTILES ) { + NumCntDeVar[NbCntDeVar] = Cnt; + IndexIlDeVar[NbCntDeVar] = ic; + NbCntDeVar++; + } + } + ic = Csui[ic]; + } + + if ( NbCntDeVar <= 1 ) goto NextVar; + + if ( NbCntDeVar > MAX_NBTMX ) NbCntDeVar = MAX_NBTMX; + + /* On balaie les contraintes de la variable Var */ + + for ( ic = 0 ; ic < NbCntDeVar ; ic++ ) { + if ( A[IndexIlDeVar[ic]] == 0.0 ) continue; + Cnt = NumCntDeVar[ic]; + if ( Flag[Cnt] == 1 ) continue; + if ( SensContrainte[Cnt] != '=' ) continue; + if ( NbTermesUtilesDeCnt[Cnt] <= 1 ) continue; + /*if ( NbTermesUtilesDeCnt[Cnt] > MAX_TERMES_UTILES ) continue;*/ + /* Preparation des tables pour la contrainte Cnt */ + S = 0.0; + ilDebCnt = Mdeb[Cnt]; + ilMaxCnt = ilDebCnt + NbTerm[Cnt]; + il = ilDebCnt; + while ( il < ilMaxCnt ) { + if ( A[il] != 0.0 ) { + VarDeCnt = Nuvar[il]; + if ( TypeDeBornePourPresolve[VarDeCnt] != VARIABLE_FIXE ) { + V[VarDeCnt] = A[il]; + T[VarDeCnt] = 1; + } + else S += A[il] * ValeurDeXPourPresolve[VarDeCnt]; + } + il++; + } + + BCnt = B[Cnt] - S; + SensCnt = SensContrainte[Cnt]; + + /* On compare a Cnt toutes les contraintes suivantes de la colonne */ + for ( ic1 = 0 /*ic + 1*/ ; ic1 < NbCntDeVar ; ic1++ ) { + if ( ic1 == ic ) continue; + if ( A[IndexIlDeVar[ic1]] == 0.0 ) continue; + + Cnt1 = NumCntDeVar[ic1]; + if ( Flag[Cnt1] != 0 ) continue; + if ( NbTermesUtilesDeCnt[Cnt1] < NbTermesUtilesDeCnt[Cnt] ) continue; + /* Comparaison de Cnt a Cnt1 */ + + PRS_ComparerContraintesADeuxTermesUtiles( Presolve, Cnt, SensCnt, BCnt, NbTermesUtilesDeCnt, + Var, V, T, Cnt1, Flag, NbModifications ); + + + + /* Si le Flag de Cnt a change on passe a la contrainte suivante */ + if ( Flag[Cnt] == 1 ) break; + + } + /* RAZ de V et T avant de passer a la contrainte suivante */ + /*Flag[Cnt] = 1;*/ + il = ilDebCnt; + while ( il < ilMaxCnt ) { + V[Nuvar[il]] = 0.0; + T[Nuvar[il]] = 0; + il++; + } + } + + /* + for ( ic = 0 ; ic < NbCntDeVar ; ic++ ) { + Flag[NumCntDeVar[ic]] = 1; + } + */ + + /*********************************************/ + NextVar: + Var = ParColonneVariableSuivante[Var]; + } +} + +free( Buffer ); + +# if VERBOSE_PRS == 1 + printf("-> Nombre de combinaisons de contraintes %d\n",*NbModifications); + fflush(stdout); +# endif + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_ComparerContraintesADeuxTermesUtiles( PRESOLVE * Presolve, int Cnt, + char SensCnt, double BCnt, + int * NbTermesUtilesDeCnt, + int VariablePivot, + double * V, char * T, int Cnt1, + char * Flag, int * NbModifications ) +{ +int Nb; int il1; int il1Max; int * Mdeb; int * NbTerm; double * A; int * Nuvar; +int Var1; double * B; long double Rapport; int ilDeRapport; double * ValeurDeXPourPresolve; +char * SensContrainte; int * TypeDeBornePourPresolve; char SensCnt1; PROBLEME_PNE * Pne; +int il1Deb; int * TypeDeVariable; double X; double PlusGrandTerme; double PlusPetitTerme; + +if ( SensCnt != '=' ) return; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +SensContrainte = Pne->SensContrainteTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +B = Pne->BTrav; +A = Pne->ATrav; +Nuvar = Pne->NuvarTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +PlusGrandTerme = Pne->PlusGrandTerme; +PlusPetitTerme = Pne->PlusPetitTerme; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +Rapport = 1; +ilDeRapport = -1; +/* Si la contrainte Cnt1 contient le support de la contrainte Cnt, on cherche a annuler 1 + terme de la contrainte Cnt1 */ +Nb = NbTermesUtilesDeCnt[Cnt]; +il1Deb = Mdeb[Cnt1]; +il1Max = il1Deb + NbTerm[Cnt1]; +/* Determination du rapport */ +il1 = il1Deb; +while ( il1 < il1Max ) { + if ( A[il1] != 0.0 ) { + Var1 = Nuvar[il1]; + if ( TypeDeBornePourPresolve[Var1] != VARIABLE_FIXE ) { + if ( T[Var1] == 1 ) Nb--; + if ( Var1 == VariablePivot ) { + Rapport = -A[il1] / (long double) V[VariablePivot]; + ilDeRapport = il1; + } + } + } + il1++; +} + +if ( Nb != 0 ) return; +if ( ilDeRapport < 0 ) return; + +/* Le support de Cnt est inclus dans celui de Cnt1, on va chercher un terme a annuler dans Cnt1 */ + +/* On verifie qu'on ne deconditionne pas trop le systeme */ +il1 = il1Deb; +while ( il1 < il1Max ) { + if ( il1 != ilDeRapport ) { + if ( A[il1] != 0.0 ) { + Var1 = Nuvar[il1]; + if ( TypeDeBornePourPresolve[Var1] != VARIABLE_FIXE ) { + if ( T[Var1] == 1 ) { + X = fabs( A[il1] + ((long double) V[Var1] * Rapport) ); + if ( X < EPSILON_POUR_ANNULATION ) X = 0.0; + if ( X > PlusGrandTerme || (X < PlusPetitTerme && X != 0.0 ) ) { + # if TRACES == 1 + printf("Refus de la combinaison car mauvais conditionnement: PlusPetitTerme %e PlusGrandTerme %e et X = %e \n", + PlusPetitTerme,PlusGrandTerme,X); + printf(" A %18.15e V %18.15e Rapport %18.15e\n",A[il1],V[Var1],(double)Rapport); + /* Impression des 2 contraintes */ + printf("Contrainte 1: %d\n",Cnt); + il1 = Mdeb[Cnt]; + il1Max = il1 + NbTerm[Cnt]; + while ( il1 < il1Max ) { + printf(" %15.10e (%d) ",A[il1],Nuvar[il1]); + il1++; + } + printf(" %c %15.10e\n",Pne->SensContrainteTrav[Cnt],Pne->BTrav[Cnt]); + + printf("Contrainte 2: %d\n",Cnt1); + il1 = Mdeb[Cnt1]; + il1Max = il1 + NbTerm[Cnt1]; + while ( il1 < il1Max ) { + printf(" %15.10e (%d) ",A[il1],Nuvar[il1]); + il1++; + } + printf(" %c %15.10e\n",Pne->SensContrainteTrav[Cnt1],Pne->BTrav[Cnt1]); + # endif + return; + } + } + } + } + } + il1++; +} + +if ( fabs( A[ilDeRapport] + ((long double) V[VariablePivot] * Rapport) ) > EPSILON_POUR_ANNULATION ) { + # if TRACES == 1 + printf("Refus de la combinaison car elle n'annule pas le terme choisi: %20.16e et Rapport %e\n", + fabs( A[ilDeRapport] + ((long double) V[VariablePivot] * Rapport) ),(double) Rapport); + # endif + return; +} + +SensCnt1 = SensContrainte[Cnt1]; + +/* On modifie Cnt1 */ +il1 = il1Deb; +while ( il1 < il1Max ) { + if ( A[il1] != 0.0 ) { + Var1 = Nuvar[il1]; + if ( TypeDeBornePourPresolve[Var1] != VARIABLE_FIXE ) { + if ( T[Var1] == 1 ) { + A[il1] += (long double) V[Var1] * Rapport; + if ( fabs( A[il1] ) < EPSILON_POUR_ANNULATION ) { + A[il1] = 0.0; + NbTermesUtilesDeCnt[Cnt1]--; + } + } + } + } + il1++; +} + +/* +A[ilDeRapport] = 0.0; +NbTermesUtilesDeCnt[Cnt1]--; +*/ + +/* Si la contrainte etait bornante pour cette variable on initialise la conservation + de la borne puisque la variable disparait de la contrainte */ +if ( Presolve->ContrainteBornanteSuperieurement[VariablePivot] == Cnt1 ) { + Presolve->ConserverLaBorneSupDuPresolve[VariablePivot] = OUI_PNE; + Presolve->ContrainteBornanteSuperieurement[VariablePivot] = -1; +} +if ( Presolve->ContrainteBornanteInferieurement[VariablePivot] == Cnt ) { + Presolve->ConserverLaBorneInfDuPresolve[VariablePivot] = OUI_PNE; + Presolve->ContrainteBornanteInferieurement[VariablePivot] = -1; +} + +B[Cnt1] += Rapport * BCnt; +*NbModifications = *NbModifications + 1; +/*Flag[Cnt1] = 1;*/ + + +return; +} + + + diff --git a/src/ext/Sirius_Solver/presolve/prs_contraintes_colineaires.c b/src/ext/Sirius_Solver/presolve/prs_contraintes_colineaires.c new file mode 100644 index 0000000000..2d46853c06 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_contraintes_colineaires.c @@ -0,0 +1,423 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recherche de contraintes colineaires. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# include "lu_define.h" +# include "lu_fonctions.h" + +# define ZERO_COLINEAIRE 1.e-10 /*1.e-10*/ +# define ZERO_QUASI_COLINEAIRE 1.e-7 /*1.e-7*/ +# define MARGE_POUR_INFAISABILITE 1.e-6 /*1.e-6*/ +# define MAX_NBTMX 1000 + +void PRS_ComparerContraintes( PRESOLVE * , int , int , double , double * , char * , int , char * , int * ); +void PRS_InhiberUneContrainte( PROBLEME_PNE * , PRESOLVE * , char * , int , int , int * ); + +/*----------------------------------------------------------------------------*/ + +void PRS_ContraintesColineaires( PRESOLVE * Presolve , int * NbContraintesSupprimees ) +{ +int il; int ic; int ilDebCnt; int ilMaxCnt; int ic1; int NombreDeContraintes; +int NombreDeVariables; int Cnt; int Cnt1; double * V; char * T; int LallocTas; +double BCnt; double * B; int * Mdeb; int * NbTerm; int * Nuvar; double * A; +int * NumContrainte; int NbTermesUtilesDeCnt; double S; char * Flag; char * pt; +char * ContrainteInactive; int * Cdeb; int * Csui; int * TypeDeBornePourPresolve; +int Var; int NbT; int * ParColonnePremiereVariable; int * ParColonneVariableSuivante; +char * Buffer; char * SensContrainte; int HashCnt; double * ValeurDeXPourPresolve; +int * HashCode; char InitV; int NbCntDeVar; int * NumCntDeVar; int VarCnt; +PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +*NbContraintesSupprimees = 0; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; + +B = Pne->BTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +SensContrainte = Pne->SensContrainteTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; + +ContrainteInactive = Presolve->ContrainteInactive; +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ParColonnePremiereVariable = Presolve->ParColonnePremiereVariable; +ParColonneVariableSuivante = Presolve->ParColonneVariableSuivante; + +LallocTas = 0; +LallocTas += NombreDeVariables * sizeof( double ); /* V */ +LallocTas += NombreDeVariables * sizeof( char ); /* T */ +LallocTas += NombreDeContraintes * sizeof( char ); /* Flag */ +LallocTas += NombreDeContraintes * sizeof( int ); /* HashCode */ +LallocTas += NombreDeContraintes * sizeof( int ); /* NumCntDeVar */ + +Buffer = (char *) malloc( LallocTas ); +if ( Buffer == NULL ) { + printf(" Solveur PNE , memoire insuffisante dans le presolve. Sous-programme: PRS_ContraintesColineaires \n"); + return; +} + +pt = Buffer; +V = (double *) pt; +pt += NombreDeVariables * sizeof( double ); +T = (char *) pt; +pt += NombreDeVariables * sizeof( char ); +Flag = (char *) pt; +pt += NombreDeContraintes * sizeof( char ); +HashCode = (int *) pt; +pt += NombreDeContraintes * sizeof( int ); +NumCntDeVar = (int *) pt; +pt += NombreDeContraintes * sizeof( int ); + +memset( (char *) T, 0, NombreDeVariables * sizeof( char ) ); + +/* Flag = 0 s'il faut prendre en compte la contrainte */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteInactive[Cnt] == OUI_PNE ) Flag[Cnt] = 1; + else Flag[Cnt] = 0; + /* Calcul d'un hashcode */ + NbT = 0; + ic = 0; + il = Mdeb[Cnt]; + ilMaxCnt = il + NbTerm[Cnt]; + while ( il < ilMaxCnt ) { + if ( A[il] != 0.0 ) { + Var = Nuvar[il]; + if ( TypeDeBornePourPresolve[Var] != VARIABLE_FIXE ) { + NbT++; + ic += Var; + } + } + il++; + } + HashCode[Cnt] = ( ic + NbT ) % NombreDeVariables; +} + +/* On balaye les colonnes dans l'ordre croissant du nombre de termes et on ne compare que les + les lignes qui ont un terme dans cette colonne */ + +for ( NbT = 2 ; NbT <= Presolve->NbMaxTermesDesColonnes ; NbT++ ) { + Var = ParColonnePremiereVariable[NbT]; + while ( Var >= 0 ) { + /*********************************************/ + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) goto NextVar; + /* On prepare la table des contraintes a explorer */ + NbCntDeVar = 0; + ic = Cdeb[Var]; + while ( ic >= 0 ) { + if ( A[ic] != 0 ) { + Cnt = NumContrainte[ic]; + if ( Flag[Cnt] == 0 ) { + NumCntDeVar[NbCntDeVar] = Cnt; + NbCntDeVar++; + } + } + ic = Csui[ic]; + } + + if ( NbCntDeVar > MAX_NBTMX ) NbCntDeVar = MAX_NBTMX; + + for ( ic = 0 ; ic < NbCntDeVar ; ic++ ) { + Cnt = NumCntDeVar[ic]; + if ( Flag[Cnt] == 1 ) continue; + ilDebCnt = 0; + HashCnt = HashCode[Cnt]; + InitV = NON_PNE; + ilMaxCnt = -1; + BCnt = LINFINI_PNE; + NbTermesUtilesDeCnt = 0; + /* On compare a Cnt toutes les contraintes suivantes de la colonne */ + for ( ic1 = ic + 1 ; ic1 < NbCntDeVar ; ic1++ ) { + Cnt1 = NumCntDeVar[ic1]; + if ( HashCode[Cnt1] != HashCnt ) continue; + if ( Flag[Cnt1] != 0 ) continue; + /* Comparaison de Cnt a Cnt1 */ + if ( InitV == NON_PNE ) { + /* Preparation des tables pour la contrainte Cnt */ + S = 0.0; + ilDebCnt = Mdeb[Cnt]; + ilMaxCnt = ilDebCnt + NbTerm[Cnt]; + il = ilDebCnt; + while ( il < ilMaxCnt ) { + if ( A[il] != 0.0 ) { + VarCnt = Nuvar[il]; + if ( TypeDeBornePourPresolve[VarCnt] != VARIABLE_FIXE ) { + V[VarCnt] = A[il]; + T[VarCnt] = 1; + NbTermesUtilesDeCnt++; + } + else S += A[il] * ValeurDeXPourPresolve[VarCnt]; + } + il++; + } + BCnt = B[Cnt] - S; + InitV = OUI_PNE; + if ( NbTermesUtilesDeCnt <= 0 ) break; + } + PRS_ComparerContraintes( Presolve, Cnt, NbTermesUtilesDeCnt, BCnt, V, T, + Cnt1, Flag, NbContraintesSupprimees ); + + /* Si le Flag de Cnt a change on passe a la contrainte suivante */ + if ( Flag[Cnt] == 1 ) break; + + } + /* RAZ de V et T avant de passer a la contrainte suivante */ + Flag[Cnt] = 1; + if ( InitV == OUI_PNE ) { + il = ilDebCnt; + while ( il < ilMaxCnt ) { + V[Nuvar[il]] = 0.0; + T[Nuvar[il]] = 0; + il++; + } + } + } + /*********************************************/ + NextVar: + Var = ParColonneVariableSuivante[Var]; + } +} + +free( Buffer ); + +# if VERBOSE_PRS == 1 + printf("-> Nombre de contraintes supprimees par colinearite %d\n",*NbContraintesSupprimees); + fflush(stdout); +# endif + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_ComparerContraintes( PRESOLVE * Presolve, int Cnt, int NbTermesUtilesDeCnt, double BCnt, + double * V, char * T, int Cnt1, char * Flag, int * NbContraintesSupprimees ) +{ +int Nb; double S1; int il1; int il1Max; int * Mdeb; int * NbTerm; double * A; int * Nuvar; +int Var1; double * B; long double BCnt1; long double Rapport; double * ValeurDeXPourPresolve; +char * SensContrainte; int * TypeDeBornePourPresolve; char SensCnt1; char SensCnt; PROBLEME_PNE * Pne; +long double X; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +SensContrainte = Pne->SensContrainteTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +B = Pne->BTrav; +A = Pne->ATrav; +Nuvar = Pne->NuvarTrav; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; + +Nb = NbTermesUtilesDeCnt; +S1 = 0.0; +il1 = Mdeb[Cnt1]; +il1Max = il1 + NbTerm[Cnt1]; +/* Determination du rapport */ +Rapport = 1.0; +while ( il1 < il1Max ) { + if ( A[il1] != 0.0 ) { + Var1 = Nuvar[il1]; + if ( TypeDeBornePourPresolve[Var1] == VARIABLE_FIXE ) S1 += A[il1] * ValeurDeXPourPresolve[Var1]; + else { + if ( T[Var1] == 0 ) return; /* Pas de terme correspondant dans la colonne */ + Rapport = (long double) V[Var1] / (long double) A[il1]; + Nb--; + il1++; + break; + } + } + il1++; +} + +/* On poursuit l'analyse de la contrainte Cnt1 */ +while ( il1 < il1Max ) { + if ( A[il1] != 0.0 ) { + Var1 = Nuvar[il1]; + if ( TypeDeBornePourPresolve[Var1] == VARIABLE_FIXE ) S1 += A[il1] * ValeurDeXPourPresolve[Var1]; + else { + if ( T[Var1] == 0 ) return; + /* Il est utile de supprimer les contraintes quasi colineaires. ces contraintes sont + souvent produites par les modeleurs. Elles n'apportent rien mais les conserver + conduisent a des difficultes numeriques. Pour cette raison, le ZERO_RAPPORT_COLINEAIRE + reste assez grand. Dans une etape suivante on controle que la combinaison lineaire + permet bien d'avoir un vecteur quasi nul */ + X = fabs( (long double) V[Var1] - ( Rapport * (long double) A[il1]) ); + if ( X > ZERO_QUASI_COLINEAIRE ) return; + /* Le terme resultant est-il suffisament plus petit que le terme d'origine ? */ + if ( X / ( fabs( A[il1] ) + ZERO_COLINEAIRE ) > ZERO_COLINEAIRE ) return; + Nb--; + } + } + il1++; +} + +if ( Nb != 0 ) return; + +SensCnt = SensContrainte[Cnt]; + +BCnt1 = (long double) B[Cnt1] - (long double) S1; +SensCnt1 = SensContrainte[Cnt1]; + +if ( SensCnt == '=' ) { + if ( SensCnt1 == '=' ) { + X = fabs( (long double) BCnt - (Rapport * BCnt1) ); + if ( X > ZERO_QUASI_COLINEAIRE ) return; /* Il est preferable de ne pas se prononcer sur la faisabilite */ + /* Cnt et Cnt1 sont colineaires on inhibe Cnt1 */ + PRS_InhiberUneContrainte( Pne, Presolve, Flag, Cnt, Cnt1, NbContraintesSupprimees ); + } + else if ( SensCnt1 == '<' ) { + if ( Rapport > 0.0 ) { + if ( Rapport * BCnt1 < (long double) BCnt - MARGE_POUR_INFAISABILITE ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + else if ( Rapport * BCnt1 >= (long double) BCnt ) { + /* Cnt et Cnt1 sont colineaires on inhibe Cnt1 */ + PRS_InhiberUneContrainte( Pne, Presolve, Flag, Cnt, Cnt1, NbContraintesSupprimees ); + } + } + else { + /* Le rapport est negatif */ + if ( Rapport * BCnt1 > (long double) BCnt + MARGE_POUR_INFAISABILITE ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + else if ( Rapport * BCnt1 <= (long double) BCnt ) { + /* Cnt et Cnt1 sont colineaires on inhibe Cnt1 */ + PRS_InhiberUneContrainte( Pne, Presolve, Flag, Cnt, Cnt1, NbContraintesSupprimees ); + } + } + } +} +else { + /* La contrainte Cnt est de type < */ + if ( SensCnt1 == '=' ) { + if ( (long double) BCnt < (Rapport * BCnt1) - MARGE_POUR_INFAISABILITE ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + else if ( (long double) BCnt >= Rapport * BCnt1 ) { + /* Cnt et Cnt1 sont colineaires on inhibe Cnt */ + PRS_InhiberUneContrainte( Pne, Presolve, Flag, Cnt1, Cnt, NbContraintesSupprimees ); + } + } + else { + /* La contrainte Cnt1 est aussi de type < */ + if ( Rapport > 0.0 ) { + if ( (long double) BCnt < Rapport * BCnt1 ) { + /* On inhibe Cnt1 */ + PRS_InhiberUneContrainte( Pne, Presolve, Flag, Cnt, Cnt1, NbContraintesSupprimees ); + } + else { + /* On inhibe Cnt */ + PRS_InhiberUneContrainte( Pne, Presolve, Flag, Cnt1, Cnt, NbContraintesSupprimees ); + } + } + else { + /* Rapport < 0 */ + if ( Rapport * BCnt1 > (long double) BCnt + MARGE_POUR_INFAISABILITE ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + else if ( fabs( (long double) BCnt - (Rapport * BCnt1) ) < ZERO_COLINEAIRE ) { + /* On inhibe Cnt1 */ + PRS_InhiberUneContrainte( Pne, Presolve, Flag, Cnt, Cnt1, NbContraintesSupprimees ); + /* On transforme Cnt en = */ + SensContrainte[Cnt] = '='; + /* Comme on transforme le sens de la contrainte, la variable duale que l'on avait n'est plus exploitable + puisque cette nouvelle contrainte en regroupe 2 */ + Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_NON_INITIALISE; + Presolve->LambdaMin[Cnt] = -LINFINI_PNE; + Presolve->LambdaMax[Cnt] = LINFINI_PNE; + } + } + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_InhiberUneContrainte( PROBLEME_PNE * Pne, PRESOLVE * Presolve, char * Flag, + int ContrainteConservee, int ContrainteInhibee, + int * NbContraintesSupprimees ) +{ +int il1; int il1Max; int Var1; int * Mdeb; int * NbTerm; int * Nuvar; +int * ContrainteBornanteInferieurement; int * ContrainteBornanteSuperieurement; + +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; + +ContrainteBornanteInferieurement = Presolve->ContrainteBornanteInferieurement; +ContrainteBornanteSuperieurement = Presolve->ContrainteBornanteSuperieurement; + +/* On reporte ContrainteBornanteSuperieurement et ContrainteBornanteInferieurement + sur la contrainte conservee */ +il1 = Mdeb[ContrainteInhibee]; +il1Max = il1 + NbTerm[ContrainteInhibee]; +while ( il1 < il1Max ) { + Var1 = Nuvar[il1]; + if ( ContrainteBornanteSuperieurement[Var1] == ContrainteInhibee ) ContrainteBornanteSuperieurement[Var1] = ContrainteConservee; + if ( ContrainteBornanteInferieurement[Var1] == ContrainteInhibee ) ContrainteBornanteInferieurement[Var1] = ContrainteConservee; + il1++; +} +Presolve->ContrainteInactive[ContrainteInhibee] = OUI_PNE; +Pne->NumeroDesContraintesInactives[Pne->NombreDeContraintesInactives] = ContrainteInhibee; +Pne->NombreDeContraintesInactives++; + +/* Pour le postsolve */ +Pne->TypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = SUPPRESSION_CONTRAINTE_COLINEAIRE; +Pne->IndexDansLeTypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = Pne->NbSuppressionsDeContraintesColineaires; +Pne->NombreDOperationsDePresolve++; + +Pne->ContrainteConservee[Pne->NbSuppressionsDeContraintesColineaires] = Pne->CorrespondanceCntPneCntEntree[ContrainteConservee]; +Pne->ContrainteSupprimee[Pne->NbSuppressionsDeContraintesColineaires] = Pne->CorrespondanceCntPneCntEntree[ContrainteInhibee]; +Pne->NbSuppressionsDeContraintesColineaires++; + +Flag[ContrainteInhibee] = 1; +*NbContraintesSupprimees = *NbContraintesSupprimees + 1; + +return; +} + diff --git a/src/ext/Sirius_Solver/presolve/prs_contraintes_inactives.c b/src/ext/Sirius_Solver/presolve/prs_contraintes_inactives.c new file mode 100644 index 0000000000..e9273718db --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_contraintes_inactives.c @@ -0,0 +1,102 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Detection des contraintes toujours inactives. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PRS_ContraintesToujoursInactives( PRESOLVE * Presolve, int * NbCntInact ) +{ +int Cnt; int Nb; double Seuil; PROBLEME_PNE * Pne; int NombreDeContraintes; +double * MaxContrainte; double * B; double * MinContrainte; int * Nuvar; +char * ContrainteInactive; char * SensContrainte; char * MaxContrainteCalcule; +char * MinContrainteCalcule; int * Mdeb; int * NbTerm; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; + +ContrainteInactive = Presolve->ContrainteInactive; +SensContrainte = Pne->SensContrainteTrav; + +MaxContrainte = Presolve->MaxContrainte; +MinContrainte = Presolve->MinContrainte; +B = Pne->BTrav; +MaxContrainteCalcule = Presolve->MaxContrainteCalcule; +MinContrainteCalcule = Presolve->MinContrainteCalcule; + +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; + +/* On regarde si certaines contraintes sont toujours satisfaites */ +Seuil = 0.05 * SEUIL_DADMISSIBILITE; + +for ( Nb = 0 , Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + + if ( ContrainteInactive[Cnt] == OUI_PNE ) continue; + + /* A ce stade toutes les contraintes sont soit en = soit en < */ + if ( SensContrainte[Cnt] == '<' ) { + if ( MaxContrainte[Cnt] <= B[Cnt] && MaxContrainteCalcule[Cnt] == OUI_PNE ) { + # if TRACES == 1 + printf("Contrainte d'inegalite %d desactivee car ne peut etre jamais atteinte\n",Cnt); + # endif + Nb++ ; + PRS_DesactiverContrainte( Presolve, Cnt ); + } + } + else { /* Contrainte d'egalite */ + if ( fabs( MaxContrainte[Cnt] - B[Cnt] ) < Seuil && fabs( MinContrainte[Cnt] - B[Cnt] ) < Seuil && + MaxContrainteCalcule[Cnt] == OUI_PNE && MinContrainteCalcule[Cnt] == OUI_PNE ) { + # if TRACES == 1 + printf("Contrainte d'egalite %d desactivee car ne peut etre jamais atteinte\n",Cnt); + # endif + Nb++ ; + PRS_DesactiverContrainte( Presolve, Cnt ); + } + } + +} + +#if VERBOSE_PRS == 1 + printf("-> Nombre de contraintes supprimees car jamais actives %d\n",Nb); + fflush(stdout); +#endif + +*NbCntInact = Nb; + +return; +} + + + diff --git a/src/ext/Sirius_Solver/presolve/prs_contruire_graphe_DIMACS.c b/src/ext/Sirius_Solver/presolve/prs_contruire_graphe_DIMACS.c new file mode 100644 index 0000000000..c0694cb9f3 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_contruire_graphe_DIMACS.c @@ -0,0 +1,238 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +# ifdef ON_COMPILE + +/*********************************************************************** + + FONCTION: Construction du graphe au format DIMACS + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PRS_ConstruireLeGrapheAuFormatDIMACS( PRESOLVE * Presolve ) +{ +int NombreDeVariables; int NombreDeContraintes; int * Mdeb; int * NbTerm; +int * Nuvar; double * A; double * CoutLineaire; int Cnt; int i; double Ai; +int * Cdeb; int * Csui; int * NumContrainte; int DerniereCouleurDeLaMatrice; +char * SensContrainte; double * B; int Var; int NombreDArcs; int PremierCouleurDeLaMatrice; +int * TypeDeVariable; int * TypeDeBorne; int DerniereCouleurDesContraintes; +double * Xmin; double * Xmax; int PremiereCouleurDeContraintes; int Cn; +char * ContrainteInactive; int il; int ilMax; char Sens; double Bi; +int PremiereCouleurDesContraintes; int DerniereCouleurDesVariables; +int PremiereCouleurDesVariables; char * SensContrainteDeLaCouleur; +double * ValeurDeLaCouleur; int * VertexDeLaVariable; int * VertexDeLaContrainte; +int * VertexDuTerme; int C; int NombreDeCouleurs; int * CouleurDuNoeud; +PROBLEME_PNE * Pne; FILE * Flot; int NombreDeNoeuds; int NbTermesMatrice; + +printf("PRS_ConstruireLeGrapheAuFormatDIMACS\n"); + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +Flot = fopen( "Graphe_DIMACS_Du_Probleme", "w" ); +if( Flot == NULL ) { + printf("Erreur ouverture du fichier pour l'ecriture du jeu de donnees \n"); + exit(0); +} + +NombreDeVariables = Pne->NombreDeVariablesTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; +TypeDeBorne = Pne->TypeDeBorneTrav; +CoutLineaire = Pne->LTrav; +Xmin = Pne->UminTrav; +Xmax = Pne->UmaxTrav; +ContrainteInactive = Presolve->ContrainteInactive; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +B = Pne->BTrav; +SensContrainte = Pne->SensContrainteTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; + +NbTermesMatrice = 0; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteInactive[Cnt] == OUI_PNE ) continue; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( A[il] != 0.0 ) NbTermesMatrice++; + il++; + } +} + +NombreDeNoeuds = NombreDeVariables + NombreDeContraintes + NbTermesMatrice; + +VertexDeLaVariable = (int *) malloc( NombreDeVariables * sizeof( int ) ); +VertexDeLaContrainte = (int *) malloc( NombreDeContraintes * sizeof( int ) ); +VertexDuTerme = (int *) malloc( NbTermesMatrice * sizeof( int ) ); +CouleurDuNoeud = (int *) malloc( NombreDeNoeuds * sizeof( int ) ); + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) VertexDeLaVariable[Var] = -1; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) VertexDeLaContrainte[Cnt] = -1; +for ( il = 0 ; il < NbTermesMatrice ; il++ ) VertexDuTerme[il] = -1; + +for ( i = 0 ; i < NombreDeNoeuds ; i++ ) CouleurDuNoeud[i] = -1; + +NombreDeCouleurs = NombreDeNoeuds; + +SensContrainteDeLaCouleur = (char *) malloc( NombreDeCouleurs * sizeof( char ) ); +ValeurDeLaCouleur = (double *) malloc( NombreDeCouleurs * sizeof( double ) ); + +for ( C = 0 ; C < NombreDeCouleurs ; C++ ) { + ValeurDeLaCouleur[C] = -1; + SensContrainteDeLaCouleur[C] = '='; +} + +/* Toutes les variables entieres ont la meme couleur */ +NombreDeNoeuds = 0; +NombreDeCouleurs = 0; +PremiereCouleurDesVariables = NombreDeCouleurs; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeVariable[Var] != ENTIER ) continue; + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) continue; + VertexDeLaVariable[Var] = NombreDeNoeuds; + CouleurDuNoeud[NombreDeNoeuds] = NombreDeCouleurs; + NombreDeNoeuds++; +} +/* Les variables continues */ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + /* On pourrait regrouper les variables continues qui ont les memes bornes et le meme cout */ + if ( TypeDeVariable[Var] == ENTIER ) continue; + if ( TypeDeBorne[Var] == VARIABLE_FIXE ) continue; + VertexDeLaVariable[Var] = NombreDeNoeuds; + CouleurDuNoeud[NombreDeNoeuds] = NombreDeCouleurs; + NombreDeNoeuds++; + NombreDeCouleurs++; +} +DerniereCouleurDesVariables = NombreDeCouleurs - 1; +PremiereCouleurDesContraintes = NombreDeCouleurs; +/* Le second membre */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteInactive[Cnt] == OUI_PNE ) continue; + Bi = B[Cnt]; + Sens = SensContrainte[Cnt]; + Cn = -1; + for ( C = PremiereCouleurDeContraintes ; C < NombreDeCouleurs ; C++ ) { + if ( Bi == ValeurDeLaCouleur[C] ) { + if ( Sens == SensContrainteDeLaCouleur[C] ) { + Cn = C; + break; + } + } + } + if ( Cn == -1 ) { + /* Nouvelle couleur */ + Cn = NombreDeCouleurs; + ValeurDeLaCouleur[Cn] = Bi; + SensContrainteDeLaCouleur[Cn] = Sens; + NombreDeCouleurs++; + } + VertexDeLaContrainte[Cnt] = NombreDeNoeuds; + CouleurDuNoeud[NombreDeNoeuds] = Cn; + NombreDeNoeuds++; +} +DerniereCouleurDesContraintes = NombreDeCouleurs - 1; +PremierCouleurDeLaMatrice = NombreDeCouleurs; +NombreDArcs = 0; +/* Les lignes de la matrice */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteInactive[Cnt] == OUI_PNE ) continue; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Ai = A[il]; + if ( Ai != 0.0 && TypeDeBorne[Nuvar[il]] != VARIABLE_FIXE ) { + /* Recherche de la couleur */ + Cn = -1; + for ( C = PremierCouleurDeLaMatrice ; C < NombreDeCouleurs ; C++ ) { + if ( Ai == ValeurDeLaCouleur[C] ) { + Cn = C; + break; + } + } + if ( Cn == -1 ) { + /* Nouvelle couleur */ + Cn = NombreDeCouleurs; + ValeurDeLaCouleur[Cn] = Ai; + NombreDeCouleurs++; + } + VertexDuTerme[il] = NombreDeNoeuds; + /*printf("VertexDuTerme[il] %d\n",VertexDuTerme[il]);*/ + CouleurDuNoeud[NombreDeNoeuds] = Cn; + NombreDeNoeuds++; + /* Un arc entre la variable et ce noeud et un arc ent ce noeud et la contrainte */ + NombreDArcs += 2; + } + il++; + } +} +DerniereCouleurDeLaMatrice = NombreDeCouleurs - 1; + +/* Ecrire du titre */ +fprintf(Flot,"p edge %d %d\n",NombreDeNoeuds,NombreDArcs); + +for ( i = 0 ; i < NombreDeNoeuds ; i++ ) { + fprintf(Flot,"n %d %d\n",i+1,CouleurDuNoeud[i]+1); +} + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteInactive[Cnt] == OUI_PNE ) continue; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Ai = A[il]; + if ( Ai != 0.0 && TypeDeBorne[Nuvar[il]] != VARIABLE_FIXE ) { + fprintf(Flot,"e %d %d\n",VertexDeLaVariable[Nuvar[il]]+1,VertexDuTerme[il]+1); + fprintf(Flot,"e %d %d\n",VertexDuTerme[il]+1,VertexDeLaContrainte[Cnt]+1); + } + il++; + } +} + +fclose( Flot ); + +free( VertexDeLaVariable ); +free( VertexDeLaContrainte ); +free( VertexDuTerme ); +free( CouleurDuNoeud ); +free( SensContrainteDeLaCouleur ); +free( ValeurDeLaCouleur ); + +return; +} + +# endif diff --git a/src/ext/Sirius_Solver/presolve/prs_define.h b/src/ext/Sirius_Solver/presolve/prs_define.h new file mode 100644 index 0000000000..6cf0ed92cf --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_define.h @@ -0,0 +1,124 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef DEFINITIONS_PRESOLVE_FAITES +/*******************************************************************************************/ + +# define VERBOSE_PRS 0 + +# define PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # undef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + +# define DUMALGE_MENDELSON NON_PNE /*NON_PNE*/ + +# define SEUIL_POUR_AMELIORATION_DE_BORNE 1.e-6 /* 1.e-6 */ /* Doit etre superieur a MARGE_SUR_MODIF_DE_BORNE */ +# define MARGE_SUR_MODIF_DE_BORNE 0.e-7 /* 5 */ +# define MARGE_EGALITE_BORNE_MIN_ET_MAX 1.e-8 /* N'est fonctionnel que si on met plus grand que 2 * MARGE_SUR_MODIF_DE_BORNE */ +# define SEUIL_INF_POUR_FIXATION_BINAIRE 0.0001 +# define SEUIL_SUP_POUR_FIXATION_BINAIRE 0.9999 +# define MARGE_DINFAISABILITE 1.e-7 +# define ECART_NUL_LAMBDAMIN_LAMBDAMAX 1.e-8 + +# define VALEUR_DE_BORNE_DEBILE 1.e+12 /*12*/ +# define PIVOT_MIN_POUR_UN_CALCUL_DE_BORNE 1.e-6 /*1.e-5*/ + +# define ECART_NUL_LAMBDAMIN_LAMBDAMAX 1.e-8 /* si l'ecart en la variable duale min et max est inferieur on considere que c'est egal */ + +# define CBARRE_POSITIF 1 +# define CBARRE_NEGATIF 2 +# define CBARRE_NUL 3 +# define CBARRE_INDIFFERENT 4 + +# define LAMBDA_MIN_CONNU 1 +# define LAMBDA_MAX_CONNU 2 +# define LAMBDA_MIN_ET_MAX_CONNU 3 +# define LAMBDA_CONNU 4 +# define LAMBDA_NON_INITIALISE 5 + +# define VALEUR_NATIVE 1 +# define VALEUR_IMPLICITE 2 + +/* Les types de reduction (pour le postsolve) */ +/* Remarque: il manque la recuperation des variables duales dans le cas ou on fait des combinaisons lineaires + de contraintes pour creer du creux. On peut le faire en reconstruisant la matrice avant combinaisons + lineaires et en faisant une resolution du systeme ub = c */ +# define SUPPRESSION_VARIABLE_NON_BORNEE 1 /* Pour trouver la valeur de la variable et la valeur de la variable duale de la contrainte */ + +# define SUBSITUTION_DE_VARIABLE 2 /* Pour trouver la valeur de la variable et la valeur de la variable duale de la contrainte */ + +# define SUPPRESSION_COLONNE_COLINEAIRE 3 /* Pour trouver la valeur des 2 variables */ + +# define SUPPRESSION_LIGNE_SINGLETON 4 /* Pour trouver la variable duale de la contrainte */ + +# define SUPPRESSION_FORCING_CONSTRAINT 5 /* Pour trouver la valeur la variable duale de la contrainte */ + +# define SUPPRESSION_CONTRAINTE_COLINEAIRE 6 /* Pour trouver la variable duale de la contrainte */ + +# define VARIABLE_FIXEE 7 /* Inutilise pour l'instant */ + +/*******************************************************************************************************/ + +typedef struct { +/* Pour les outils de gestion memoire */ +void * Tas; + +double * MinContrainte; +double * MaxContrainte; +char * MinContrainteCalcule; +char * MaxContrainteCalcule; + +double * Lambda; +double * LambdaMin; +double * LambdaMax; +char * ConnaissanceDeLambda; /* LAMBDA_MIN_CONNU LAMBDA_MAX_CONNU LAMBDA_MIN_ET_MAX_CONNU LAMBDA_CONNU LAMBDA_NON_INITIALISE */ + +char * ContrainteInactive; + +int * ContrainteBornanteSuperieurement; +int * ContrainteBornanteInferieurement; +char * ConserverLaBorneSupDuPresolve; +char * ConserverLaBorneInfDuPresolve; + +/* Pour detecter les contraintes colineaires */ +int * ParColonnePremiereVariable; +int * ParColonneVariableSuivante; +int NbMaxTermesDesColonnes; + +/* Pour detecter les colonnes colineaires */ +int * ParLignePremiereContrainte; +int * ParLigneContrainteSuivante; +int NbMaxTermesDesLignes; +int * VariableEquivalente; /* Une variable est equivalente si elle en remplce 2 autres + dont les colonnes sont colineaires */ + +double * ValeurDeXPourPresolve; +double * BorneInfPourPresolve; +double * BorneSupPourPresolve; +int * TypeDeBornePourPresolve; +char * TypeDeValeurDeBorneInf; +char * TypeDeValeurDeBorneSup; + +/*char * VariableSubstituee;*/ + +void * ProblemePneDuPresolve; + +} PRESOLVE; + +/*******************************************************************************************/ +# define DEFINITIONS_PRESOLVE_FAITES +# endif + + diff --git a/src/ext/Sirius_Solver/presolve/prs_desactiver_contrainte.c b/src/ext/Sirius_Solver/presolve/prs_desactiver_contrainte.c new file mode 100644 index 0000000000..97f057f09a --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_desactiver_contrainte.c @@ -0,0 +1,81 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Mise a jour de l'indicateur d'activite d'une contrainte. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PRS_DesactiverContrainte( PRESOLVE * Presolve, int Cnt ) +{ +int il; int ilMax; int Var; int * Nuvar; int * Mdeb; int * NbTerm; PROBLEME_PNE * Pne; +char * ConserverLaBorneSupDuPresolve; char * ConserverLaBorneInfDuPresolve; +int * ContrainteBornanteSuperieurement; int * ContrainteBornanteInferieurement; +char * ContrainteInactive; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +ConserverLaBorneSupDuPresolve = Presolve->ConserverLaBorneSupDuPresolve; +ConserverLaBorneInfDuPresolve = Presolve->ConserverLaBorneInfDuPresolve; +ContrainteBornanteSuperieurement = Presolve->ContrainteBornanteSuperieurement; +ContrainteBornanteInferieurement = Presolve->ContrainteBornanteInferieurement; +ContrainteInactive = Presolve->ContrainteInactive; + +Nuvar = Pne->NuvarTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; + +il = Mdeb[Cnt]; +ilMax = il + NbTerm[Cnt]; +while ( il < ilMax ) { + Var = Nuvar[il]; + /* Si la contrainte etait bornante, on impose de conserver les bornes du presolve */ + /* Remarque: si la variable est a nouveau bornee par une contrainte activable, cet + indicateur repasse a NON_PNE */ + if ( ContrainteBornanteSuperieurement[Var] == Cnt ) { + ConserverLaBorneSupDuPresolve[Var] = OUI_PNE; + ContrainteBornanteSuperieurement[Var] = -1; + } + if ( ContrainteBornanteInferieurement[Var] == Cnt ) { + ConserverLaBorneInfDuPresolve[Var] = OUI_PNE; + ContrainteBornanteInferieurement[Var] = -1; + } + il++; +} +# if TRACES == 1 + printf("PRS_DesactiverContrainte: contrainte %d desactivee sens %c second membre %e\n",Cnt,Pne->SensContrainteTrav[Cnt],Pne->BTrav[Cnt]); +# endif +ContrainteInactive[Cnt] = OUI_PNE; +Pne->NumeroDesContraintesInactives[Pne->NombreDeContraintesInactives] = Pne->CorrespondanceCntPneCntEntree[Cnt]; +Pne->NombreDeContraintesInactives++; + +return; +} diff --git a/src/ext/Sirius_Solver/presolve/prs_determiner_le_type_de_borne_pour_dual.c b/src/ext/Sirius_Solver/presolve/prs_determiner_le_type_de_borne_pour_dual.c new file mode 100644 index 0000000000..1ff51eb7ec --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_determiner_le_type_de_borne_pour_dual.c @@ -0,0 +1,178 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On determine le type de borne le plus contraignant pour + le cout reduit de la variable. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define MARGE 1.e-5 + +/*----------------------------------------------------------------------------*/ + +char PRS_AjusterLeTypeDeBorne( char TypeBrnNative, char TypeBrnPresolve, + double BorneInfPresolve, double BorneInfNative, + double BorneSupPresolve, double BorneSupNative, + char ConserverLaBorneInfDuPresolve, char ConserverLaBorneSupDuPresolve, + char BorneInfPresolveDisponible, char BorneSupPresolveDisponible, + char TypeDeValeurDeBorneInf, char TypeDeValeurDeBorneSup ) +{ +char TypeBrn; + +TypeBrn = TypeBrnPresolve; +if ( TypeBrn == VARIABLE_FIXE || TypeBrn == VARIABLE_NON_BORNEE ) return( TypeBrn ); + +if ( BorneInfPresolveDisponible == OUI_PNE && BorneSupPresolveDisponible == NON_PNE ) { + TypeBrn = VARIABLE_BORNEE_INFERIEUREMENT; + if ( ConserverLaBorneInfDuPresolve == NON_PNE ) { + if ( TypeBrnNative == VARIABLE_NON_BORNEE || TypeBrnNative == VARIABLE_BORNEE_SUPERIEUREMENT ) TypeBrn = VARIABLE_NON_BORNEE; + else if ( TypeBrnNative == VARIABLE_BORNEE_INFERIEUREMENT ) { + /* Des que la valeur devient implicite c'est qu'il existe une contrainte qui borne la variable */ + if ( TypeDeValeurDeBorneInf == VALEUR_IMPLICITE ) TypeBrn = VARIABLE_NON_BORNEE; + } + } + return( TypeBrn ); +} + +if ( BorneInfPresolveDisponible == NON_PNE && BorneSupPresolveDisponible == OUI_PNE ) { + TypeBrn = VARIABLE_BORNEE_SUPERIEUREMENT; + if ( ConserverLaBorneSupDuPresolve == NON_PNE ) { + if ( TypeBrnNative == VARIABLE_NON_BORNEE || TypeBrnNative == VARIABLE_BORNEE_INFERIEUREMENT ) TypeBrn = VARIABLE_NON_BORNEE; + else if ( TypeBrnNative == VARIABLE_BORNEE_SUPERIEUREMENT ) { + /* Des que la valeur devient implicite c'est qu'il existe une contrainte qui borne la variable */ + if ( TypeDeValeurDeBorneSup == VALEUR_IMPLICITE ) TypeBrn = VARIABLE_NON_BORNEE; + } + } + return( TypeBrn ); +} + +if ( BorneInfPresolveDisponible == NON_PNE && BorneSupPresolveDisponible == NON_PNE ) { + TypeBrn = VARIABLE_NON_BORNEE; + return( TypeBrn ); +} + +if ( BorneInfPresolveDisponible == OUI_PNE && BorneSupPresolveDisponible == OUI_PNE ) { + TypeBrn = VARIABLE_BORNEE_DES_DEUX_COTES; + + if ( ConserverLaBorneInfDuPresolve == NON_PNE ) { + if ( ConserverLaBorneSupDuPresolve == NON_PNE ) { + if ( TypeBrnNative == VARIABLE_NON_BORNEE ) TypeBrn = VARIABLE_NON_BORNEE; + else if ( TypeBrnNative == VARIABLE_BORNEE_INFERIEUREMENT ) { + TypeBrn = VARIABLE_BORNEE_INFERIEUREMENT; + if ( TypeDeValeurDeBorneInf == VALEUR_IMPLICITE ) TypeBrn = VARIABLE_NON_BORNEE; + } + else if ( TypeBrnNative == VARIABLE_BORNEE_SUPERIEUREMENT ) { + TypeBrn = VARIABLE_BORNEE_SUPERIEUREMENT; + if ( TypeDeValeurDeBorneSup == VALEUR_IMPLICITE ) TypeBrn = VARIABLE_NON_BORNEE; + } + else { + /* TypeBrnNative est VARIABLE_BORNEE_DES_DEUX_COTES */ + /* Des que la valeur devient implicite c'est qu'il existe une contrainte qui borne la variable */ + if ( TypeDeValeurDeBorneInf == VALEUR_IMPLICITE && TypeDeValeurDeBorneSup == VALEUR_IMPLICITE ) TypeBrn = VARIABLE_NON_BORNEE; + else if ( TypeDeValeurDeBorneInf == VALEUR_IMPLICITE ) TypeBrn = VARIABLE_BORNEE_SUPERIEUREMENT; + else if ( TypeDeValeurDeBorneSup == VALEUR_IMPLICITE ) TypeBrn = VARIABLE_BORNEE_INFERIEUREMENT; + } + } + else { + /* On doit conserver la borne sup du presolve */ + if ( TypeBrnNative == VARIABLE_NON_BORNEE ) TypeBrn = VARIABLE_BORNEE_SUPERIEUREMENT; + else if ( TypeBrnNative == VARIABLE_BORNEE_SUPERIEUREMENT ) TypeBrn = VARIABLE_BORNEE_SUPERIEUREMENT; + else if ( TypeBrnNative == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( TypeDeValeurDeBorneInf == VALEUR_IMPLICITE ) TypeBrn = VARIABLE_BORNEE_SUPERIEUREMENT; + } + else { + /* TypeBrnNative est VARIABLE_BORNEE_DES_DEUX_COTES */ + if ( TypeDeValeurDeBorneInf == VALEUR_IMPLICITE ) TypeBrn = VARIABLE_BORNEE_SUPERIEUREMENT; + } + } + } + else { + /* On doit conserver la borne inf du presolve */ + if ( ConserverLaBorneSupDuPresolve == NON_PNE ) { + if ( TypeBrnNative == VARIABLE_NON_BORNEE ) TypeBrn = VARIABLE_BORNEE_INFERIEUREMENT; + else if ( TypeBrnNative == VARIABLE_BORNEE_INFERIEUREMENT ) TypeBrn = VARIABLE_BORNEE_INFERIEUREMENT; + else if ( TypeBrnNative == VARIABLE_BORNEE_SUPERIEUREMENT ) { + if ( TypeDeValeurDeBorneSup == VALEUR_IMPLICITE ) TypeBrn = VARIABLE_BORNEE_INFERIEUREMENT; + } + else { + /* TypeBrnNative est VARIABLE_BORNEE_DES_DEUX_COTES */ + if ( TypeDeValeurDeBorneSup == VALEUR_IMPLICITE ) TypeBrn = VARIABLE_BORNEE_INFERIEUREMENT; + } + } + } + return( TypeBrn ); +} + +return( TypeBrn ); +} + +/*----------------------------------------------------------------------------*/ + +char PRS_ChoisirLaBorneLaPlusContraignantePourLesVariablesDuales( + int TypeDeBorneNative, int TypeDeBornePourPresolve, + double BorneInfPourPresolve, double BorneInfNative, + double BorneSupPourPresolve, double BorneSupNative, + char ConserverLaBorneInfDuPresolve, char ConserverLaBorneSupDuPresolve, + char TypeDeValeurDeBorneInf, char TypeDeValeurDeBorneSup ) +{ +char BorneInfPresolveDisponible; double BorneInfPresolve; char BorneSupPresolveDisponible; +double BorneSupPresolve; char TypeBrn; + +if ( TypeDeBornePourPresolve == VARIABLE_FIXE || TypeDeBornePourPresolve == VARIABLE_NON_BORNEE ) { + return( TypeDeBornePourPresolve ); +} + +BorneInfPresolveDisponible = NON_PNE; +BorneInfPresolve = -LINFINI_PNE; +BorneSupPresolveDisponible = NON_PNE; +BorneSupPresolve = LINFINI_PNE; +if ( TypeDeBornePourPresolve == VARIABLE_BORNEE_INFERIEUREMENT ) { + BorneInfPresolveDisponible = OUI_PNE; + BorneInfPresolve = BorneInfPourPresolve; +} +else if ( TypeDeBornePourPresolve == VARIABLE_BORNEE_SUPERIEUREMENT ) { + BorneSupPresolveDisponible = OUI_PNE; + BorneSupPresolve = BorneSupPourPresolve; +} +else if ( TypeDeBornePourPresolve == VARIABLE_BORNEE_DES_DEUX_COTES ) { + BorneInfPresolveDisponible = OUI_PNE; + BorneInfPresolve = BorneInfPourPresolve; + BorneSupPresolveDisponible = OUI_PNE; + BorneSupPresolve = BorneSupPourPresolve; +} + +TypeBrn = PRS_AjusterLeTypeDeBorne( TypeDeBorneNative, TypeDeBornePourPresolve, BorneInfPresolve, BorneInfNative, + BorneSupPresolve, BorneSupNative, + ConserverLaBorneInfDuPresolve, ConserverLaBorneSupDuPresolve, + BorneInfPresolveDisponible, BorneSupPresolveDisponible, + TypeDeValeurDeBorneInf, TypeDeValeurDeBorneSup ); + +return( TypeBrn ); +} + +/*----------------------------------------------------------------------------*/ diff --git a/src/ext/Sirius_Solver/presolve/prs_enlever_contraintes_inactives.c b/src/ext/Sirius_Solver/presolve/prs_enlever_contraintes_inactives.c new file mode 100644 index 0000000000..bde892e91a --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_enlever_contraintes_inactives.c @@ -0,0 +1,126 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On enleve les contraintes inactives + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PRS_EnleverLesContraintesInactives( PRESOLVE * Presolve ) +{ +int Cnt0; int Cnt0Max; int il; +int * Mdeb0; int * NbTerm0; double * B0; char * SensContrainte0; int * Nuvar0; +double * A0; int il0; int il0Max; int NombreDeTermesNonNuls; +PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +if ( Presolve == NULL ) return; + +Cnt0Max = Pne->NombreDeContraintesTrav ; + +Mdeb0 = (int *) malloc( Cnt0Max * sizeof( int ) ); +NbTerm0 = (int *) malloc( Cnt0Max * sizeof( int ) ); +B0 = (double *) malloc( Cnt0Max * sizeof( double ) ); +SensContrainte0 = (char *) malloc( Cnt0Max * sizeof( char ) ); + +Nuvar0 = (int *) malloc( Pne->TailleAlloueePourLaMatriceDesContraintes * sizeof( int ) ); +A0 = (double *) malloc( Pne->TailleAlloueePourLaMatriceDesContraintes * sizeof( double ) ); + +if ( Mdeb0 == NULL || NbTerm0 == NULL || B0 == NULL || SensContrainte0 == NULL || + Nuvar0 == NULL || A0 == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PRS_EnleverLesContraintesInactives \n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} + +/* Recopie des contraintes dans une zone de sauvegarde */ +memcpy( (char *) Nuvar0 , (char *) Pne->NuvarTrav , Pne->TailleAlloueePourLaMatriceDesContraintes * sizeof( int ) ); +memcpy( (char *) A0 , (char *) Pne->ATrav , Pne->TailleAlloueePourLaMatriceDesContraintes * sizeof( double ) ); + +for ( Cnt0 = 0 ; Cnt0 < Cnt0Max ; Cnt0++ ) { + Mdeb0 [Cnt0] = Pne->MdebTrav [Cnt0]; + NbTerm0 [Cnt0] = Pne->NbTermTrav [Cnt0]; + B0 [Cnt0] = Pne->BTrav [Cnt0]; + SensContrainte0[Cnt0] = Pne->SensContrainteTrav[Cnt0]; +} + +/* Recopie des contraintes actives */ + +Pne->NombreDeContraintesTrav = 0; +NombreDeTermesNonNuls = 0; +for ( il = 0 , Cnt0 = 0 ; Cnt0 < Cnt0Max ; Cnt0++ ) { + if ( Presolve->ContrainteInactive[Cnt0] == OUI_PNE ) { + continue; + } + + Pne->MdebTrav [Pne->NombreDeContraintesTrav] = il; + Pne->NbTermTrav [Pne->NombreDeContraintesTrav] = 0 /*NbTerm0[Cnt0]*/; + Pne->BTrav [Pne->NombreDeContraintesTrav] = B0[Cnt0]; + Pne->SensContrainteTrav[Pne->NombreDeContraintesTrav] = SensContrainte0[Cnt0]; + + /* On peut se permettre de faire cela car Cnt0 est toujours superieur ou egal a Pne->NombreDeContraintesTrav */ + Pne->CorrespondanceCntPneCntEntree[Pne->NombreDeContraintesTrav] = Pne->CorrespondanceCntPneCntEntree[Cnt0]; + + il0 = Mdeb0[Cnt0]; + il0Max = il0 + NbTerm0[Cnt0]; + while ( il0 < il0Max) { + if ( A0[il0] != 0.0 ) { + Pne->ATrav [il] = A0[il0]; + Pne->NuvarTrav[il] = Nuvar0[il0]; + Pne->NbTermTrav[Pne->NombreDeContraintesTrav]++; + il++; + NombreDeTermesNonNuls++; + } + il0++; + } + + for ( il0 = 0 ; il0 < MARGE_EN_FIN_DE_CONTRAINTE ; il0++ ) { + Pne->ATrav[il] = 0.0; + il++; + } + + Pne->NombreDeContraintesTrav++; + +} + +Pne->ChainageTransposeeExploitable = NON_PNE; + +free( Mdeb0 ); +free( NbTerm0 ); +free( B0 ); +free( SensContrainte0 ); +free( Nuvar0 ); +free( A0 ); + +return; +} diff --git a/src/ext/Sirius_Solver/presolve/prs_fixer_une_variable_a_une_valeur.c b/src/ext/Sirius_Solver/presolve/prs_fixer_une_variable_a_une_valeur.c new file mode 100644 index 0000000000..aecf1a2e6e --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_fixer_une_variable_a_une_valeur.c @@ -0,0 +1,54 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Init des indicateurs de fixation d'une variable. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void PRS_FixerUneVariableAUneValeur( PRESOLVE * Presolve, int Var, double X ) +{ +PROBLEME_PNE * Pne; +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; +Pne->TypeDeVariableTrav[Var] = REEL; +Presolve->ValeurDeXPourPresolve[Var] = X; +/* Car on se sert de ces bornes dans le postsolve +Presolve->BorneInfPourPresolve[Var] = X; +Presolve->BorneSupPourPresolve[Var] = X; +*/ +Presolve->TypeDeBornePourPresolve[Var] = VARIABLE_FIXE; +Presolve->TypeDeValeurDeBorneInf[Var] = VALEUR_IMPLICITE; +Presolve->TypeDeValeurDeBorneSup[Var] = VALEUR_IMPLICITE; +return; +} + +/*----------------------------------------------------------------------------*/ diff --git a/src/ext/Sirius_Solver/presolve/prs_fixer_variables_sur_critere.c b/src/ext/Sirius_Solver/presolve/prs_fixer_variables_sur_critere.c new file mode 100644 index 0000000000..d96ead43aa --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_fixer_variables_sur_critere.c @@ -0,0 +1,293 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: A ce stade on a soit des contraintes = , soit des contraintes + de type < . + Si une variable n'intervient que dans des contraintes de + type < avec un coefficient de meme signe et que le signe + du cout de la variable est egalement le meme ou bien si + le cout est nul alors on peut fixer la variable sur une + de ses bornes. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PRS_FixerVariablesSurCritere( PRESOLVE * Presolve, int * VariableFixee ) +{ +int Var; int Cnt; int SuppressionPossible; char Signe; int il; int TypeBrn; +char DernierSigneTrouve; int Nbs; char ContraintesSupprimee ; double Ai; +char SupprimerLesContraintes; int ilCnt; int ilMaxCnt; int VarCnt; +char SupprimerLaVariable; double * BorneInfPourPresolve; double * BorneSupPourPresolve; +int * TypeDeBornePourPresolve; int NombreDeVariables; double * CoutLineaire; +int * Cdeb; int * Csui; int * NumContrainte; double * A; char * ContrainteInactive; +char * SensContrainte; double * ValeurDeXPourPresolve; int * Mdeb; int * NbTerm; int * Nuvar; +int * ContrainteBornanteSuperieurement; int * ContrainteBornanteInferieurement; +PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +ContraintesSupprimee = NON_PNE; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +CoutLineaire = Pne->LTrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; +SensContrainte = Pne->SensContrainteTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ContrainteInactive = Presolve->ContrainteInactive; +ContrainteBornanteSuperieurement = Presolve->ContrainteBornanteSuperieurement; +ContrainteBornanteInferieurement = Presolve->ContrainteBornanteInferieurement; + +Nbs = 0; + +*VariableFixee = NON_PNE; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + + TypeBrn = TypeDeBornePourPresolve[Var]; + if ( TypeBrn == VARIABLE_FIXE ) continue; + + if ( CoutLineaire[Var] > 0.0 ) Signe = '+'; + else if ( CoutLineaire[Var] < 0.0 ) Signe = '-'; + else Signe = '|'; + + SuppressionPossible = OUI_PNE; + DernierSigneTrouve = '|'; + + il = Cdeb[Var]; + while ( il >= 0 ) { + Ai = A[il]; + if ( Ai == 0.0 ) goto ContrainteSuivante; + Cnt = NumContrainte[il]; + + if ( ContrainteInactive[Cnt] == OUI_PNE ) goto ContrainteSuivante; + if ( SensContrainte[Cnt] == '=' ) { + SuppressionPossible = NON_PNE; + break; + } + if ( Signe == '+' ) { + if ( Ai < 0.0 ) { + SuppressionPossible = NON_PNE; + break; + } + } + else if ( Signe == '-' ) { + if ( Ai > 0.0 ) { + SuppressionPossible = NON_PNE; + break; + } + } + else { /* Alors Signe = '|' ) */ + if ( Ai > 0.0 ) { + if ( DernierSigneTrouve == '-' ) { + SuppressionPossible = NON_PNE; + break; + } + else DernierSigneTrouve = '+'; + } + else if ( Ai < 0.0 ) { + if ( DernierSigneTrouve == '+' ) { + SuppressionPossible = NON_PNE; + break; + } + else DernierSigneTrouve = '-'; + } + } + ContrainteSuivante: + il = Csui[il]; + } + + SupprimerLaVariable = NON_PNE; + + if ( SuppressionPossible == OUI_PNE ) { + if ( Signe == '+' ) { + + if ( TypeBrn == VARIABLE_NON_BORNEE || TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + # if TRACES == 1 + if ( TypeBrn == VARIABLE_NON_BORNEE ) { + printf("*** Phase de Presolve-> La variable %d est NON BORNEE or a l'optimum elle doit etre placee\n",Var); + printf("sur sa borne inf. L'optimum est donc non borne.\n"); + } + else { + printf("*** Phase de Presolve-> La variable %d est INFERIEUREMENT NON BORNEE or a l'optimum elle doit etre placee\n",Var); + printf("sur sa borne inf. L'optimum est donc non borne.\n"); + } + # endif + *VariableFixee = NON_PNE; + Pne->YaUneSolution = PROBLEME_NON_BORNE; + return; + } + + # if TRACES == 1 + printf("-> Analyse des couts, variable %d cout %e fixee a sa borne inf: %e \n",Var,Pne->LTrav[Var],BorneInfPourPresolve[Var]); + # endif + + SupprimerLaVariable = OUI_PNE; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneInfPourPresolve[Var] ); + + } + else if ( Signe == '-' ) { + + if ( TypeBrn == VARIABLE_NON_BORNEE || TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + # if TRACES == 1 + if ( TypeBrn == VARIABLE_NON_BORNEE ) { + printf("*** Phase de Presolve-> La variable %d est NON BORNEE or a l'optimum elle doit etre placee\n",Var); + printf("sur sa borne sup. L'optimum est donc non borne.\n"); + } + else { + printf("*** Phase de Presolve-> La variable %d est SUPERIEUREMENT NON BORNEE or a l'optimum elle doit etre placee\n",Var); + printf("sur sa borne sup. L'optimum est donc non borne.\n"); + } + # endif + *VariableFixee = NON_PNE; + Pne->YaUneSolution = PROBLEME_NON_BORNE; + return; + } + + # if TRACES == 1 + printf("-> Analyse des couts, variable %d cout %e fixee a sa borne sup: %lf \n",Var,Pne->LTrav[Var],BorneSupPourPresolve[Var]); + # endif + + SupprimerLaVariable = OUI_PNE; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneSupPourPresolve[Var] ); + + } + else { /* Alors Signe = '|' ) */ + SupprimerLesContraintes = NON_PNE; + if ( DernierSigneTrouve == '+' ) { + /* La variable n'intervient que dans des contraintes d'inegalite, avec un coefficient positif et + de plus elle n'a pas de cout => on la fixe a Xmin */ + + /* Si la variable est non bornee inferieurement toutes les contraintes dans lesquelles elle intervient + seront toujours satisfaites => on peut les supprimer. ATTENTION ensuite il faut recalculer la + valeur de la variable en sortie */ + if ( TypeBrn == VARIABLE_NON_BORNEE || TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + SupprimerLesContraintes = OUI_PNE; + /*printf("PRS_FixerVariablesSurCritere: suppression possible des contraintes de la variable %d\n",Var);*/ + } + + if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + # if TRACES == 1 + printf("-> Analyse des couts, variable %d sans cout, fixee a sa borne inf: %lf\n",Var, BorneInfPourPresolve[Var]); + # endif + SupprimerLaVariable = OUI_PNE; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneInfPourPresolve[Var] ); + } + + } + else if ( DernierSigneTrouve == '-' ) { + /* La variable n'intervient que dans des contraintes d'inegalite, avec un coefficient negatif et + de plus elle n'a pas de cout => on la fixe a Xmax */ + /* Si la variable est non bornee inferieurement toutes les contraintes dans lesquelles elle intervient + seront toutjours satisfaites => on peut les supprimer. ATTENTION ensuite il faut recalculer la + valeur de la variable en sortie */ + if ( TypeBrn == VARIABLE_NON_BORNEE || TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + SupprimerLesContraintes = OUI_PNE; + /*printf("PRS_FixerVariablesSurCritere: suppression possible des contraintes de la variable %d\n",Var);*/ + } + + if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + + # if TRACES == 1 + printf("-> Analyse des couts, variable %d sans cout, fixee a sa borne sup: %lf\n",Var,BorneSupPourPresolve[Var]); + # endif + SupprimerLaVariable = OUI_PNE; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneSupPourPresolve[Var] ); + } + + } + else { + /* DernierSigneTrouve = '|' : la variable n'intervient pas dans les contraintes et son cout est nul */ + /* On n'intervient pas: il y a la routine qui enleve les variables sans contrainte */ + } + /* Temporaire: comme je n'ai pas fait le necessaire pour pouvoir recalculer la variable en sortie + si elle supprime la contrainte, je ne fais rien. Mais je pense finalement qu'en sortie les valeurs extremes + conviennent quand meme et qu'il n'y a pas besoin de recalculer */ + if ( SupprimerLesContraintes == OUI_PNE ) { + SupprimerLaVariable = NON_PNE; + SupprimerLesContraintes = NON_PNE; + } + /* Fin temporaire */ + + if ( SupprimerLesContraintes == OUI_PNE ) { + il = Cdeb[Var]; + while ( il >= 0 ) { + ContraintesSupprimee = OUI_PNE; + Cnt = NumContrainte[il]; + ContrainteInactive[Cnt] = OUI_PNE; /* Attention elle peut etre bornante: non car la variable est au moins non bornee d'un cote */ + /* Comme la contrainte peut etre bornante, on interdit de liberer les variables qu'elle borne */ + ilCnt = Mdeb[Cnt]; + ilMaxCnt = ilCnt + NbTerm[Cnt]; + while ( ilCnt < ilMaxCnt ) { + VarCnt = Nuvar[ilCnt]; + /* Comme on est dans le cas ou le cout de la variable supprimee est nul, il est inutile de modifier + les couts des variables de la contrainte */ + ilCnt++; + } + /* */ + il = Pne->CsuiTrav[il]; + } + Pne->VariableElimineeSansValeur[Pne->NombreDeVariablesElimineesSansValeur] = Var; + Pne->NombreDeVariablesElimineesSansValeur++; + } + } + + if ( SupprimerLaVariable == OUI_PNE ) { + Nbs++; + *VariableFixee = OUI_PNE; + + # if TRACES == 1 + if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) printf(" Fixation d'une variable entiere, var num %d val %e \n",Var,ValeurDeXPourPresolve[Var]); + # endif + + } + + } + +} + +#if VERBOSE_PRS + printf("-> Nombre de variables fixees sur critere: %d\n",Nbs); +#endif + +return; +} + + diff --git a/src/ext/Sirius_Solver/presolve/prs_fonctions.h b/src/ext/Sirius_Solver/presolve/prs_fonctions.h new file mode 100644 index 0000000000..0de2757be9 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_fonctions.h @@ -0,0 +1,173 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +# include "prs_define.h" + +void PRS_AllocationsStructure( PRESOLVE * ); + +void PRS_AllocTablesDeSubstitution( void * ); /* En realite c'est un type PROBLEME_PNE mais il n'est pas connu dans ce fichier */ + +void PRS_LiberationStructure( PRESOLVE * ); + +void PRS_AmeliorerLesBornes( PRESOLVE * , int * ); + +void PRS_AmeliorerBorneSurVariable( PRESOLVE * , int , int * ); + +void PRS_MettreAJourLesBornesDUneVariable( PRESOLVE * , int , char , double , int , char , double , int , char * ); + +void PRS_VariablesDeBornesIdentiques( PRESOLVE * , int , double , double , char * ); + +void PRS_VariablesDualesEtCoutsReduits( PRESOLVE * , int * ); + +void PRS_MajVariableDuale( PRESOLVE * , int , double , double , char , int * ); + +void PRS_AmeliorerOuCalculerCoutsReduits( PRESOLVE * , int , int * ); + +void PRS_AmeliorerBornesDesVariablesDuales( PRESOLVE * , int , char , double , char ,double , char , int * ); + +void PRS_BornerLesVariablesDualesNonBornees( PRESOLVE * , int * ); + +void PRS_CalculeBorneSurVariableDualeEnFonctionDeLaVariable( PRESOLVE * , int , int , char , char * , double * , char * , double * ); + +void PRS_MettreAJourLesBornesDUneVariableDuale( PRESOLVE * , int , char , double , char , double , char * ); + +void PRS_VariablesDualesDeBornesIdentiques( PRESOLVE * , int , double , double , char * ); + +void PRS_CalculerLesBornesDeToutesLesContraintes( PRESOLVE * , int * ); + +void PRS_AmeliorerLesCoefficientsDesVariablesBinaires( PRESOLVE * ); + +void PRS_AmeliorerCoeffDesContraintesDeBornesVariables( PRESOLVE * , int * ); + +void PRS_CalculerLesBornesDuneContrainte( PRESOLVE * , int , char , int * , int * ); + +void PRS_CalculeBorneSurVariableEnFonctionDeLaContrainte( PRESOLVE * , int , int , char * , double * , char * , double * ); + +void PRS_ContraintesToujoursInactives( PRESOLVE * , int * ); + +void PRS_SubstituerVariableDansCntDInegalite( PRESOLVE * , int , int , char , double , int , int * , + double * , char * , double , char * , double * , int * ); + +void PRS_TesterLaDominanceDesContraintes( PRESOLVE * , char * , char * ); + +void PRS_TesterLaRedondanceDUneContrainte( PRESOLVE * , char * , double , double , int , int, + char * , double * , double * ,double * ); + +void PRS_EnleverLesContraintesInactives( PRESOLVE * ); + +void PRS_FixerVariablesSurCritere( PRESOLVE * , int * ); + +void PRS_Presolve( void * ); + +void PRS_SingletonsSurLignes( PRESOLVE * , int * ); + +void PRS_SingletonsSurColonnes( PRESOLVE * , int * ); + +char PRS_ChoisirLaBorneLaPlusContraignantePourLesVariablesDuales( int , int , double , double , double , double , char , + char , char , char ); + +char PRS_AjusterLeTypeDeBorne( char , char , double , double , double , double , char , char , char , char , char , char ); + +void PRS_DesactiverContrainte( PRESOLVE * , int ); + +void PRS_SubstituerVariables( PRESOLVE * , int * ); + +char PRS_TestSubstituerUneVariable( PRESOLVE * , int ,int , double , double , int ); + +void PRS_SubstituerUneVariable( PRESOLVE * , int ,int , double , double ); + +void PRS_ClasserVariablesDansContraintes( PRESOLVE * ); + +void PRS_SupprimerLesContraintesAvecQueDesVariablesFixees( PRESOLVE * ); + +void PRS_BornerLesVariablesNonBornees( PRESOLVE * , int * ); + +void PRS_TenterUnCalculDeBorne( PRESOLVE * , int , int , int * ); + +void PRS_VariablesHorsContraintes( PRESOLVE * , int * ); + +void PRS_CombinaisonDeContraintes( PRESOLVE * , int * ); + +void PRS_ContraintesColineaires( PRESOLVE * , int * ); + +void PRS_ColonnesColineaires( PRESOLVE * , int * ); + +void PRS_ConstruireLeGrapheAuFormatDIMACS( PRESOLVE * ); + +void PRS_SubstituerLesVariablesNonBornees( PRESOLVE * ); + +void PRS_FixerUneVariableAUneValeur( PRESOLVE * , int , double ); + +/* Pour le test BTF */ +void PRS_BTF( PRESOLVE * ); +void PRS_DumalgeMendelson( PRESOLVE * ); +void PRS_DumalgeMendelsonPourLaMatriceDesContraintes( PRESOLVE * ); +void * PRS_DumalgeFactoriserMatrice( PRESOLVE * , void ** , int , int , int , int , int , int , + void * , void * , int * , int * , char * , char , char ); + + +void PRS_DumalgeResoudrePrimal( PRESOLVE * , + void * , + void * , + int , + int , + int , + int , + int , + int , + void * , + void * , + int * , + int * , + double * , + char * , + char + ); + +void * PRS_DumalgeMendelsonResoudreSystemeTranspose( PRESOLVE * , + int , int , int , int , int , int , void * , void * , int * , + int * , int * , int * , double * , char * , char , char ); + +void PRS_DumalgeResoudreDual( PRESOLVE * , void * , void * , int , int , int , int , int , + int , void * , void *, int * , int * , double * , char * ); + + +/* Fin Test */ + +/* */ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/presolve/prs_maj_variable_duale.c b/src/ext/Sirius_Solver/presolve/prs_maj_variable_duale.c new file mode 100644 index 0000000000..7b631034c8 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_maj_variable_duale.c @@ -0,0 +1,132 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Mise a jour des bornes d'une variable duale. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" + +# include "pne_define.h" + +# include "prs_define.h" + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PRS_MajVariableDuale( PRESOLVE * Presolve, int Cnt, double CBarre, + double Coeff, char SensInegaliteDuCoutReduit, + int * NbModifications ) +{ +double Lbd; + +if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_CONNU ) return; + +Lbd = CBarre / Coeff; +if ( SensInegaliteDuCoutReduit == '=' ) { + Presolve->Lambda[Cnt] = Lbd; + Presolve->LambdaMin[Cnt] = Lbd; + Presolve->LambdaMax[Cnt] = Lbd; + Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_CONNU; + *NbModifications = *NbModifications + 1; +} +else if ( SensInegaliteDuCoutReduit == '<' ) { + if ( Coeff > 0.0 ) { + if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU || Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( Lbd > Presolve->LambdaMin[Cnt] ) { + Presolve->LambdaMin[Cnt] = Lbd; + *NbModifications = *NbModifications + 1; + } + } + else { + Presolve->LambdaMin[Cnt] = Lbd; + *NbModifications = *NbModifications + 1; + if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU ) Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_ET_MAX_CONNU; + else Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_CONNU; + } + } + else { + if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU || Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( Lbd < Presolve->LambdaMax[Cnt] ) { + Presolve->LambdaMax[Cnt] = Lbd; + *NbModifications = *NbModifications + 1; + } + } + else { + Presolve->LambdaMax[Cnt] = Lbd; + *NbModifications = *NbModifications + 1; + if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU ) Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_ET_MAX_CONNU; + else Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_MAX_CONNU; + } + } +} +else if ( SensInegaliteDuCoutReduit == '>' ) { + if ( Coeff > 0.0 ) { + if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU || Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( Lbd < Presolve->LambdaMax[Cnt] ) { + Presolve->LambdaMax[Cnt] = Lbd; + *NbModifications = *NbModifications + 1; + } + } + else { + Presolve->LambdaMax[Cnt] = Lbd; + *NbModifications = *NbModifications + 1; + if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU ) Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_ET_MAX_CONNU; + else Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_MAX_CONNU; + } + } + else { + if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU || Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( Lbd > Presolve->LambdaMin[Cnt] ) { + Presolve->LambdaMin[Cnt] = Lbd; + *NbModifications = *NbModifications + 1; + } + } + else { + Presolve->LambdaMin[Cnt] = Lbd; + *NbModifications = *NbModifications + 1; + if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU ) Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_ET_MAX_CONNU; + else Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_CONNU; + } + } +} + +if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( fabs( Presolve->LambdaMin[Cnt] - Presolve->LambdaMax[Cnt] ) < ECART_NUL_LAMBDAMIN_LAMBDAMAX ) { + # if TRACES == 1 + printf("Cnt %d LambdaMin = LambdaMax = %e\n",Cnt,Presolve->LambdaMin[Cnt]); + # endif + Presolve->Lambda[Cnt] = 0.5 * ( Presolve->LambdaMin[Cnt] + Presolve->LambdaMax[Cnt] ); + Presolve->LambdaMin[Cnt] = Presolve->Lambda[Cnt]; + Presolve->LambdaMax[Cnt] = Presolve->Lambda[Cnt]; + Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_CONNU; + *NbModifications = *NbModifications + 1; + } +} + +return; +} + + + + diff --git a/src/ext/Sirius_Solver/presolve/prs_memoire.h b/src/ext/Sirius_Solver/presolve/prs_memoire.h new file mode 100644 index 0000000000..b62c125ef5 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_memoire.h @@ -0,0 +1,34 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef PRS_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# include "mem_fonctions.h" +/***************************************************************** + + + Macros pour redefinir les primitives de gestion memoire lorsqu'on + ne veut pas utiliser celles de lib de l'OS + + +*****************************************************************/ + +# define malloc(Taille) MEM_Malloc(Presolve->Tas,Taille) +# define free(Pointeur) MEM_Free(Pointeur) +# define realloc(Pointeur,Taille) MEM_Realloc(Presolve->Tas,Pointeur,Taille) + +/*****************************************************************/ +# define PRS_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# endif diff --git a/src/ext/Sirius_Solver/presolve/prs_mettre_a_jour_bornes_des_variables.c b/src/ext/Sirius_Solver/presolve/prs_mettre_a_jour_bornes_des_variables.c new file mode 100644 index 0000000000..ccaf3a49d2 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_mettre_a_jour_bornes_des_variables.c @@ -0,0 +1,199 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Mise a jour des bornes d'une variable a chaque fois qu'on + calcule une nouvelle borne. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES_BORNES_IDENTIQUES 0 +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ +/* Il se peut qu'en ameliorant les bornes, la variable en soit fixee */ +void PRS_VariablesDeBornesIdentiques( PRESOLVE * Presolve, int Var, + double BorneInf, double BorneSup, + char * BorneAmelioree ) +{ +PROBLEME_PNE * Pne; +*BorneAmelioree = NON_PNE; +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) return; +if ( Presolve->TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) return; +/* Il se peut qu'en ameliorant les bornes, la variable en soit fixee */ +if ( fabs( BorneSup - BorneInf ) < MARGE_EGALITE_BORNE_MIN_ET_MAX ) { + # if TRACES_BORNES_IDENTIQUES == 1 + printf("Fixation de la variable %d car bornes identiques BorneInf %e BorneSup %e Ecart %e\n", + Var,BorneInf,BorneSup,BorneSup-BorneInf); + # endif + *BorneAmelioree = OUI_PNE; + PRS_FixerUneVariableAUneValeur( Presolve, Var, 0.5 * ( BorneSup + BorneInf ) ); +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_MettreAJourLesBornesDUneVariable( PRESOLVE * Presolve, int Var, + char BorneInfCalculee, double BorneInf, + int ContrainteBornanteInf, + char BorneSupCalculee, double BorneSup, + int ContrainteBornanteSup, + char * BorneAmelioree ) +{ +int * TypeDeVariable; int * TypeDeBornePourPresolve; double * BorneInfPourPresolve; +double * BorneSupPourPresolve; int TypeBrn; int * ContrainteBornanteInferieurement; +int * ContrainteBornanteSuperieurement; char * TypeDeValeurDeBorneInf; +char * TypeDeValeurDeBorneSup; char * ConserverLaBorneInfDuPresolve; +char * ConserverLaBorneSupDuPresolve; double MargeSurModifDeBorne; +double SeuilPourAmeliorationDeBorne; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +*BorneAmelioree = NON_PNE; + +TypeDeVariable = Pne->TypeDeVariableTrav; + +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +TypeDeValeurDeBorneInf = Presolve->TypeDeValeurDeBorneInf; +TypeDeValeurDeBorneSup = Presolve->TypeDeValeurDeBorneSup; +ContrainteBornanteInferieurement = Presolve->ContrainteBornanteInferieurement; +ContrainteBornanteSuperieurement = Presolve->ContrainteBornanteSuperieurement; +ConserverLaBorneInfDuPresolve = Presolve->ConserverLaBorneInfDuPresolve; +ConserverLaBorneSupDuPresolve = Presolve->ConserverLaBorneSupDuPresolve; + +TypeBrn = TypeDeBornePourPresolve[Var]; + +MargeSurModifDeBorne = MARGE_SUR_MODIF_DE_BORNE; +SeuilPourAmeliorationDeBorne = SEUIL_POUR_AMELIORATION_DE_BORNE; + +if ( BorneInfCalculee == OUI_PNE ) { + + PRS_VariablesDeBornesIdentiques( Presolve, Var, BorneInf, BorneSupPourPresolve[Var], BorneAmelioree ); + if ( *BorneAmelioree == OUI_PNE ) return; + + /*if ( ConserverLaBorneInfDuPresolve[Var] == OUI_PNE || TypeDeValeurDeBorneInf[Var] == VALEUR_NATIVE ) SeuilPourAmeliorationDeBorne = 0.0;*/ + /*if ( TypeDeValeurDeBorneInf[Var] == VALEUR_NATIVE ) SeuilPourAmeliorationDeBorne = 0.0;*/ + + if ( BorneInf - MargeSurModifDeBorne >= BorneInfPourPresolve[Var] + SeuilPourAmeliorationDeBorne || + TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT || TypeBrn == VARIABLE_NON_BORNEE ) { + # if TRACES == 1 + printf("-> variable %d borne inf amelioree valeur %e nouvelle valeur %e\n",Var,BorneInfPourPresolve[Var],BorneInf); + # endif + *BorneAmelioree = OUI_PNE; + BorneInfPourPresolve[Var] = BorneInf - MargeSurModifDeBorne; + ConserverLaBorneInfDuPresolve[Var] = NON_PNE; /* Car elle a pu etre mise a OUI_PNE lors d'une desactivation de contrainte */ + ContrainteBornanteInferieurement[Var] = ContrainteBornanteInf; + TypeDeValeurDeBorneInf[Var] = VALEUR_IMPLICITE; + + /* Maj des bornes pour le presolve */ + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) TypeDeBornePourPresolve[Var] = VARIABLE_BORNEE_DES_DEUX_COTES; + else if ( TypeBrn == VARIABLE_NON_BORNEE ) TypeDeBornePourPresolve[Var] = VARIABLE_BORNEE_INFERIEUREMENT; + } +} +if ( TypeDeVariable[Var] == ENTIER && BorneInfPourPresolve[Var] > SEUIL_INF_POUR_FIXATION_BINAIRE ) { + if ( BorneSupPourPresolve[Var] == 1.0 ) { + # if TRACES == 1 + printf("-> variable entiere %d fixee a 1\n",Var); + # endif + *BorneAmelioree = OUI_PNE; + PRS_FixerUneVariableAUneValeur( Presolve, Var, 1.0 ); + return; + } + else { + # if TRACES == 1 + printf("-> Probleme infaisable: variable entiere %d BorneSup %e BorneInf %e\n",Var,BorneSupPourPresolve[Var],BorneInfPourPresolve[Var]); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } +} + +if ( BorneSupCalculee == OUI_PNE ) { + + PRS_VariablesDeBornesIdentiques( Presolve, Var, BorneInfPourPresolve[Var], BorneSup, BorneAmelioree ); + if ( *BorneAmelioree == OUI_PNE ) return; + + /*if ( ConserverLaBorneSupDuPresolve[Var] == OUI_PNE || TypeDeValeurDeBorneSup[Var] == VALEUR_NATIVE ) SeuilPourAmeliorationDeBorne = 0.0;*/ + /*if ( TypeDeValeurDeBorneSup[Var] == VALEUR_NATIVE ) SeuilPourAmeliorationDeBorne = 0.0;*/ + + if ( BorneSup + MargeSurModifDeBorne <= BorneSupPourPresolve[Var] - SeuilPourAmeliorationDeBorne || + TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT || TypeBrn == VARIABLE_NON_BORNEE ) { + # if TRACES == 1 + printf("-> variable %d borne sup amelioree valeur %e nouvelle valeur %e\n",Var,BorneSupPourPresolve[Var],BorneSup); + # endif + *BorneAmelioree = OUI_PNE; + BorneSupPourPresolve[Var] = BorneSup + MargeSurModifDeBorne; + ConserverLaBorneSupDuPresolve[Var] = NON_PNE; /* Car elle a pu etre mise a OUI_PNE lors d'une desactivation de contrainte */ + ContrainteBornanteSuperieurement[Var] = ContrainteBornanteSup; + TypeDeValeurDeBorneSup[Var] = VALEUR_IMPLICITE; + + /* Maj des bornes pour le presolve */ + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) TypeDeBornePourPresolve[Var] = VARIABLE_BORNEE_DES_DEUX_COTES; + else if ( TypeBrn == VARIABLE_NON_BORNEE ) TypeDeBornePourPresolve[Var] = VARIABLE_BORNEE_SUPERIEUREMENT; + } +} +if ( TypeDeVariable[Var] == ENTIER && BorneSupPourPresolve[Var] < SEUIL_SUP_POUR_FIXATION_BINAIRE ) { + if ( BorneInfPourPresolve[Var] == 0.0 ) { + # if TRACES == 1 + printf("-> variable entiere %d fixee a 0\n",Var); + # endif + *BorneAmelioree = OUI_PNE; + PRS_FixerUneVariableAUneValeur( Presolve, Var, 0.0 ); + return; + } + else { + # if TRACES == 1 + printf("-> Probleme infaisable: variable entiere %d BorneSup %e BorneInf %e\n",Var,BorneSupPourPresolve[Var],BorneInfPourPresolve[Var]); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } +} + +if ( TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_DES_DEUX_COTES && + BorneInfPourPresolve[Var] > BorneSupPourPresolve[Var] + MARGE_DINFAISABILITE ) { + # if TRACES == 1 + printf("** Phase de Presolve, resserage des bornes des variables:\n"); + printf(" la variable %d a une borne inf %e plus grande que la borne sup %e\n",Var, + BorneInfPourPresolve[Var],BorneSupPourPresolve[Var]); + printf(" Valeur min en entree %e Valeur max en entree %e\n",Pne->UminTrav[Var],Pne->UmaxTrav[Var]); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; +} + +return; +} + + + + diff --git a/src/ext/Sirius_Solver/presolve/prs_mettre_a_jour_bornes_des_variables_duales.c b/src/ext/Sirius_Solver/presolve/prs_mettre_a_jour_bornes_des_variables_duales.c new file mode 100644 index 0000000000..a0357f1ff2 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_mettre_a_jour_bornes_des_variables_duales.c @@ -0,0 +1,128 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Mise a jour des bornes d'une variable duale a chaque fois qu'on + calcule une nouvelle borne. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES_BORNES_IDENTIQUES 0 +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ +/* Il se peut qu'en ameliorant les bornes, la variable en soit fixee */ +void PRS_VariablesDualesDeBornesIdentiques( PRESOLVE * Presolve, int Cnt, + double BorneInf, double BorneSup, + char * BorneAmelioree ) +{ +*BorneAmelioree = NON_PNE; +if ( Presolve->ConnaissanceDeLambda[Cnt] == LAMBDA_CONNU ) return; +/* Il se peut qu'en ameliorant les bornes, la variable en soit fixee */ +if ( fabs( BorneSup - BorneInf ) > ECART_NUL_LAMBDAMIN_LAMBDAMAX ) return; +# if TRACES_BORNES_IDENTIQUES == 1 + printf("fixation de la variable duale de la contrainte %d car bornes identiques BorneInf %e BorneSup %e\n", + Cnt,BorneInf,BorneSup); +# endif +Presolve->Lambda[Cnt] = 0.5 * ( BorneInf + BorneSup ); +Presolve->LambdaMin[Cnt] = Presolve->Lambda[Cnt]; +Presolve->LambdaMax[Cnt] = Presolve->Lambda[Cnt]; +Presolve->ConnaissanceDeLambda[Cnt] = LAMBDA_CONNU; +*BorneAmelioree = OUI_PNE; +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_MettreAJourLesBornesDUneVariableDuale( PRESOLVE * Presolve, int Cnt, + char BorneInfCalculee, double BorneInf, + char BorneSupCalculee, double BorneSup, + char * BorneAmelioree ) +{ +double * LambdaMin; double * LambdaMax; double * Lambda; char * ConnaissanceDeLambda; + +*BorneAmelioree = NON_PNE; +LambdaMin = Presolve->LambdaMin; +LambdaMax = Presolve->LambdaMax; +Lambda = Presolve->Lambda; +ConnaissanceDeLambda = Presolve->ConnaissanceDeLambda; + +if ( BorneInfCalculee == OUI_PNE ) { + + PRS_VariablesDualesDeBornesIdentiques( Presolve, Cnt, BorneInf, LambdaMax[Cnt], BorneAmelioree ); + if ( *BorneAmelioree == OUI_PNE ) return; + + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( BorneInf > LambdaMin[Cnt] ) { + LambdaMin[Cnt] = BorneInf; + *BorneAmelioree = OUI_PNE; + } + } + else { + LambdaMin[Cnt] = BorneInf; + *BorneAmelioree = OUI_PNE; + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU ) ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_ET_MAX_CONNU; + else ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_CONNU; + } +} + +if ( BorneSupCalculee == OUI_PNE ) { + + PRS_VariablesDualesDeBornesIdentiques( Presolve, Cnt, LambdaMin[Cnt], BorneSup, BorneAmelioree ); + if ( *BorneAmelioree == OUI_PNE ) return; + + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( BorneSup < Presolve->LambdaMax[Cnt] ) { + Presolve->LambdaMax[Cnt] = BorneSup; + *BorneAmelioree = OUI_PNE; + } + } + else { + LambdaMax[Cnt] = BorneSup; + *BorneAmelioree = OUI_PNE; + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU ) ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_ET_MAX_CONNU; + else ConnaissanceDeLambda[Cnt] = LAMBDA_MAX_CONNU; + } +} + +if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( fabs( LambdaMin[Cnt] - LambdaMax[Cnt] ) < ECART_NUL_LAMBDAMIN_LAMBDAMAX ) { + # if TRACES == 1 + printf("Cnt %d LambdaMin = LambdaMax = %e\n",Cnt,Presolve->LambdaMin[Cnt]); + # endif + Lambda[Cnt] = 0.5 * ( LambdaMin[Cnt] + LambdaMax[Cnt] ); + LambdaMin[Cnt] = Lambda[Cnt]; + LambdaMax[Cnt] = Lambda[Cnt]; + ConnaissanceDeLambda[Cnt] = LAMBDA_CONNU; + *BorneAmelioree = OUI_PNE; + } +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/presolve/prs_presolve.c b/src/ext/Sirius_Solver/presolve/prs_presolve.c new file mode 100644 index 0000000000..d5ab142a49 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_presolve.c @@ -0,0 +1,421 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Presolve + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# define NI_AU_DEBUT_NI_A_LA_FIN 0 +# define AU_DEBUT 1 +# define A_LA_FIN 2 +# define AU_DEBUT_ET_A_LA_FIN 3 +# define AMELIORATION_DES_COEFF_BINAIRES AU_DEBUT +# if UTILISER_LE_GRAPHE_DE_CONFLITS == NON_PNE + # define AMELIORATION_DES_COEFF_BINAIRES AU_DEBUT_ET_A_LA_FIN +# endif + +# define TRACES 0 + +# define MARGE 1.e-5 + +/*----------------------------------------------------------------------------*/ + +void PRS_Presolve( void * PneE ) +{ +int NbModifications; int Relancer; int VariableEntiereFixee; int NombreDeVariables; +int BorneAmelioree; int VariableFixee; int NbCycles; int * ContrainteBornanteInferieurement; +int * ContrainteBornanteSuperieurement; int NbCntInact; int Var; int Cnt; char * ContrainteInactive; +int il; int ilMax; double A; double Amn; double Amx; int * TypeDeBornePourPresolve; +int * TypeDeBorneTrav; int NbMetaCycles; double * UTrav; double * UminTrav; double * UmaxTrav; +double * ValeurDeXPourPresolve; double * BorneInfPourPresolve; double * BorneSupPourPresolve; +char * ConserverLaBorneSupDuPresolve; char * ConserverLaBorneInfDuPresolve; int NbVarNb; +char BorneInfPresolveDisponible; char BorneSupPresolveDisponible; char TypeBrn; +double Marge; PRESOLVE * Presolve; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) PneE; + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + void * Tas; + Tas = MEM_Init(); + Presolve = (PRESOLVE *) MEM_Malloc( Tas, sizeof( PRESOLVE ) ); + if ( Presolve == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet PRESOLVE\n"); + goto FinDuPresolve; + } + Presolve->Tas = Tas; +# else + Presolve = (PRESOLVE *) malloc( sizeof( PRESOLVE ) ); + if ( Presolve == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet PRESOLVE\n"); + goto FinDuPresolve; + } + Presolve->Tas = NULL; +# endif + +Pne->ProblemePrsDuSolveur = (void *) Presolve; +Presolve->ProblemePneDuPresolve = PneE; + +for ( Pne->NombreDeVariablesEntieresTrav = 0 , Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) Pne->NombreDeVariablesEntieresTrav++; +} + +if ( Pne->AffichageDesTraces == OUI_PNE ) { + printf("Starting computations ->"); + printf(" rows: %6d",Pne->NombreDeContraintesTrav); + printf(" columns: %6d",Pne->NombreDeVariablesTrav); + printf(" binaries: %d",Pne->NombreDeVariablesEntieresTrav); + printf("\n"); +} + +#if VERBOSE_PRS + printf("Phase de Presolve\n"); +#endif + +if ( Pne->ChainageTransposeeExploitable == NON_PNE ) PNE_ConstruireLeChainageDeLaTransposee( Pne ); + +PRS_AllocationsStructure( Presolve ); + +NbCycles = 0; /* Pour eviter les warnign de compilation */ +NbMetaCycles = 0; + +/*if ( Pne->FaireDuPresolve == NON_PNE ) goto FinDuPresolve;*/ + +/* Calcul du plus grand et du plus petit terme (different de zero) */ +Amn = LINFINI_PNE; +Amx = -LINFINI_PNE; +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + il = Pne->MdebTrav[Cnt]; + ilMax = il + Pne->NbTermTrav[Cnt]; + while ( il < ilMax ) { + A = fabs ( Pne->ATrav[il] ); + if ( A > ZERO_PRESOLVE ) { + if ( A < Amn ) Amn = A; + else if ( A > Amx ) Amx = A; + } + il++; + } +} + +Pne->PlusGrandTerme = Amx; +Pne->PlusPetitTerme = Amn; + +if ( Pne->FaireDuPresolve == NON_PNE ) goto FinDuPresolve; + +/***********************************************************************************/ + +/* Attention: ne peut etre appele que sur les bornes natives des variables ou sur les + bornes definitives. Donc pas pendant les iterations de presolve car les bornes + du presolve ne sont pas toutes conservees. */ +# if AMELIORATION_DES_COEFF_BINAIRES == AU_DEBUT || AMELIORATION_DES_COEFF_BINAIRES == AU_DEBUT_ET_A_LA_FIN + PNE_AmeliorerLesCoefficientsDesVariablesBinaires( Pne, (void *) Presolve, MODE_PRESOLVE ); +# endif + +DebutDesCycles: +NbCycles = 0; +NbMetaCycles++; +Relancer = OUI_PNE; /* C'est juste pour passer dans le while */ +while ( Relancer == OUI_PNE && NbCycles < 5 /*5*/ && Pne->YaUneSolution != PROBLEME_INFAISABLE ) { + + NbCycles++; + + #if VERBOSE_PRS + printf("Cycle de presolve numero %d \n",NbCycles); + #endif + Relancer = NON_PNE; + + /* Singleton sur ligne */ + NbModifications = 1; + while( NbModifications > 0 ) { + NbModifications = 0; + PRS_SingletonsSurLignes( Presolve, &NbModifications ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_SingletonsSurLignes\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( NbModifications != 0 ) Relancer = OUI_PNE; + } + + /* Singleton sur colonne */ + NbModifications = 1; + while( NbModifications > 0 ) { + NbModifications = 0; + PRS_SingletonsSurColonnes( Presolve, &NbModifications ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_SingletonsSurColonnes\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( NbModifications != 0 ) Relancer = OUI_PNE; + } + + /* On cherche a borner les limites infinies a l'aide contraintes dont il manque + des bornes a une seule variable */ + + PRS_BornerLesVariablesNonBornees( Presolve, &NbModifications ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_BornerLesVariablesNonBornees\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( NbModifications != 0 ) Relancer = OUI_PNE; + + /* On cherche a ameliorer les bornes */ + PRS_CalculerLesBornesDeToutesLesContraintes( Presolve, &NbModifications ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_CalculerLesBornesDeToutesLesContraintes\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( NbModifications != 0 ) Relancer = OUI_PNE; + + PRS_ContraintesToujoursInactives( Presolve, &NbCntInact ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_ContraintesToujoursInactives\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( NbCntInact != 0 ) Relancer = OUI_PNE; + + PRS_AmeliorerLesBornes( Presolve, &BorneAmelioree ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_AmeliorerLesBornes\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( BorneAmelioree == OUI_PNE ) Relancer = OUI_PNE; + + PRS_BornerLesVariablesDualesNonBornees( Presolve, &NbModifications ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_BornerLesVariablesDualesNonBornees\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( NbModifications != 0 ) Relancer = OUI_PNE; + + /* A verifier: il ne faut pas de subititution de variable ou si presolve uniquement */ + PRS_VariablesDualesEtCoutsReduits( Presolve, &BorneAmelioree ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_VariablesDualesEtCoutsReduits\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( BorneAmelioree == OUI_PNE ) Relancer = OUI_PNE; + + /* On regarde si on peut fixer des variables a l'aide de leurs couts: si une variable + n'intervient que dans des inegalites (ici toujours <) et que le signe de son cout et + le meme que ceux de ses coeff. dans les contraintes alors on peut fixer la variable + sur une de ses bornes */ + + PRS_FixerVariablesSurCritere( Presolve, &VariableFixee ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_FixerVariablesSurCritere\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( VariableFixee == OUI_PNE ) Relancer = OUI_PNE; + + /* Si une variable n'intervient pas dans les contraintes et n'est pas deja fixee on peut la + fixer sur une de ses bornes en fonction de son cout */ + + PRS_VariablesHorsContraintes( Presolve, &NbModifications ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_VariablesHorsContraintes\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( NbModifications != 0 ) Relancer = OUI_PNE; + + /* A mettre en service parce que ca marche */ + PRS_SubstituerVariables( Presolve, &NbModifications ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_SubstituerVariables\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( NbModifications != 0 ) Relancer = OUI_PNE; + + PRS_ContraintesColineaires( Presolve, &NbModifications ); + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_ContraintesColineaires\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( NbModifications != 0 ) Relancer = OUI_PNE; + + /* Si presolve uniquement par appel pendant un branch and bound: on ne supprime pas les colonnes colineaires */ + if ( Pne->Controls != NULL ) { + if ( Pne->Controls->PresolveUniquement == OUI_PNE ) { + NbModifications = 0; + } + } + else { + PRS_ColonnesColineaires( Presolve, &NbModifications ); + } + # if TRACES == 1 + if ( Pne->YaUneSolution != OUI_PNE ) printf("Probleme infaisable apres PRS_ColonnesColineaires\n"); + # endif + if ( Pne->YaUneSolution != OUI_PNE ) break; + if ( NbModifications != 0 ) Relancer = OUI_PNE; + +} + +/* Experimentalement on constate que ce type de transformation peut conduire a des + imprecisions sur les coefficients des contraintes telles que parfois on peut + se retrouver avec un probleme sans solution */ +/* +if ( Pne->YaUneSolution != PROBLEME_INFAISABLE && NbMetaCycles <= 5 ) { + Relancer = NON_PNE; + NbModifications = 1; + while( NbModifications > 0 ) { + NbModifications = 0; + PRS_CombinaisonDeContraintes( Presolve, &NbModifications ); + if ( NbModifications != 0 ) Relancer = OUI_PNE; + } + if ( Relancer == OUI_PNE ) goto DebutDesCycles; +} +*/ + +#if VERBOSE_PRS + printf("Fin des cycles de presolve\n"); +#endif + +/* Les contraintes dont toutes les variables sont fixees ne servent a rien */ + +PRS_SupprimerLesContraintesAvecQueDesVariablesFixees( Presolve ); + +if ( Pne->Controls != NULL ) { + if ( Pne->Controls->PresolveUniquement == OUI_PNE ) { + Pne->Controls->Presolve = (void *) Presolve; + return; + } +} + +NombreDeVariables = Pne->NombreDeVariablesTrav; +UTrav = Pne->UTrav; +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; +TypeDeBorneTrav = Pne->TypeDeBorneTrav; + +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +ConserverLaBorneSupDuPresolve = Presolve->ConserverLaBorneSupDuPresolve; +ConserverLaBorneInfDuPresolve = Presolve->ConserverLaBorneInfDuPresolve; +ContrainteInactive = Presolve->ContrainteInactive; +ContrainteBornanteInferieurement = Presolve->ContrainteBornanteInferieurement; +ContrainteBornanteSuperieurement = Presolve->ContrainteBornanteSuperieurement; + +Marge = 1.e-5; + +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) { /* C'est entre autres toujours vrai si c'est dans les donnees de depart */ + UTrav[Var] = ValeurDeXPourPresolve[Var]; + UminTrav[Var] = BorneInfPourPresolve[Var]; + UmaxTrav[Var] = BorneSupPourPresolve[Var]; + TypeDeBorneTrav[Var] = TypeDeBornePourPresolve[Var]; + continue; + } + else if ( ConserverLaBorneInfDuPresolve[Var] == OUI_PNE ) { + UTrav[Var] = 0.0; /* Pas d'importance */ + UminTrav[Var] = BorneInfPourPresolve[Var]; + if ( ConserverLaBorneSupDuPresolve[Var] == OUI_PNE ) { + UmaxTrav[Var] = BorneSupPourPresolve[Var]; + TypeDeBorneTrav[Var] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else { + if ( TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) TypeDeBorneTrav[Var] = VARIABLE_BORNEE_INFERIEUREMENT; + else if ( TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) TypeDeBorneTrav[Var] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + } + else if ( ConserverLaBorneSupDuPresolve[Var] == OUI_PNE ) { + /* Donc ConserverLaBorneInfDuPresolve[Var] est egal a NON_PNE */ + UTrav[Var] = 0.0; /* Pas d'importance */ + UmaxTrav[Var] = BorneSupPourPresolve[Var]; + if ( TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) TypeDeBorneTrav[Var] = VARIABLE_BORNEE_SUPERIEUREMENT; + else if ( TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) TypeDeBorneTrav[Var] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else { + /* On garde les bornes du presolve mais on les elargi un petit peu */ + /* Si c'est un entier on le garde */ + if ( Pne->TypeDeVariableTrav[Var] != ENTIER ) { + TypeDeBorneTrav[Var] = TypeDeBornePourPresolve[Var]; + UTrav[Var] = 0.0; + Marge = 1.e-5; + if ( BorneInfPourPresolve[Var] - Marge >= UminTrav[Var] ) UminTrav[Var] = BorneInfPourPresolve[Var] - Marge; + if ( BorneSupPourPresolve[Var] + Marge <= UmaxTrav[Var] ) UmaxTrav[Var] = BorneSupPourPresolve[Var] + Marge; + } + } +} + +/* Attention: ne peut etre appele que sur les bornes natives des variables ou sur les + bornes definitives. Donc pas pendant les iterations de presolve car les bornes + du presolve ne sont pas toutes conservees. */ +# if AMELIORATION_DES_COEFF_BINAIRES == A_LA_FIN || AMELIORATION_DES_COEFF_BINAIRES == AU_DEBUT_ET_A_LA_FIN + /* Ici on beneficie de la creation de bornes la ou il n'y en n'avait pas */ + for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + TypeDeBornePourPresolve[Var] = TypeDeBorneTrav[Var]; + BorneInfPourPresolve[Var] = UminTrav[Var]; + BorneSupPourPresolve[Var] = UmaxTrav[Var]; + } + PNE_AmeliorerLesCoefficientsDesVariablesBinaires( Pne, (void *) Presolve, MODE_PRESOLVE ); +# endif + +FinDuPresolve: + +/* Pour sortir le graphe au format DIMACS */ +/*PRS_ConstruireLeGrapheAuFormatDIMACS( Presolve );*/ + +/* Meme lorsqu'on ne fait pas de presolve on fait cet appel qui enleve les termes strictement + nuls de la matrice */ + +PRS_EnleverLesContraintesInactives( Presolve ); + +if ( Pne->YaDesVariablesEntieres == OUI_PNE ) { + /* Attention: il est imperatif de le faire apres avoir enleve le contraintes inactives et pas avant. + De plus si on le fait avant le presolve, celui-ci risque de la supprimer en la detectant inactive + ce qui est vrai tant qu'on n'a pas trouve de solution entiere. */ + PNE_AjouterLaContrainteDeCoutMax( Pne ); +} + +/*********************************************/ +TypeDeBorneTrav = Pne->TypeDeBorneTrav; +UminTrav = Pne->UminTrav; +UmaxTrav = Pne->UmaxTrav; +UTrav = Pne->UTrav; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( UminTrav[Var] == UmaxTrav[Var] ) { + TypeDeBorneTrav[Var] = VARIABLE_FIXE; + Pne->TypeDeVariableTrav[Var] = REEL; + UTrav[Var] = UminTrav[Var]; + } +} +/*****************************************/ + +#if VERBOSE_PRS + printf("Nombre de cycles de presolve %d \n",NbCycles); +#endif + +PRS_LiberationStructure( Presolve ); + +return; +} + diff --git a/src/ext/Sirius_Solver/presolve/prs_singleton_colonne.c b/src/ext/Sirius_Solver/presolve/prs_singleton_colonne.c new file mode 100644 index 0000000000..66c82bbf76 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_singleton_colonne.c @@ -0,0 +1,525 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Colonnes singleton. + - Si la variable est non bornee et que la contrainte est + non bornante et que c'est une egalite, on peut enlever la variable des donnees + et la remplacer par les autres variables de la contrainte. + Dans les autres cas on conserve la contrainte mais on peut + soit calculer la variable duale de la contrainte, soit calculer + une borne sur cette variable duale. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES 0 + +void PRS_SingletonsSurColonnesSubstituerLaVariable( PRESOLVE * , int , int , int * ); + +char PRS_FabriquerUneVariableNonBorneeAPartirDUneContrainteDoubleton( PROBLEME_PNE * , PRESOLVE * , int , char , int ); + +/*----------------------------------------------------------------------------*/ + +void PRS_SingletonsSurColonnesSubstituerLaVariable( PRESOLVE * Presolve, int Var, int Cnt, int * NbModifications ) +{ +double CoutVar; int il; int ilMax; int V; double * CoutLineaire; double * A; char Flag; +int * Nuvar; int * Mdeb; int * NbTerm; double CoeffPivot; PROBLEME_PNE * Pne; +int * Cdeb; int * Csui; int * NumContrainte; int iSubstitution; double B; +double * ValeurDeLaConstanteDeSubstitution; int NbVariablesSubstituees; +int * IndiceDebutVecteurDeSubstitution; int * NbTermesVecteurDeSubstitution; +int Nb; double * CoeffDeSubstitution; int * NumeroDeVariableDeSubstitution; +int * NumeroDesVariablesSubstituees; double * CoutDesVariablesSubstituees; +int * TypeDeBornePourPresolve; double * ValeurDeXPourPresolve; +int * ContrainteDeLaSubstitution; int * CorrespondanceCntPneCntEntree; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +if ( Pne->NumeroDesVariablesSubstituees == NULL ) return; /* Pas de substitution possible */ +/* Si la table de substitution est plein on arrete */ +if ( Pne->NbVariablesSubstituees >= Pne->NombreDeVariablesTrav - 1 ) return; +if ( Pne->NombreDOperationsDePresolve >= Pne->TailleTypeDOperationDePresolve ) return; + +CorrespondanceCntPneCntEntree = Pne->CorrespondanceCntPneCntEntree; +NbVariablesSubstituees = Pne->NbVariablesSubstituees; +NumeroDesVariablesSubstituees = Pne->NumeroDesVariablesSubstituees; +ValeurDeLaConstanteDeSubstitution = Pne->ValeurDeLaConstanteDeSubstitution; +IndiceDebutVecteurDeSubstitution = Pne->IndiceDebutVecteurDeSubstitution; +NbTermesVecteurDeSubstitution = Pne->NbTermesVecteurDeSubstitution; +CoeffDeSubstitution = Pne->CoeffDeSubstitution; +NumeroDeVariableDeSubstitution = Pne->NumeroDeVariableDeSubstitution; +CoutDesVariablesSubstituees = Pne->CoutDesVariablesSubstituees; +ContrainteDeLaSubstitution = Pne->ContrainteDeLaSubstitution; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; + +*NbModifications = *NbModifications + 1; + +CoutLineaire = Pne->LTrav; +A = Pne->ATrav; +Nuvar = Pne->NuvarTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; + +/* Reperage du type de reduction */ +Pne->TypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = SUPPRESSION_VARIABLE_NON_BORNEE; +Pne->IndexDansLeTypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = Pne->NbVariablesSubstituees; +Pne->NombreDOperationsDePresolve++; + +/* Description de la reduction */ +CoeffPivot = 1; +Flag = 0; +il = Cdeb[Var]; +while ( il >= 0 ) { + if ( NumContrainte[il] == Cnt ) { + CoeffPivot = A[il]; + Flag = 1; + break; + } + il = Csui[il]; +} +if ( Flag == 0 ) { + printf("BUG dans SingletonsSurColonnesSubstituerLaVariable pivot pas trouve \n"); + return; +} + +CoutVar = CoutLineaire[Var]; +B = Pne->BTrav[Cnt]; + +il = Mdeb[Cnt]; +ilMax = il + NbTerm[Cnt]; +Nb = 0; +iSubstitution = Pne->IndexLibreVecteurDeSubstitution; +IndiceDebutVecteurDeSubstitution[NbVariablesSubstituees] = iSubstitution; +while ( il < ilMax ) { + V = Nuvar[il]; + if ( TypeDeBornePourPresolve[V] == VARIABLE_FIXE ) B -= A[il] * ValeurDeXPourPresolve[V]; + else { + if ( V != Var ) { + CoutLineaire[V] -= CoutVar * A[il] / CoeffPivot; + /*CoutLineaire[V] -= CoutVar * A[il] / CoeffPivot;*/ /* Gros bug de copier coller !!! */ + CoeffDeSubstitution[iSubstitution] = -A[il] / CoeffPivot; + NumeroDeVariableDeSubstitution[iSubstitution] = V; + iSubstitution++; + Nb++; + } + else CoutLineaire[V] = 0; + } + il++; +} +NbTermesVecteurDeSubstitution[NbVariablesSubstituees] = Nb; + +NumeroDesVariablesSubstituees[NbVariablesSubstituees] = Var; +CoutDesVariablesSubstituees[NbVariablesSubstituees] = CoutVar; +ContrainteDeLaSubstitution[NbVariablesSubstituees] = CorrespondanceCntPneCntEntree[Cnt]; +ValeurDeLaConstanteDeSubstitution[NbVariablesSubstituees] = B / CoeffPivot; +NbVariablesSubstituees++; + +Pne->Z0 += CoutVar * B / CoeffPivot; + +Pne->IndexLibreVecteurDeSubstitution = iSubstitution; +Pne->NbVariablesSubstituees = NbVariablesSubstituees; + +/* Quand on supprime une variable, la valeur de remplacement n'a pas d'importance car elle sera calculee. + Il n'est pas necessaire de mettre les termes de la colonne (ou de la contrainte) a 0 car elle + devient inactive */ +PRS_FixerUneVariableAUneValeur( Presolve, Var, 0.0 ); + +/* Desactivation de la contrainte */ +PRS_DesactiverContrainte( Presolve, Cnt ); + +# if TRACES == 1 + printf("Singleton sur colonne %d de type VARIABLE_NON_BORNEE: la variable est substituee et la contrainte %d supprimee Pivot %e\n", + Var,Cnt,CoeffPivot); +# endif + +return; +} + +/*----------------------------------------------------------------------------*/ + +char PRS_FabriquerUneVariableNonBorneeAPartirDUneContrainteDoubleton( PROBLEME_PNE * Pne, + PRESOLVE * Presolve, + int VariableSingleton, + char TypeBrnVariableSingleton, + int CntDeLaVariableSingleton ) +{ +int il; int ilMax; int Nb; int V; int * Mdeb; int * NbTerm; int * Nuvar; double * A; +char BorneInfCalculee; char BorneSupCalculee; double BorneInf; double BorneSup; +double * BorneInfPourPresolve; double * BorneSupPourPresolve; int * TypeDeBornePourPresolve; +int * ContrainteBornanteInferieurement; int * ContrainteBornanteSuperieurement; +char OnReboucle; int NbTours; int VariableRestante; int * TypeDeVariable; +double * ValeurDeXPourPresolve; char * TypeDeValeurDeBorneInf; char * TypeDeValeurDeBorneSup; +char * ConserverLaBorneInfDuPresolve; char * ConserverLaBorneSupDuPresolve; +double MargeInfaisabilite; + +MargeInfaisabilite = 1.e-6; + +/* On verifie que c'est une contrainte a 2 termes */ +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +TypeDeVariable = Pne->TypeDeVariableTrav; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ContrainteBornanteInferieurement = Presolve->ContrainteBornanteInferieurement; +ContrainteBornanteSuperieurement = Presolve->ContrainteBornanteSuperieurement; +TypeDeValeurDeBorneInf = Presolve->TypeDeValeurDeBorneInf; +TypeDeValeurDeBorneSup = Presolve->TypeDeValeurDeBorneSup; +ConserverLaBorneInfDuPresolve = Presolve->ConserverLaBorneInfDuPresolve; +ConserverLaBorneSupDuPresolve = Presolve->ConserverLaBorneSupDuPresolve; + +Nb = 0; +VariableRestante = -1; +il = Mdeb[CntDeLaVariableSingleton]; +ilMax = il + NbTerm[CntDeLaVariableSingleton]; +while ( il < ilMax ) { + if ( A[il] != 0.0 ) { + V = Nuvar[il]; + if ( TypeDeBornePourPresolve[V] != VARIABLE_FIXE ) { + Nb++; + if ( Nb > 2 ) break; + if ( V != VariableSingleton ) VariableRestante = V; + } + } + il++; +} +if ( Nb != 2 || VariableRestante < 0 ) return( TypeBrnVariableSingleton ); + +/* On peut en faire un singleton non borne */ +NbTours = 0; +OnReboucle = OUI_PNE; +while ( OnReboucle == OUI_PNE ) { + OnReboucle = NON_PNE; + /* On cherche a borner au mieux les variables */ + /* VariableSingleton */ + PRS_CalculeBorneSurVariableEnFonctionDeLaContrainte( Presolve, CntDeLaVariableSingleton, VariableSingleton, + &BorneInfCalculee, &BorneInf, &BorneSupCalculee, &BorneSup ); + if ( BorneInfCalculee == OUI_PNE ) { + if ( BorneInf > BorneSupPourPresolve[VariableSingleton] + MargeInfaisabilite ) { + /* Infaisabilite */ + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return( TypeBrnVariableSingleton ); + } + if ( BorneInf > BorneInfPourPresolve[VariableSingleton] ) { + BorneInfPourPresolve[VariableSingleton] = BorneInf; + TypeDeValeurDeBorneInf[VariableSingleton] = VALEUR_IMPLICITE; + ContrainteBornanteInferieurement[VariableSingleton] = CntDeLaVariableSingleton; + OnReboucle = OUI_PNE; + if ( TypeDeBornePourPresolve[VariableSingleton] == VARIABLE_NON_BORNEE ) { + TypeDeBornePourPresolve[VariableSingleton] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( TypeDeBornePourPresolve[VariableSingleton] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + TypeDeBornePourPresolve[VariableSingleton] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + } + } + if ( BorneSupCalculee == OUI_PNE ) { + if ( BorneSup < BorneInfPourPresolve[VariableSingleton] - MargeInfaisabilite ) { + /* Infaisabilite */ + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return( TypeBrnVariableSingleton ); + } + if ( BorneSup < BorneSupPourPresolve[VariableSingleton] ) { + BorneSupPourPresolve[VariableSingleton] = BorneSup; + TypeDeValeurDeBorneSup[VariableSingleton] = VALEUR_IMPLICITE; + ContrainteBornanteSuperieurement[VariableSingleton] = CntDeLaVariableSingleton; + OnReboucle = OUI_PNE; + if ( TypeDeBornePourPresolve[VariableSingleton] == VARIABLE_NON_BORNEE ) { + TypeDeBornePourPresolve[VariableSingleton] = VARIABLE_BORNEE_SUPERIEUREMENT; + } + else if ( TypeDeBornePourPresolve[VariableSingleton] == VARIABLE_BORNEE_INFERIEUREMENT ) { + TypeDeBornePourPresolve[VariableSingleton] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + } + } + /* VariableRestante */ + PRS_CalculeBorneSurVariableEnFonctionDeLaContrainte( Presolve, CntDeLaVariableSingleton, VariableRestante, + &BorneInfCalculee, &BorneInf, &BorneSupCalculee, &BorneSup ); + if ( BorneInfCalculee == OUI_PNE ) { + if ( BorneInf > BorneSupPourPresolve[VariableRestante] + MargeInfaisabilite ) { + /* Infaisabilite */ + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return( TypeBrnVariableSingleton ); + } + if ( BorneInf > BorneInfPourPresolve[VariableRestante] ) { + BorneInfPourPresolve[VariableRestante] = BorneInf; + TypeDeValeurDeBorneInf[VariableRestante] = VALEUR_IMPLICITE; + ContrainteBornanteInferieurement[VariableRestante] = CntDeLaVariableSingleton; + OnReboucle = OUI_PNE; + if ( TypeDeBornePourPresolve[VariableRestante] == VARIABLE_NON_BORNEE ) { + TypeDeBornePourPresolve[VariableRestante] = VARIABLE_BORNEE_INFERIEUREMENT; + } + else if ( TypeDeBornePourPresolve[VariableRestante] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + TypeDeBornePourPresolve[VariableRestante] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + } + } + if ( BorneSupCalculee == OUI_PNE ) { + if ( BorneSup < BorneInfPourPresolve[VariableRestante] - MargeInfaisabilite ) { + /* Infaisabilite */ + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return( TypeBrnVariableSingleton ); + } + if ( BorneSup < BorneSupPourPresolve[VariableRestante] ) { + BorneSupPourPresolve[VariableRestante] = BorneSup; + TypeDeValeurDeBorneSup[VariableRestante] = VALEUR_IMPLICITE; + ContrainteBornanteSuperieurement[VariableRestante] = CntDeLaVariableSingleton; + OnReboucle = OUI_PNE; + if ( TypeDeBornePourPresolve[VariableRestante] == VARIABLE_NON_BORNEE ) { + TypeDeBornePourPresolve[VariableRestante] = VARIABLE_BORNEE_SUPERIEUREMENT; + } + else if ( TypeDeBornePourPresolve[VariableRestante] == VARIABLE_BORNEE_INFERIEUREMENT ) { + TypeDeBornePourPresolve[VariableRestante] = VARIABLE_BORNEE_DES_DEUX_COTES; + } + } + } + NbTours++; + if ( NbTours > 10 ) break; +} + +if ( TypeDeVariable[VariableRestante] == ENTIER ) { + if ( BorneInfPourPresolve[VariableRestante] > SEUIL_INF_POUR_FIXATION_BINAIRE ) { + if ( BorneSupPourPresolve[VariableRestante] == 1.0 ) { + PRS_FixerUneVariableAUneValeur( Presolve, VariableRestante, 1.0 ); + } + else Pne->YaUneSolution = PROBLEME_INFAISABLE; + return( TypeBrnVariableSingleton ); + } + if ( BorneSupPourPresolve[VariableRestante] < SEUIL_SUP_POUR_FIXATION_BINAIRE ) { + if ( BorneInfPourPresolve[VariableRestante] == 0.0 ) { + PRS_FixerUneVariableAUneValeur( Presolve, VariableRestante, 0.0 ); + } + else Pne->YaUneSolution = PROBLEME_INFAISABLE; + return( TypeBrnVariableSingleton ); + } +} + + +/* Ci-dessous c'est une connerie */ + +/* On n'a pas pu finir ? */ +/* +if ( OnReboucle == OUI_PNE ) return( TypeBrnVariableSingleton ); +return( VARIABLE_NON_BORNEE ); +*/ + +TypeBrnVariableSingleton = PRS_ChoisirLaBorneLaPlusContraignantePourLesVariablesDuales( + Pne->TypeDeBorneTrav[VariableSingleton], TypeDeBornePourPresolve[VariableSingleton], + BorneInfPourPresolve[VariableSingleton], Pne->UminTrav[VariableSingleton], + BorneSupPourPresolve[VariableSingleton], Pne->UmaxTrav[VariableSingleton], + ConserverLaBorneInfDuPresolve[VariableSingleton], ConserverLaBorneSupDuPresolve[VariableSingleton], + TypeDeValeurDeBorneInf[VariableSingleton], TypeDeValeurDeBorneSup[VariableSingleton] ); + +return( TypeBrnVariableSingleton ); +} + +/*----------------------------------------------------------------------------*/ + +void PRS_SingletonsSurColonnes( PRESOLVE * Presolve, int * NbModifications ) +{ +int il; int Cnt; int Var; double BorneInf; double BorneSup; int NbTermes; char SensCnt ; +int CntDeLaVariable; int TypeBrnPresolve; PROBLEME_PNE * Pne; char BorneInfCalculee; +char BorneSupCalculee; int * Cdeb; int * Csui; char * ContrainteInactive; double * A; +int * NumContrainte; char * SensContrainte; char TypeBrnNative; double * BorneInfPourPresolve; +double * BorneSupPourPresolve; int * TypeDeBornePourPresolve; int * TypeDeVariable; +int * ContrainteBornanteInferieurement; int * ContrainteBornanteSuperieurement; +int NombreDeVariables; int * TypeDeBorneNative; char BorneInfPresolveDisponible; +char BorneSupPresolveDisponible; char * ConserverLaBorneSupDuPresolve; char * ConserverLaBorneInfDuPresolve; +double BorneInfPresolve; double BorneSupPresolve; char TypeBrn; double * BorneInfNative; +double * BorneSupNative; int NbVariablesFixees; int NbLambdaModifies; double Ai; +double * CoutLineaire; char * TypeDeValeurDeBorneInf; char * TypeDeValeurDeBorneSup; +char TypeValBorneInf; char TypeValBorneSup; char BorneAmelioree; + +# if TRACES == 1 + int CntS; int Cnti; char CsvSup; char CsvInf; +# endif + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +*NbModifications = 0; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +CoutLineaire = Pne->LTrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +SensContrainte = Pne->SensContrainteTrav; +A = Pne->ATrav; + +TypeDeBorneNative = Pne->TypeDeBorneTrav; +BorneInfNative = Pne->UminTrav; +BorneSupNative = Pne->UmaxTrav; +TypeDeVariable = Pne->TypeDeVariableTrav; + +ContrainteInactive = Presolve->ContrainteInactive; +ContrainteBornanteInferieurement = Presolve->ContrainteBornanteInferieurement; +ContrainteBornanteSuperieurement = Presolve->ContrainteBornanteSuperieurement; +ConserverLaBorneSupDuPresolve = Presolve->ConserverLaBorneSupDuPresolve; +ConserverLaBorneInfDuPresolve = Presolve->ConserverLaBorneInfDuPresolve; + +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +TypeDeValeurDeBorneInf = Presolve->TypeDeValeurDeBorneInf; +TypeDeValeurDeBorneSup = Presolve->TypeDeValeurDeBorneSup; + +NbVariablesFixees = 0; +NbLambdaModifies = 0; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + + if ( TypeDeVariable[Var] == ENTIER ) continue; + + TypeBrnPresolve = TypeDeBornePourPresolve[Var]; + TypeBrnNative = TypeDeBorneNative[Var]; + + if ( TypeBrnPresolve == VARIABLE_FIXE ) continue; + NbTermes = 0; + SensCnt = '='; + CntDeLaVariable = -1; + Ai = 0.0; + il = Cdeb[Var]; + while ( il >= 0 ) { + Cnt = NumContrainte[il]; + if ( A[il] != 0.0 ) { + if ( ContrainteInactive[Cnt] == NON_PNE ) { + Ai = A[il]; + NbTermes++; + SensCnt = SensContrainte[Cnt]; + CntDeLaVariable = Cnt; + if ( NbTermes > 1 ) break; + } + } + il = Csui[il]; + } + + if ( NbTermes != 1 ) continue; /* Variable suivante */ + + if ( fabs( Ai ) < PIVOT_MIN_POUR_UN_CALCUL_DE_BORNE ) continue; + + TypeBrn = PRS_ChoisirLaBorneLaPlusContraignantePourLesVariablesDuales( TypeBrnNative, TypeBrnPresolve, + BorneInfPourPresolve[Var], BorneInfNative[Var], + BorneSupPourPresolve[Var], BorneSupNative[Var], + ConserverLaBorneInfDuPresolve[Var], ConserverLaBorneSupDuPresolve[Var], + TypeDeValeurDeBorneInf[Var], TypeDeValeurDeBorneSup[Var] ); + + if ( TypeBrn != VARIABLE_NON_BORNEE && SensCnt == '=' ) { + /* Doubleton ? Si oui on essai d'en faire un singleton non borne */ + TypeBrn = PRS_FabriquerUneVariableNonBorneeAPartirDUneContrainteDoubleton( Pne, Presolve, Var, TypeBrn, CntDeLaVariable ); + } + + if ( TypeBrn == VARIABLE_NON_BORNEE ) { + /* On peut fixer la variable duale de la contrainte ou enlever la variable et la contrainte */ + if ( SensCnt == '=' ) { + # if TRACES == 1 + printf("1- VARIABLE_NON_BORNEE substitution BorneInfPresolve %e BorneSupPresolve %e | BorneInfNative %e BorneSupNative %e\n", + BorneInfPourPresolve[Var],BorneSupPourPresolve[Var],BorneInfNative[Var],BorneSupNative[Var]); + CntS = Presolve->ContrainteBornanteSuperieurement[Var]; + Cnti = Presolve->ContrainteBornanteInferieurement[Var]; + CsvSup = ConserverLaBorneSupDuPresolve[Var]; + CsvInf = ConserverLaBorneInfDuPresolve[Var]; + printf("Contrainte %d CntBornanteSup %d CntBornanteInf %d CsvSup %d CsvInf %d\n",CntDeLaVariable,CntS,Cnti,CsvSup,CsvInf); + if ( CntS >= 0 ) printf("ContrainteInactive[%d] = %d\n",CntS,Presolve->ContrainteInactive[CntS]); + if ( Cnti >= 0 ) printf("ContrainteInactive[%d] = %d\n",Cnti,Presolve->ContrainteInactive[Cnti]); + # endif + PRS_SingletonsSurColonnesSubstituerLaVariable( Presolve, Var, CntDeLaVariable, &NbVariablesFixees ); + } + else { + # if TRACES == 1 + printf("1- VARIABLE_NON_BORNEE calcul de la variable duale\n"); + # endif + PRS_MajVariableDuale( Presolve, CntDeLaVariable, CoutLineaire[Var], Ai, '=', &NbLambdaModifies ); + } + continue; + } + else { + + /* On calcule les meilleures bornes primales sur la variable a l'aide de la contrainte puis on examine les + consequences sur la variable duale */ + PRS_CalculeBorneSurVariableEnFonctionDeLaContrainte( Presolve, CntDeLaVariable, Var, &BorneInfCalculee, &BorneInf, &BorneSupCalculee, &BorneSup ); + + /* On regarde si on a pu ameliorer la borne */ + PRS_MettreAJourLesBornesDUneVariable( Presolve, Var, BorneInfCalculee, BorneInf, CntDeLaVariable, + BorneSupCalculee, BorneSup, CntDeLaVariable, &BorneAmelioree ); + + TypeBrnPresolve = TypeDeBornePourPresolve[Var]; /* Car le type de borne a pu changer lors de la mise a jour des bornes */ + TypeBrn = PRS_ChoisirLaBorneLaPlusContraignantePourLesVariablesDuales( TypeBrnNative, TypeBrnPresolve, + BorneInfPourPresolve[Var], BorneInfNative[Var], + BorneSupPourPresolve[Var], BorneSupNative[Var], + ConserverLaBorneInfDuPresolve[Var], ConserverLaBorneSupDuPresolve[Var], + TypeDeValeurDeBorneInf[Var], TypeDeValeurDeBorneSup[Var] ); + + /* On examine a nouveau les consequence sur les couts reduits */ + if ( TypeBrn == VARIABLE_NON_BORNEE ) { + /* On peut fixer la variable duale de la contrainte ou enlever la variable et la contrainte */ + if ( SensCnt == '=' ) { + # if TRACES == 1 + printf("2- VARIABLE_NON_BORNEE substitution\n"); + # endif + PRS_SingletonsSurColonnesSubstituerLaVariable( Presolve, Var, CntDeLaVariable, &NbVariablesFixees ); + } + else { + # if TRACES == 1 + printf("2- VARIABLE_NON_BORNEE calcul de la variable duale\n"); + # endif + PRS_MajVariableDuale( Presolve, CntDeLaVariable, CoutLineaire[Var], Ai, '=', &NbLambdaModifies ); + } + } + else if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + /* Le singleton sur colonne est borne inferieurement: son cout reduit est >= 0 */ + # if TRACES == 1 + printf("2- VARIABLE_BORNEE_INFERIEUREMENT calcul d'une borne sur la variable duale\n"); + # endif + PRS_MajVariableDuale( Presolve, CntDeLaVariable, CoutLineaire[Var], Ai, '>', &NbLambdaModifies ); + } + else if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + /* Le singleton sur colonne est borne superieurement: son cout reduit est <= 0 */ + # if TRACES == 1 + printf("2- VARIABLE_BORNEE_SUPERIEUREMENT calcul d'une borne sur la variable duale\n"); + # endif + PRS_MajVariableDuale( Presolve, CntDeLaVariable, CoutLineaire[Var], Ai, '<', &NbLambdaModifies ); + } + } +} + +# if VERBOSE_PRS == 1 + printf("-> Colonne singleton: variables supprimees %d / contraintes supprimees %d / variables duales modifiees %d / total %d\n", + NbVariablesFixees,NbVariablesFixees,NbLambdaModifies,( 2 * NbVariablesFixees ) + NbLambdaModifies); +# endif + +*NbModifications = ( 2 * NbVariablesFixees ) + NbLambdaModifies; + +return; +} diff --git a/src/ext/Sirius_Solver/presolve/prs_singleton_ligne.c b/src/ext/Sirius_Solver/presolve/prs_singleton_ligne.c new file mode 100644 index 0000000000..4a93faacca --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_singleton_ligne.c @@ -0,0 +1,249 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On regarde si la resolution de certaines equations est + triviale. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PRS_SingletonsSurLignes( PRESOLVE * Presolve, int * NbModifications ) +{ +int Cnt; int il ; int ilMax; int ilNonFix; int NbNonFix; int VarNonFix; int Var; +long double S; long double X; PROBLEME_PNE * Pne; int * Mdeb; int * NbTerm; int * Nuvar; +int TypeBrn; double * A; double * B; char * ContrainteInactive; char * SensContrainte; +int NombreDeContraintes; double * BorneInfPourPresolve; double * BorneSupPourPresolve; +int * TypeDeBornePourPresolve; double * ValeurDeXPourPresolve; int * TypeDeVariable; +int * ContrainteBornanteSuperieurement; int * ContrainteBornanteInferieurement; +int NombreDeContraintesSupprimees; int NombreDeVariablesFixees; +int NombreDeBornesModifiees; char BorneAmelioree; char * TypeDeValeurDeBorneInf; +char * TypeDeValeurDeBorneSup; int * NumeroDeLaContrainteSingleton; int * VariableDeLaContrainteSingleton; +char * TypeDOperationDePresolve; int * IndexDansLeTypeDOperationDePresolve; +double * SecondMembreDeLaContrainteSingleton; int * CorrespondanceCntPneCntEntree; + +*NbModifications = 0; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +if ( Pne->NbLignesSingleton >= Pne->NombreDeContraintesTrav ) return; +if ( Pne->NombreDOperationsDePresolve >= Pne->TailleTypeDOperationDePresolve ) return; + +ContrainteInactive = Presolve->ContrainteInactive; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +TypeDeValeurDeBorneInf = Presolve->TypeDeValeurDeBorneInf; +TypeDeValeurDeBorneSup = Presolve->TypeDeValeurDeBorneSup; + +ContrainteBornanteSuperieurement = Presolve->ContrainteBornanteSuperieurement; +ContrainteBornanteInferieurement = Presolve->ContrainteBornanteInferieurement; + +CorrespondanceCntPneCntEntree = Pne->CorrespondanceCntPneCntEntree; +TypeDeVariable = Pne->TypeDeVariableTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +B = Pne->BTrav; +SensContrainte = Pne->SensContrainteTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; + +TypeDOperationDePresolve = Pne->TypeDOperationDePresolve; +IndexDansLeTypeDOperationDePresolve = Pne->IndexDansLeTypeDOperationDePresolve; +NumeroDeLaContrainteSingleton = Pne->NumeroDeLaContrainteSingleton; +VariableDeLaContrainteSingleton = Pne->VariableDeLaContrainteSingleton; +SecondMembreDeLaContrainteSingleton = Pne->SecondMembreDeLaContrainteSingleton; + +NombreDeContraintesSupprimees = 0; +NombreDeVariablesFixees = 0; +NombreDeBornesModifiees = 0; + +/* On regarde si on peut resoudre certaines contraintes "a la main" */ + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + + if ( ContrainteInactive[Cnt] == OUI_PNE ) continue; + if ( Pne->NbLignesSingleton >= NombreDeContraintes ) return; + if ( Pne->NombreDOperationsDePresolve >= Pne->TailleTypeDOperationDePresolve ) return; + + S = 0.; + NbNonFix = 0; + ilNonFix = -1; + VarNonFix = -1; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( A[il] != 0.0 ) { + Var = Nuvar[il]; + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) { + /* La variable est fixee */ + S += A[il] * ValeurDeXPourPresolve[Var]; + } + else { + NbNonFix++; + VarNonFix = Var; + ilNonFix = il; + if ( NbNonFix > 1 ) break; + } + } + il++; + } + + if ( NbNonFix != 1 ) continue; + if ( fabs( A[ilNonFix] ) < PIVOT_MIN_POUR_UN_CALCUL_DE_BORNE ) continue; + + /* Si la contrainte n'a qu'une seule variable on peut resoudre directement */ + TypeBrn = TypeDeBornePourPresolve[VarNonFix]; + X = ( (long double) B[Cnt] - S ) / (long double) A[ilNonFix]; + + if ( SensContrainte[Cnt] == '=' ) { + /* Test d'admissibilite */ + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( X < BorneInfPourPresolve[VarNonFix] - SEUIL_DADMISSIBILITE ) { + # if VERBOSE_PRS == 1 + printf("*** Ligne singleton -> La contrainte %d ne peut pas etre satisfaite\n",Cnt); + printf(" Variable %d BorneInfPourPresolve %e X %e \n", + VarNonFix,BorneInfPourPresolve[VarNonFix],(double) X); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; return; + } + } + else if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + if ( X > BorneSupPourPresolve[VarNonFix] + SEUIL_DADMISSIBILITE ) { + # if VERBOSE_PRS == 1 + printf("*** Ligne singleton -> La contrainte %d ne peut pas etre satisfaite\n",Cnt); + printf(" Variable %d X %e BorneSupPourPresolve %e\n", + VarNonFix,(double) X,BorneSupPourPresolve[VarNonFix]); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; return; + } + } + else if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( X < BorneInfPourPresolve[VarNonFix] - SEUIL_DADMISSIBILITE || X > BorneSupPourPresolve[VarNonFix] + SEUIL_DADMISSIBILITE ) { + # if VERBOSE_PRS == 1 + printf("*** Ligne singleton -> La contrainte %d ne peut pas etre satisfaite\n",Cnt); + printf(" Variable %d BorneInfPourPresolve %e X %e BorneSupPourPresolve %e\n", + VarNonFix,BorneInfPourPresolve[VarNonFix],(double) X,BorneSupPourPresolve[VarNonFix]); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; return; + } + } + if ( TypeDeVariable[VarNonFix] == ENTIER ) { + if ( fabs( X ) > MARGE_DINFAISABILITE && fabs( 1 - X ) > MARGE_DINFAISABILITE ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; return; + } + } + + # if TRACES == 1 + printf("Ligne singleton fixation de la variable %d a %e grace a la contrainte d'egalite %d\n",VarNonFix,(double) X,Cnt); + # endif + + /* Infos pour le postsolve */ + TypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = SUPPRESSION_LIGNE_SINGLETON; + IndexDansLeTypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = Pne->NbLignesSingleton; + Pne->NombreDOperationsDePresolve++; + NumeroDeLaContrainteSingleton[Pne->NbLignesSingleton] = CorrespondanceCntPneCntEntree[Cnt]; + VariableDeLaContrainteSingleton[Pne->NbLignesSingleton] = VarNonFix; + SecondMembreDeLaContrainteSingleton[Pne->NbLignesSingleton] = X; + Pne->NbLignesSingleton++; + /* */ + + PRS_FixerUneVariableAUneValeur( Presolve, VarNonFix, (double) X ); + NombreDeVariablesFixees++; + + /* On peut desactiver meme si elle est bornante car toutes les variables de la contrainte + deviennent fixes */ + PRS_DesactiverContrainte( Presolve, Cnt ); + NombreDeContraintesSupprimees++; + + } + else { /* la contraintes est forcement < */ + if ( A[ilNonFix] > 0. ) { + /* X est une borne sup candidate */ + PRS_MettreAJourLesBornesDUneVariable( Presolve, VarNonFix, NON_PNE, -LINFINI_PNE, -1, + OUI_PNE, (double) X, Cnt, &BorneAmelioree ); + if ( BorneAmelioree == OUI_PNE ) { + NombreDeBornesModifiees++; + /* Infos pour le postsolve */ + TypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = SUPPRESSION_LIGNE_SINGLETON; + IndexDansLeTypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = Pne->NbLignesSingleton; + Pne->NombreDOperationsDePresolve++; + NumeroDeLaContrainteSingleton[Pne->NbLignesSingleton] = CorrespondanceCntPneCntEntree[Cnt]; + VariableDeLaContrainteSingleton[Pne->NbLignesSingleton] = VarNonFix; + SecondMembreDeLaContrainteSingleton[Pne->NbLignesSingleton] = X; + Pne->NbLignesSingleton++; + /* */ + } + /* Soit on a mis a jour la borne et alors on n'a plus besoin de la contrainte. Soit on ne l'a pas + mise a jour et on n'a plus non plus besoin de la contrainte car la borne de la variable etait plus + restrictive que la contrainte */ + PRS_DesactiverContrainte( Presolve, Cnt ); + NombreDeContraintesSupprimees++; + } + else { + /* X est une borne inf candidate */ + PRS_MettreAJourLesBornesDUneVariable( Presolve, VarNonFix, OUI_PNE, (double) X, Cnt, + NON_PNE, LINFINI_PNE, -1, &BorneAmelioree ); + if ( BorneAmelioree == OUI_PNE ) { + NombreDeBornesModifiees++; + /* Infos pour le postsolve */ + TypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = SUPPRESSION_LIGNE_SINGLETON; + IndexDansLeTypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = Pne->NbLignesSingleton; + Pne->NombreDOperationsDePresolve++; + + NumeroDeLaContrainteSingleton[Pne->NbLignesSingleton] = CorrespondanceCntPneCntEntree[Cnt]; + VariableDeLaContrainteSingleton[Pne->NbLignesSingleton] = VarNonFix; + SecondMembreDeLaContrainteSingleton[Pne->NbLignesSingleton] = X; + Pne->NbLignesSingleton++; + /* */ + } + /* Soit on a mis a jour la borne et alors on n'a plus besoin de la contrainte. Soit on ne l'a pas + mise a jour et on n'a plus non plus besoin de la contrainte car la borne de la variable etait plus + restrictive que la contrainte */ + PRS_DesactiverContrainte( Presolve, Cnt ); + NombreDeContraintesSupprimees++; + } + } +} + +#if VERBOSE_PRS + printf("-> Lignes singleton: contraintes supprimees %d / bornes modifiees %d / variables fixees %d / total %d\n", + NombreDeContraintesSupprimees,NombreDeBornesModifiees,NombreDeVariablesFixees, + NombreDeContraintesSupprimees+NombreDeBornesModifiees+NombreDeVariablesFixees); +#endif + +*NbModifications = NombreDeContraintesSupprimees + NombreDeVariablesFixees + NombreDeBornesModifiees; + +return; +} + diff --git a/src/ext/Sirius_Solver/presolve/prs_substituer_variables.c b/src/ext/Sirius_Solver/presolve/prs_substituer_variables.c new file mode 100644 index 0000000000..fd455a700c --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_substituer_variables.c @@ -0,0 +1,579 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On tente de faire des substitutions de variables grace aux + contraintes d'égalite ne comprenant que 2 termes. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES 0 + +# define ATILDE_MIN 1.e-5 +# define ATILDE_MAX 1.e+5 + +void PRS_CalculerLesNouvellesBornesDeLaVariableRestante( PRESOLVE * , int ,int , double , double ); + +/*----------------------------------------------------------------------------*/ + +void PRS_SubstituerVariables( PRESOLVE * Presolve, int * NbModifications ) +{ +int Cnt; int Var1; int Var2; double CoeffDeVar1; double CoeffDeVar2; int il; +int ilMax; char SubstitutionPossible; int il1; int il2; PROBLEME_PNE * Pne; +int NombreDeContraintes; char * ContrainteInactive; char * SensContrainte; +int * Mdeb; int * NbTerm; int * Nuvar; int * TypeDeBornePourPresolve; +int * TypeDeVariableNative; double * A; double * BorneInfPourPresolve; +double * BorneSupPourPresolve; double * B; double BTilde; double ATilde; +double BCnt; char * ConserverLaBorneSupDuPresolve; char * ConserverLaBorneInfDuPresolve; +double S; double * ValeurDeXPourPresolve; double X; double * CoutLineaire; +int * NumeroDesVariablesSubstituees; double * CoutDesVariablesSubstituees; +double * ValeurDeLaConstanteDeSubstitution; int * IndiceDebutVecteurDeSubstitution; +int * NbTermesVecteurDeSubstitution; double * CoeffDeSubstitution; +int * NumeroDeVariableDeSubstitution; int * IndexDansLeTypeDOperationDePresolve; +char * TypeDOperationDePresolve; int * ContrainteDeLaSubstitution; +int * CorrespondanceCntPneCntEntree; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +*NbModifications = 0; + +return; + +if ( Pne->NbVariablesSubstituees >= Pne->NombreDeVariablesTrav - 1 ) return; +if ( Pne->NombreDOperationsDePresolve >= Pne->TailleTypeDOperationDePresolve ) return; + +CoutLineaire = Pne->LTrav; +TypeDeVariableNative = Pne->TypeDeVariableTrav; +NombreDeContraintes = Pne->NombreDeContraintesTrav; +SensContrainte = Pne->SensContrainteTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +B = Pne->BTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +CorrespondanceCntPneCntEntree = Pne->CorrespondanceCntPneCntEntree; + +ContrainteInactive = Presolve->ContrainteInactive; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +ConserverLaBorneSupDuPresolve = Presolve->ConserverLaBorneSupDuPresolve; +ConserverLaBorneInfDuPresolve = Presolve->ConserverLaBorneInfDuPresolve; + +TypeDOperationDePresolve = Pne->TypeDOperationDePresolve; +IndexDansLeTypeDOperationDePresolve = Pne->IndexDansLeTypeDOperationDePresolve; + +IndiceDebutVecteurDeSubstitution = Pne->IndiceDebutVecteurDeSubstitution; +NumeroDesVariablesSubstituees = Pne->NumeroDesVariablesSubstituees; +CoutDesVariablesSubstituees = Pne->CoutDesVariablesSubstituees; +ContrainteDeLaSubstitution = Pne->ContrainteDeLaSubstitution; +ValeurDeLaConstanteDeSubstitution = Pne->ValeurDeLaConstanteDeSubstitution; +NbTermesVecteurDeSubstitution = Pne->NbTermesVecteurDeSubstitution; +CoeffDeSubstitution = Pne->CoeffDeSubstitution; +NumeroDeVariableDeSubstitution = Pne->NumeroDeVariableDeSubstitution; + +for ( Cnt = 0 ; Cnt < NombreDeContraintes; Cnt++ ) { + + if ( ContrainteInactive[Cnt] == OUI_PNE ) continue; + + if ( SensContrainte[Cnt] != '=' ) continue; + /* On recherche les contraintes d'egalite a 2 termes. Etude des intervalles + de variation de chacune des 2 variables. Il est necessaire de compter les termes, + en effet, pour gagner du temps, lorsqu'une variable est substituee, elle n'est pas + explicitement supprimee de la contrainte mais son coefficient est mis ŕ 0 ce qui + revient au meme. On ne substitue pas une variable entiere par quelque chose + d'autre */ + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + il1 = -1; + il2 = -1; + SubstitutionPossible = OUI_PNE; + S = 0.0; + while ( il < ilMax ) { + if ( A[il] != 0.0 ) { + + /* Attention ci dessous on passe les variables fixes dans le second membre or les tables + de sortie ne sont pas pretes pour un second membre modifie. Il faudra faire la modif */ + + if ( TypeDeBornePourPresolve[Nuvar[il]] == VARIABLE_FIXE ) { + S += A[il] * ValeurDeXPourPresolve[Nuvar[il]]; + } + else { + if ( il1 == -1 ) il1 = il; + else if ( il2 == -1 ) il2 = il; + else { + SubstitutionPossible = NON_PNE; + break; + } + } + } + il++; + } + if ( SubstitutionPossible == NON_PNE ) continue; + if ( il1 < 0 || il2 < 0 ) continue; + Var1 = Nuvar[il1]; + Var2 = Nuvar[il2]; + + if ( TypeDeBornePourPresolve[Var1] == VARIABLE_FIXE || TypeDeBornePourPresolve[Var2] == VARIABLE_FIXE ) continue; + + CoeffDeVar1 = A[il1]; + CoeffDeVar2 = A[il2]; + + if ( fabs( CoeffDeVar1 ) < ZERO_PRESOLVE ) continue; + if ( fabs( CoeffDeVar2 ) < ZERO_PRESOLVE ) continue; + + BCnt = B[Cnt] - S; + + /* On essaie d'exprimer Var1 en fonction de Var2 */ + + if ( TypeDeVariableNative[Var1] == ENTIER && TypeDeVariableNative[Var2] != ENTIER ) goto TestVar2; /* On ne peut pas remplacer */ + + BTilde = BCnt / CoeffDeVar1; + ATilde = CoeffDeVar2 / CoeffDeVar1; + + /* Si les nombres sont trop differents on ne prend pas a cause des imprecisions */ + if ( fabs( ATilde ) < ATILDE_MIN || fabs( ATilde ) > ATILDE_MAX ) goto TestVar2; + + if ( TypeDeVariableNative[Var1] == ENTIER && TypeDeVariableNative[Var2] == ENTIER ) { + if ( ceil( BTilde ) - BTilde > 1.e-10 && BTilde - floor( BTilde ) > 1.e-10 ) goto TestVar2; /* On ne peut pas remplacer */ + if ( ceil( ATilde ) - ATilde > 1.e-10 && ATilde - floor( ATilde ) > 1.e-10 ) goto TestVar2; /* On ne peut pas remplacer */ + } + + if ( PRS_TestSubstituerUneVariable( Presolve, Var1, Var2, ATilde, BTilde, Cnt ) == NON_PNE ) goto TestVar2; + + # if TRACES == 1 + printf("1- Variable %d substituee par la %d et mise en inactivite de la contrainte %d ATilde %lf BTilde %lf\n",Var1,Var2,Cnt,ATilde,BTilde); + # endif + + if ( Pne->NbVariablesSubstituees >= Pne->NombreDeVariablesTrav - 1 ) return; + if ( Pne->NombreDOperationsDePresolve >= Pne->TailleTypeDOperationDePresolve ) return; + + TypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = SUBSITUTION_DE_VARIABLE; + IndexDansLeTypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = Pne->NbVariablesSubstituees; + Pne->NombreDOperationsDePresolve++; + + IndiceDebutVecteurDeSubstitution [Pne->NbVariablesSubstituees] = Pne->IndexLibreVecteurDeSubstitution; + NumeroDesVariablesSubstituees [Pne->NbVariablesSubstituees] = Var1; + CoutDesVariablesSubstituees [Pne->NbVariablesSubstituees] = CoutLineaire[Var1]; + ContrainteDeLaSubstitution [Pne->NbVariablesSubstituees] = CorrespondanceCntPneCntEntree[Cnt]; + ValeurDeLaConstanteDeSubstitution[Pne->NbVariablesSubstituees] = BTilde; + NbTermesVecteurDeSubstitution [Pne->NbVariablesSubstituees] = 1; + CoeffDeSubstitution [Pne->IndexLibreVecteurDeSubstitution] = -ATilde; + NumeroDeVariableDeSubstitution[Pne->IndexLibreVecteurDeSubstitution] = Var2; + Pne->IndexLibreVecteurDeSubstitution++; + Pne->NbVariablesSubstituees++; + + ConserverLaBorneSupDuPresolve[Var2] = OUI_PNE; + ConserverLaBorneInfDuPresolve[Var2] = OUI_PNE; + + ContrainteInactive[Cnt] = OUI_PNE; + *NbModifications = *NbModifications + 1; + + PRS_SubstituerUneVariable( Presolve, Var1, Var2, ATilde, BTilde ); + + /* Si necessaire on ajuste les bornes sur Var2 en fonction des bornes sur Var1 */ + ATilde = -ATilde; + PRS_CalculerLesNouvellesBornesDeLaVariableRestante( Presolve, Var1, Var2, ATilde, BTilde); + + CoutLineaire[Var1] = 0.0; + X = 0.; /* Pas d'importance mais ainsi on n'a pas besoin de la supprimer de la liste des + variables ni de la supprimer des contraintes */ + PRS_FixerUneVariableAUneValeur( Presolve, Var1, X ); + + continue; + + TestVar2: + + /* On essaie d'exprimer Var2 en fonction de Var1 */ + if ( TypeDeVariableNative[Var2] == ENTIER && TypeDeVariableNative[Var1] != ENTIER ) continue; /* On ne peut pas remplacer */ + + BTilde = BCnt / CoeffDeVar2; + ATilde = CoeffDeVar1 / CoeffDeVar2; + + /* Si les nombres sont trop differents on ne prend pas a cause des imprecisions */ + if ( fabs( ATilde ) < ATILDE_MIN || fabs( ATilde ) > ATILDE_MAX ) continue; + + if ( TypeDeVariableNative[Var1] == ENTIER && TypeDeVariableNative[Var2] == ENTIER ) { + if ( ceil( BTilde ) - BTilde > 1.e-10 && BTilde - floor( BTilde ) > 1.e-10 ) continue; /* On ne peut pas remplacer */ + if ( ceil( ATilde ) - ATilde > 1.e-10 && ATilde - floor( ATilde ) > 1.e-10 ) continue; /* On ne peut pas remplacer */ + } + + if ( PRS_TestSubstituerUneVariable( Presolve, Var2, Var1, ATilde, BTilde, Cnt ) == NON_PNE ) continue; + + # if TRACES == 1 + printf("2- Variable %d substituee par la %d et mise en inactivite de la contrainte %d ATilde %lf BTilde %lf\n",Var2,Var1,Cnt,ATilde,BTilde); + # endif + + if ( Pne->NbVariablesSubstituees >= Pne->NombreDeVariablesTrav - 1 ) return; + if ( Pne->NombreDOperationsDePresolve >= Pne->TailleTypeDOperationDePresolve ) return; + + TypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = SUBSITUTION_DE_VARIABLE; + IndexDansLeTypeDOperationDePresolve[Pne->NombreDOperationsDePresolve] = Pne->NbVariablesSubstituees; + Pne->NombreDOperationsDePresolve++; + + IndiceDebutVecteurDeSubstitution [Pne->NbVariablesSubstituees] = Pne->IndexLibreVecteurDeSubstitution; + NumeroDesVariablesSubstituees [Pne->NbVariablesSubstituees] = Var2; + CoutDesVariablesSubstituees [Pne->NbVariablesSubstituees] = CoutLineaire[Var2]; + ContrainteDeLaSubstitution [Pne->NbVariablesSubstituees] = CorrespondanceCntPneCntEntree[Cnt]; + ValeurDeLaConstanteDeSubstitution[Pne->NbVariablesSubstituees] = BTilde; + NbTermesVecteurDeSubstitution [Pne->NbVariablesSubstituees] = 1; + CoeffDeSubstitution [Pne->IndexLibreVecteurDeSubstitution] = -ATilde; + NumeroDeVariableDeSubstitution[Pne->IndexLibreVecteurDeSubstitution] = Var1; + Pne->IndexLibreVecteurDeSubstitution++; + Pne->NbVariablesSubstituees++; + + ConserverLaBorneSupDuPresolve[Var1] = OUI_PNE; + ConserverLaBorneInfDuPresolve[Var1] = OUI_PNE; + + ContrainteInactive[Cnt] = OUI_PNE; + *NbModifications = *NbModifications + 1; + + PRS_SubstituerUneVariable( Presolve, Var2, Var1, ATilde, BTilde ); + + /* Si necessaire on ajuste les bornes sur Var1 en fonction des bornes sur Var2 */ + ATilde = -ATilde; + PRS_CalculerLesNouvellesBornesDeLaVariableRestante( Presolve, Var2, Var1, ATilde, BTilde); + + CoutLineaire[Var2] = 0.0; + X = 0.; /* Pas d'importance mais ainsi on n'a pas besoin de la supprimer de la liste des + variables ni de la supprimer des contraintes */ + PRS_FixerUneVariableAUneValeur( Presolve, Var2, X ); + + continue; + +} + +#if VERBOSE_PRS + printf("-> Nombre de contraintes supprimees par substitution de variables %d\n",*NbModifications); +#endif + +if ( *NbModifications > 0 && 0 ) { + PRS_ClasserVariablesDansContraintes( Presolve ); /* Ca n'a plus d'utilite */ + PNE_ConstruireLeChainageDeLaTransposee( Pne ); +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_CalculerLesNouvellesBornesDeLaVariableRestante( PRESOLVE * Presolve, + int VarSubstituee, + int VarRestante, + double ATilde, + double BTilde ) +{ +int TypeBorne; char XmaxExiste; char XminExiste; double Xmax; double Xmin; +double X; PROBLEME_PNE * Pne; + +Pne = Presolve->ProblemePneDuPresolve; + +TypeBorne = Presolve->TypeDeBornePourPresolve[VarSubstituee]; +XmaxExiste = NON_PNE; +XminExiste = NON_PNE; +Xmin = 0; +Xmax = 0; +if ( ATilde > 0.0 ) { + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Xmax = ( Presolve->BorneSupPourPresolve[VarSubstituee] - BTilde ) / ATilde; + XmaxExiste = OUI_PNE; + } + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) { + Xmin = ( Presolve->BorneInfPourPresolve[VarSubstituee] - BTilde ) / ATilde; + XminExiste = OUI_PNE; + } +} +else { + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) { + Xmax = ( Presolve->BorneInfPourPresolve[VarSubstituee] - BTilde ) / ATilde; + XmaxExiste = OUI_PNE; + } + if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Xmin = ( Presolve->BorneSupPourPresolve[VarSubstituee] - BTilde ) / ATilde; + XminExiste = OUI_PNE; + } +} + +TypeBorne = Presolve->TypeDeBornePourPresolve[VarRestante]; +if ( XminExiste == OUI_PNE ) { + if ( TypeBorne == VARIABLE_NON_BORNEE || TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Presolve->BorneInfPourPresolve[VarRestante] = Xmin; + if ( TypeBorne == VARIABLE_NON_BORNEE ) TypeBorne = VARIABLE_BORNEE_INFERIEUREMENT; + else if ( TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) TypeBorne = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( Xmin > Presolve->BorneInfPourPresolve[VarRestante] ) { + Presolve->BorneInfPourPresolve[VarRestante] = Xmin; + } + } +} +if ( XmaxExiste == OUI_PNE ) { + if ( TypeBorne == VARIABLE_NON_BORNEE || TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) { + Presolve->BorneSupPourPresolve[VarRestante] = Xmax; + if ( TypeBorne == VARIABLE_NON_BORNEE ) TypeBorne = VARIABLE_BORNEE_SUPERIEUREMENT; + else if ( TypeBorne == VARIABLE_BORNEE_INFERIEUREMENT ) TypeBorne = VARIABLE_BORNEE_DES_DEUX_COTES; + } + else if ( TypeBorne == VARIABLE_BORNEE_DES_DEUX_COTES || TypeBorne == VARIABLE_BORNEE_SUPERIEUREMENT ) { + if ( Xmax < Presolve->BorneSupPourPresolve[VarRestante] ) { + Presolve->BorneSupPourPresolve[VarRestante] = Xmax; + } + } +} + +Presolve->TypeDeBornePourPresolve[VarRestante] = TypeBorne; +if ( Pne->TypeDeVariableTrav[VarRestante] == ENTIER ) { + if ( Presolve->BorneSupPourPresolve[VarRestante] < Pne->UmaxTrav[VarRestante] - 1.e-7 && + Presolve->BorneInfPourPresolve[VarRestante] > Pne->UminTrav[VarRestante] + 1.e-7 ) { + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + if ( Presolve->BorneSupPourPresolve[VarRestante] < Pne->UmaxTrav[VarRestante] - 1.e-7 ) { + X = Pne->UminTrav[VarRestante]; + PRS_FixerUneVariableAUneValeur( Presolve, VarRestante, X ); + } + else if ( Presolve->BorneInfPourPresolve[VarRestante] > Pne->UminTrav[VarRestante] + 1.e-7 ) { + X = Pne->UmaxTrav[VarRestante]; + PRS_FixerUneVariableAUneValeur( Presolve, VarRestante, X ); + } +} + +/* 14/01/2015: Il faut reajuster ConserverLaBorneSupDuPresolve et ConserverLaBorneInfDuPresolve */ +if ( Presolve->TypeDeBornePourPresolve[VarRestante] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Presolve->ConserverLaBorneSupDuPresolve[VarRestante] = NON_PNE; +} +else if ( Presolve->TypeDeBornePourPresolve[VarRestante] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + Presolve->ConserverLaBorneInfDuPresolve[VarRestante] = NON_PNE; +} +else if ( Presolve->TypeDeBornePourPresolve[VarRestante] == VARIABLE_NON_BORNEE ) { + Presolve->ConserverLaBorneSupDuPresolve[VarRestante] = NON_PNE; + Presolve->ConserverLaBorneInfDuPresolve[VarRestante] = NON_PNE; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +char PRS_TestSubstituerUneVariable( PRESOLVE * Presolve, + int VarSubstituee, + int VarRestante, + double ATilde, + double BTilde, + int CntSubstitution ) +{ +int il ; double Ai; int Cnt; int ilCnt; int ilMaxCnt; char VarRestanteTrouvee; +double X ; PROBLEME_PNE * Pne; int * Cdeb; int * NumContrainte; int * Mdeb; +int * NbTerm; int * Nuvar; int * Csui; double * A; char * ContrainteInactive; +double PlusGrandTerme; double PlusPetitTerme; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +# if TRACES != 1 + CntSubstitution = -1; /* Pour ne pas avoir de warning a la compilation */ +# endif + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +PlusGrandTerme = Pne->PlusGrandTerme; +PlusPetitTerme = Pne->PlusPetitTerme; + +ContrainteInactive = Presolve->ContrainteInactive; + +BTilde = 0.; /* Pour ne pas avoir de warning a la compilation */ + +/* On balaye la colonne de la variable substituee */ +il = Cdeb[VarSubstituee]; +while ( il >= 0 ) { + Cnt = NumContrainte[il]; + if ( ContrainteInactive[Cnt] == OUI_PNE ) goto Next_il; + VarRestanteTrouvee = NON_PNE; + Ai = A[il]; + /* On balaye la contrainte pour faire les actions necessaires au cas ou + la variable VarRestante y serait deja presente */ + ilCnt = Mdeb[Cnt]; + ilMaxCnt = ilCnt + NbTerm[Cnt]; + while ( ilCnt < ilMaxCnt ) { + if ( Nuvar[ilCnt] == VarRestante ) { + X = fabs( A[ilCnt] - (Ai * ATilde) ); + if ( X > PlusGrandTerme || (X < PlusPetitTerme && X != 0.0 ) ) { + /* On refuse la substitution de variable */ + # if TRACES == 1 + printf("refus 1 car Cnt %d CntSubstitution %d X = %e ATrav = %e Ai = %e ATilde = %e \n",Cnt,CntSubstitution,X,Pne->ATrav[ilCnt],Ai,ATilde); + # endif + return( NON_PNE ); + } + VarRestanteTrouvee = OUI_PNE; + break; + } + ilCnt++; + } + if ( VarRestanteTrouvee == NON_PNE ) { + X = fabs( -Ai * ATilde ); + if ( X > PlusGrandTerme || (X < PlusPetitTerme && X != 0.0 ) ) { + /* On refuse la substitution de variable */ + # if TRACES == 1 + printf("refus 2 car Cnt %d CntSubstitution %d X = %e Ai = %e ATilde = %e \n",Cnt,CntSubstitution,X,Ai,ATilde); + # endif + return( NON_PNE ); + } + } + Next_il: + il = Csui[il]; +} + +return( OUI_PNE ); +} + +/*----------------------------------------------------------------------------*/ + +void PRS_SubstituerUneVariable( PRESOLVE * Presolve, + int VarSubstituee, + int VarRestante, + double ATilde, + double BTilde ) +{ +int il ; long double Ai ; int Cnt; int ilCnt; int ilMaxCnt; char VarRestanteTrouvee; +int ilR; int ilPrec; PROBLEME_PNE * Pne; int * Cdeb; int * NumContrainte; +int * Mdeb; int * NbTerm; int * Nuvar; int * Csui; double * A; double * B; +char * ContrainteInactive; double * CoutLineaire; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +/* On balaye la colonne de la variable substituee */ + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +CoutLineaire = Pne->LTrav; +NumContrainte = Pne->NumContrainteTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; +B = Pne->BTrav; +ContrainteInactive = Presolve->ContrainteInactive; + +il = Cdeb[VarSubstituee]; +while ( il >= 0 ) { + Cnt = NumContrainte[il]; + VarRestanteTrouvee = NON_PNE; + /* Pas de substitution sur des contraintes inactives */ + Ai = (long double) A[il]; + if ( ContrainteInactive[Cnt] != OUI_PNE && Ai != 0.0 ) { + /* On balaye la contrainte pour faire les actions necessaires au cas ou + la variable VarRestante y serait deja presente */ + ilCnt = Mdeb[Cnt]; + ilMaxCnt = ilCnt + NbTerm[Cnt]; + while ( ilCnt < ilMaxCnt ) { + if ( Nuvar[ilCnt] == VarRestante ) { + A[ilCnt] -= Ai * (long double) ATilde; + VarRestanteTrouvee = OUI_PNE; + break; + } + ilCnt++; + } + B[Cnt] -= Ai * (long double) BTilde; + } + + ilPrec = il; + il = Csui[il]; + + if ( VarRestanteTrouvee == NON_PNE && ContrainteInactive[Cnt] != OUI_PNE && Ai != 0.0 ) { + Nuvar[ilPrec] = VarRestante; + A[ilPrec] = -Ai * (long double) ATilde; + /* Attention comme on a change la colonne d'un terme il faut modifier le chainage + de la colonne VarRestante */ + ilR = Cdeb[VarRestante]; + Cdeb[VarRestante] = ilPrec; + Csui[ilPrec] = ilR; + } + else { + /* On peut mettre le coefficient de la variable substituee ŕ 0 s'il y avait la + variable restante dans la contrainte */ + A[ilPrec] = 0.; + } +} + +CoutLineaire[VarRestante] -= CoutLineaire[VarSubstituee] * ATilde; + +Pne->Z0 += CoutLineaire[VarSubstituee] * BTilde; + +Cdeb[VarSubstituee] = -1; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_ClasserVariablesDansContraintes( PRESOLVE * Presolve ) +{ + +int Cnt; char OnContinue; int NombreDeContraintesTrav; int ilDeb; int il; +int ilMax; int Var1; double A1; int * MdebTrav; int * NbTermTrav; +int * NuvarTrav; double * ATrav; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NombreDeContraintesTrav = Pne->NombreDeContraintesTrav; + +MdebTrav = Pne->MdebTrav; +NbTermTrav = Pne->NbTermTrav; +NuvarTrav = Pne->NuvarTrav; +ATrav = Pne->ATrav; + +for ( Cnt = 0 ; Cnt < NombreDeContraintesTrav ; Cnt++ ) { + ilDeb = MdebTrav[Cnt]; + ilMax = ilDeb + NbTermTrav[Cnt]; + ilMax--; + OnContinue = OUI_PNE; + while ( OnContinue == OUI_PNE ) { + OnContinue = NON_PNE; + il = ilDeb; + while ( il < ilMax ) { + if ( NuvarTrav[il] > NuvarTrav[il+1] ) { + OnContinue = OUI_PNE; + Var1 = NuvarTrav[il]; + A1 = ATrav[il]; + NuvarTrav[il] = NuvarTrav[il+1]; + ATrav [il] = ATrav[il+1]; + NuvarTrav[il+1] = Var1; + ATrav [il+1] = A1; + } + il++; + } + } +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/presolve/prs_substituer_variables_non_bornees.c b/src/ext/Sirius_Solver/presolve/prs_substituer_variables_non_bornees.c new file mode 100644 index 0000000000..5b3259902c --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_substituer_variables_non_bornees.c @@ -0,0 +1,493 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Substitution des variables non bornees. La routine n'est + eventuellement utilisee qu'une seule fois au debut du presolve. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# define PIVOT_MIN 1.e-5 +# define RAPPORT_MIN 1.e-2 + +void PRS_SubstitutionDUneVariableNonBornee( PRESOLVE * , int , int , double , double * , int * , char * , + int * , int * , int , int * , char * ); + +/*----------------------------------------------------------------------------*/ +/* Important: ne peut etre utilise qu'une seule fois tout au debut du presolve */ + +void PRS_SubstitutionDUneVariableNonBornee( PRESOLVE * Presolve, + int CntDeSubstitution, + int VarSubstituee, + double Pivot, + double * LignePivot, + int * DernierIndexDispo, + char * T, + int * NbContraintesParColonne, + int * NbContraintesEgaliteParColonne, + int NbTermesColonnePivot, + int * ContraintesDeLaColonnePivot, + char * ContrainteModifiee + ) +{ +int il2 ; int il2Max; int ic; int Cnt; double CoeffPivot; int Var; int i; +double BDeCntDeSubstitution; int NombreDeContraintesImpactees; int NbTermesLignePivot; +int Nn; int Nb; int il1; int il1Max; int icPrec; char Flag; PROBLEME_PNE * Pne; + +return; /* Ne pas utiliser */ + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +BDeCntDeSubstitution = Pne->BTrav[CntDeSubstitution]; +NombreDeContraintesImpactees = 0; +NbTermesLignePivot = Pne->NbTermTrav[CntDeSubstitution]; /* On y a deja supprime le terme pivot */ + +/* Remarque: il faut conserver Pne-> pour eviter les pb lies aux redimensionnements */ +for ( i = 0 ; i < NbTermesColonnePivot ; i++ ) { + Cnt = ContraintesDeLaColonnePivot[i]; + ContrainteModifiee[Cnt] = OUI_PNE; + /* Remarque: toutes les contraintes ayant servi a une substitution on deja ete dechainees */ + + /* Recherche du terme de la ligne qui se trouve dans la colonne pivot */ + Flag = 0; + il2 = Pne->MdebTrav[Cnt]; + il2Max = il2 + Pne->NbTermTrav[Cnt]; + while ( il2 < il2Max ) { + if ( Pne->NuvarTrav[il2] == VarSubstituee ) { + CoeffPivot = Pne->ATrav[il2]; + Flag = 1; + /* On supprime le terme de la ligne qui se trouve dans la colonne pivot */ + /* Attention au cas ou c'est le premier terme qu'on supprime */ + if ( il2 == Pne->MdebTrav[Cnt] ) { + Pne->MdebTrav[Cnt]++; + } + else { + il2Max--; + Pne->ATrav[il2] = Pne->ATrav[il2Max]; + Var = Pne->NuvarTrav[il2Max]; + + Pne->NuvarTrav[il2] = Pne->NuvarTrav[il2Max]; + + /* On change le chainage de la colonne Var de la colonne */ + if ( Var != VarSubstituee ) { + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) { + icPrec = -1; + ic = Pne->CdebTrav[Var]; + while ( ic >= 0 ) { + if ( ic == il2Max ) break; + icPrec = ic; + ic = Pne->CsuiTrav[ic]; + } + if ( icPrec >= 0 ) { + Pne->CsuiTrav[icPrec] = il2; + Pne->CsuiTrav[il2] = Pne->CsuiTrav[ic]; + } + else { + Pne->CdebTrav[Var] = il2; + Pne->CsuiTrav[il2] = Pne->CsuiTrav[ic]; + } + } + } + } + Pne->NbTermTrav[Cnt]--; + break; + } + il2++; + } + if ( Flag == 0 ) { + printf("Bug contrainte %d on ne trouve pas la variable pivot %d\n",Cnt,VarSubstituee); + exit(0); + } + + il2 = Pne->MdebTrav[Cnt]; + il2Max = il2 + Pne->NbTermTrav[Cnt]; + Nb = NbTermesLignePivot; + while ( il2 < il2Max ) { + Var = Pne->NuvarTrav[il2]; + /* T[Var] = 0 si Var = VarSubstituee */ + if ( T[Var] == 1 ) { + /* Le terme existe deja */ + Pne->ATrav[il2] -= CoeffPivot * LignePivot[Var]; + T[Var] = 0; + Nb--; + } + il2++; + } + + if ( Nb > 0 ) { + /* Nb est le nombre de termes que l'on va creer */ + /* Nn est le dernier index apres recopie. Quand on recopie on en profite pour reconstituer la marge */ + + Nn = Pne->MdebTrav[Cnt] + Pne->NbTermTrav[Cnt] + Nb - 1 ; + if ( Nn > DernierIndexDispo[Cnt] ) { + /* Ca ne tient pas: on doit recopier la contrainte a la fin et reconstituer la marge */ + Nn = Pne->PremierIndexLibre + Pne->NbTermTrav[Cnt] + Nb - 1 + MARGE_EN_FIN_DE_CONTRAINTE; + if ( Nn >= Pne->TailleAlloueePourLaMatriceDesContraintes - 10 /* Marge */) { + /*printf("Redimensionnement\n");*/ + PNE_AugmenterLaTailleDeLaMatriceDesContraintes( Pne ); + } + /*printf("Recopie d'une contrainte a la fin %d\n",Cnt);*/ + /* Recopie de la contrainte a la fin */ + il1 = Pne->MdebTrav[Cnt]; + il1Max = il1 + Pne->NbTermTrav[Cnt]; + + il2 = Pne->PremierIndexLibre; + Pne->MdebTrav[Cnt] = il2; + + while ( il1 < il1Max ) { + Pne->ATrav[il2] = Pne->ATrav[il1]; + Var = Pne->NuvarTrav[il1]; + Pne->NuvarTrav[il2] = Var; + + Pne->NumContrainteTrav[il2] = Cnt; + + if ( Var != VarSubstituee ) { + if ( Pne->TypeDeBorneTrav[Var] != VARIABLE_NON_BORNEE ) { + /* Modification du chainage par colonne */ + /* Recherche de l'index il1 */ + icPrec = -1; + ic = Pne->CdebTrav[Var]; + while ( ic >= 0 ) { + if ( ic == il1 ) break; + icPrec = ic; + ic = Pne->CsuiTrav[ic]; + } + if ( icPrec >= 0 ) { + Pne->CsuiTrav[icPrec] = il2; + Pne->CsuiTrav[il2] = Pne->CsuiTrav[ic]; + } + else { + Pne->CdebTrav[Var] = il2; + Pne->CsuiTrav[il2] = Pne->CsuiTrav[ic]; + } + } + } + il1++; + il2++; + } + + DernierIndexDispo[Cnt] = Nn; + Pne->PremierIndexLibre = DernierIndexDispo[Cnt] + 1; + } + + il2 = Pne->MdebTrav[Cnt] + Pne->NbTermTrav[Cnt]; + + il1 = Pne->MdebTrav[CntDeSubstitution]; + il1Max = il1 + Pne->NbTermTrav[CntDeSubstitution]; + while ( il1 < il1Max ) { + Var = Pne->NuvarTrav[il1]; + if ( T[Var] == 1 ) { + /* Le terme est cree */ + Pne->ATrav[il2] = -CoeffPivot * LignePivot[Var]; + Pne->NuvarTrav[il2] = Var; + Pne->NbTermTrav[Cnt]++; + NbContraintesParColonne[Var]++; + if ( Pne->SensContrainteTrav[Cnt] == '=' ) NbContraintesEgaliteParColonne[Var]++; + /* On chaine le nouveau terme */ + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) { + icPrec = Pne->CdebTrav[Var]; + Pne->CdebTrav[Var] = il2; + Pne->NumContrainteTrav[il2] = Cnt; + Pne->CsuiTrav[il2] = icPrec; + } + il2++; + T[Var] = 0; + } + il1++; + } + } + + Pne->BTrav[Cnt] -= CoeffPivot * BDeCntDeSubstitution / Pivot; + + NombreDeContraintesImpactees++; + + il1 = Pne->MdebTrav[CntDeSubstitution]; + il1Max = il1 + Pne->NbTermTrav[CntDeSubstitution]; + Nb = 0; + while ( il1 < il1Max ) { + T[Pne->NuvarTrav[il1]] = 1; /* La colonne pivot a ete supprimee de la ligne pivot */ + Nb++; + il1++; + } + +} + + +/*printf(" NombreDeContraintesImpactees %d\n",NombreDeContraintesImpactees);*/ + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_SubstituerLesVariablesNonBornees( PRESOLVE * Presolve ) +{ +int Var; int ic; int NbCMin; int NbC; int Nb; int VariableChoisie; int ContrainteChoisie; +int CntDeMinTermes; int MinTermesDeCnt; int Cnt; double Pivot; double PlusGrandTermeDeLaLigne; +int il; int ilMax; double PivotDeMinTermes; double PivotChoisi; int i; +double CoutDeLaVariableSubstituee; double Rapport; double RapportChoisi; PROBLEME_PNE * Pne; +double * LignePivot; char * T; int NombreDeVariablesNonBornees; int icPrec; +int * NumeroDesVariablesNonBornees; int ilPivot; int * DernierIndexDispo; int * NbContraintesEgaliteParColonne; +int * NbContraintesParColonne; int NbTermesColonnePivot; int * ContraintesDeLaColonnePivot; +char * ContrainteModifiee; + + +printf(" Ne pas utiliser PRS_SubstituerLesVariablesNonBornees !!!!!!!!!!!!!!!!\n"); + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +printf("Nombre de contraintes au debut des subtsitutions %d\n",Pne->NombreDeContraintesTrav); + +ContrainteModifiee = (char *) malloc( Pne->NombreDeContraintesTrav * sizeof( char ) ); + +ContraintesDeLaColonnePivot = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); + +NbContraintesParColonne = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +memset( (char *) NbContraintesParColonne, 0, Pne->NombreDeVariablesTrav * sizeof( int ) ); + +NbContraintesEgaliteParColonne = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +memset( (char *) NbContraintesEgaliteParColonne, 0, Pne->NombreDeVariablesTrav * sizeof( int ) ); + +DernierIndexDispo = (int *) malloc( Pne->NombreDeContraintesTrav * sizeof( int ) ); + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + ContrainteModifiee[Cnt] = NON_PNE; + DernierIndexDispo[Cnt] = Pne->MdebTrav[Cnt] + Pne->NbTermTrav[Cnt] + MARGE_EN_FIN_DE_CONTRAINTE - 1; +} + +NumeroDesVariablesNonBornees = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); + +LignePivot = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); + +T = (char *) malloc( Pne->NombreDeVariablesTrav * sizeof( char ) ); +memset( (char *) T, 0, Pne->NombreDeVariablesTrav * sizeof( char ) ); + +NombreDeVariablesNonBornees = 0; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) { + NumeroDesVariablesNonBornees[NombreDeVariablesNonBornees] = Var; + NombreDeVariablesNonBornees++; + } +} +if ( NombreDeVariablesNonBornees == 0 ) goto PasDeSubsitutions; + +for ( i = 0 ; i < NombreDeVariablesNonBornees ; i++ ) { + Var = NumeroDesVariablesNonBornees[i]; + Nb = 0; + NbC = 0; + ic = Pne->CdebTrav[Var]; + while ( ic >= 0 ) { + if ( Presolve->ContrainteInactive[Pne->NumContrainteTrav[ic]] == NON_PNE ) { + NbC++; + if ( Pne->SensContrainteTrav[Pne->NumContrainteTrav[ic]] == '=' ) Nb++; + } + ic = Pne->CsuiTrav[ic]; + } + NbContraintesParColonne[Var] = NbC; + NbContraintesEgaliteParColonne[Var] = Nb; +} + + +NextSubstitution: +/* On substitue la variable non bornee qui a le moins de termes dans sa colonne. + La contrainte choisie est la contrainte d'egalite qui a le moins de terme */ +NbCMin = Pne->NombreDeContraintesTrav + 1; +VariableChoisie = -1; +ContrainteChoisie = -1; +PivotChoisi = 0.0; +RapportChoisi = 0.0; +for ( i = 0 ; i < NombreDeVariablesNonBornees ; i++ ) { + Var = NumeroDesVariablesNonBornees[i]; + if ( NbContraintesEgaliteParColonne[Var] <= 0 ) continue; + + if ( NbContraintesParColonne[Var] != 1 ) continue; /* On ne supprime que les colonnes singleton */ + + NbC = 0; + MinTermesDeCnt = Pne->NombreDeContraintesTrav * 2; + CntDeMinTermes = -1; + PivotDeMinTermes = 0.0; + Rapport = 0.0; + ic = Pne->CdebTrav[Var]; + while ( ic >= 0 ) { + Cnt = Pne->NumContrainteTrav[ic]; + if ( Pne->SensContrainteTrav[Cnt] == '=' && ContrainteModifiee[Cnt] == NON_PNE && Presolve->ContrainteInactive[Pne->NumContrainteTrav[ic]] == NON_PNE ) { + if ( Pne->NbTermTrav[Cnt] < MinTermesDeCnt ) { + Pivot = Pne->ATrav[ic]; + if ( fabs( Pivot ) > PIVOT_MIN ) { + PlusGrandTermeDeLaLigne = -1.; + icPrec = -1; + il = Pne->MdebTrav[Cnt]; + ilMax = il + Pne->NbTermTrav[Cnt]; + while ( il < ilMax ) { + if ( Pne->NuvarTrav[il] == Var ) icPrec = il; + if ( fabs( Pne->ATrav[il] ) > PlusGrandTermeDeLaLigne ) PlusGrandTermeDeLaLigne = fabs( Pne->ATrav[il] ); + il++; + } + + if ( icPrec == -1 ) { + printf("Bug incoherence ligne colonne ligne %d colonne %d\n",Cnt,Var); + printf("la ligne %d ne continient pas la colonne %d\n",Cnt,Var); + exit(0); + } + + if ( fabs( Pivot ) / PlusGrandTermeDeLaLigne > RAPPORT_MIN ) { + MinTermesDeCnt = Pne->NbTermTrav[Cnt]; + CntDeMinTermes = Cnt; + PivotDeMinTermes = Pivot; + Rapport = fabs( Pivot ) / PlusGrandTermeDeLaLigne; + } + } + } + NbC++; + } + ic = Pne->CsuiTrav[ic]; + } + if ( CntDeMinTermes >= 0 && PivotDeMinTermes != 0.0 ) { + if ( NbC < NbCMin ) { + NbCMin = NbC; + VariableChoisie = Var; + ContrainteChoisie = CntDeMinTermes; + PivotChoisi = PivotDeMinTermes; + RapportChoisi = Rapport; + } + } +} +if ( VariableChoisie >= 0 && ContrainteChoisie >= 0 && PivotChoisi != 0.0 ) { + + /*printf("VariableChoisie %d ContrainteChoisie %d\n",VariableChoisie,ContrainteChoisie);*/ + + NumeroDesVariablesNonBornees[i] = NumeroDesVariablesNonBornees[NombreDeVariablesNonBornees - 1]; + NombreDeVariablesNonBornees--; + + /* Expand de la contrainte choisie */ + CoutDeLaVariableSubstituee = Pne->LTrav[VariableChoisie]; + ilPivot = -1; + il = Pne->MdebTrav[ContrainteChoisie]; + ilMax = il + Pne->NbTermTrav[ContrainteChoisie]; + while ( il < ilMax ) { + Var = Pne->NuvarTrav[il]; + if ( Var == VariableChoisie ) ilPivot = il; + else Pne->LTrav[Var] -= CoutDeLaVariableSubstituee * Pne->ATrav[il] / PivotChoisi; + LignePivot[Var] = Pne->ATrav[il] / PivotChoisi; + T[Var] = 1; + /* On dechaine le terme dans la colonne */ + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) { + icPrec = -1; + ic = Pne->CdebTrav[Var]; + while ( ic >= 0 ) { + if ( ic == il ) { + if ( icPrec >= 0 ) Pne->CsuiTrav[icPrec] = Pne->CsuiTrav[ic]; + else Pne->CdebTrav[Var] = Pne->CsuiTrav[ic]; + NbContraintesParColonne[Var]--; + /* ContrainteChoisie est toujours une contrainte d'eaglite */ + NbContraintesEgaliteParColonne[Var]--; + break; + } + icPrec = ic; + ic = Pne->CsuiTrav[ic]; + } + } + il++; + } + /* Suppression du terme pivot */ + Pne->LTrav[VariableChoisie] = 0.0; + T[VariableChoisie] = 0; + + if ( ilPivot == Pne->MdebTrav[ContrainteChoisie] ) { + /* Si on supprimme le 1er terme */ + Pne->MdebTrav[ContrainteChoisie]++; + } + else { + ilMax--; + Pne->ATrav[ilPivot] = Pne->ATrav[ilMax]; + Pne->NuvarTrav[ilPivot] = Pne->NuvarTrav[ilMax]; + } + Pne->NbTermTrav[ContrainteChoisie]--; + + NbTermesColonnePivot = 0; + ic = Pne->CdebTrav[VariableChoisie]; + while ( ic >= 0 ) { + ContraintesDeLaColonnePivot[NbTermesColonnePivot] = Pne->NumContrainteTrav[ic]; + NbTermesColonnePivot++; + ic = Pne->CsuiTrav[ic]; + } + + Pne->TypeDeBorneTrav[VariableChoisie] = VARIABLE_FIXE; + Pne->UTrav[VariableChoisie] = 0.; /* Pas d'importance mais ainsi on n'a pas besoin de la supprimer de la liste des + variables ni de la supprimer des contraintes */ + Presolve->ContrainteInactive[ContrainteChoisie] = OUI_PNE; + Pne->NumeroDesContraintesInactives[Pne->NombreDeContraintesInactives] = ContrainteChoisie; + Pne->NombreDeContraintesInactives++; + + /* On substitue la variable */ + if ( NbContraintesParColonne[VariableChoisie] > 0 ) { + PRS_SubstitutionDUneVariableNonBornee( Presolve, ContrainteChoisie, VariableChoisie, PivotChoisi, + LignePivot, DernierIndexDispo, T, NbContraintesParColonne, + NbContraintesEgaliteParColonne, NbTermesColonnePivot, ContraintesDeLaColonnePivot, + ContrainteModifiee ); + } + + Pne->CdebTrav[VariableChoisie] = -1; + + + il = Pne->MdebTrav[ContrainteChoisie]; + ilMax = il + Pne->NbTermTrav[ContrainteChoisie]; + while ( il < ilMax ) { + T[Pne->NuvarTrav[il]] = 0; + il++; + } + + goto NextSubstitution; + +} + +printf("Fin\n"); + +PRS_EnleverLesContraintesInactives( Presolve ); +PNE_ConstruireLeChainageDeLaTransposee( Pne ); + +PasDeSubsitutions: + +free( ContrainteModifiee ); +free( ContraintesDeLaColonnePivot ); +free( NbContraintesParColonne ); +free( NbContraintesEgaliteParColonne ); +free( DernierIndexDispo ); +free( LignePivot ); +free( T ); +free( NumeroDesVariablesNonBornees ); + +printf("Nombre de contraintes a la fin des subtsitutions %d\n",Pne->NombreDeContraintesTrav); + +return; +} + + diff --git a/src/ext/Sirius_Solver/presolve/prs_supprimer_contraintes_sans_variables.c b/src/ext/Sirius_Solver/presolve/prs_supprimer_contraintes_sans_variables.c new file mode 100644 index 0000000000..9131dc9039 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_supprimer_contraintes_sans_variables.c @@ -0,0 +1,120 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +/*----------------------------------------------------------------------------*/ +/* Attention, il faut verifier que la contrainte avec que des variables + fixees est satisfaite, c'est pour ca qu'on appelle ce SP apres avoir + calcule les bornes sur les contraintes */ + +void PRS_SupprimerLesContraintesAvecQueDesVariablesFixees( PRESOLVE * Presolve ) + +{ +int il; int ilMax; int Cnt; int QueDesVarFix; int Nb; double S; char ControleActive; +int NombreDeContraintes; char * ContrainteInactive; int * Mdeb; int * NbTerm; +int * Nuvar; int * TypeDeBornePourPresolve; double * A; double * ValeurDeXPourPresolve; +char * SensContrainte; double * B; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +SensContrainte = Pne->SensContrainteTrav; +B = Pne->BTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ContrainteInactive = Presolve->ContrainteInactive; + +ControleActive = NON_PNE; + +for ( Nb = 0 , Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + + if ( ContrainteInactive[Cnt] == OUI_PNE ) continue; + + QueDesVarFix = OUI_PNE; + + S = 0.; + + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( TypeDeBornePourPresolve[Nuvar[il]] != VARIABLE_FIXE ) { + QueDesVarFix = NON_PNE; + break; + } + S+= A[il] * ValeurDeXPourPresolve[Nuvar[il]]; + il++; + } + if ( QueDesVarFix == OUI_PNE ) { + Nb++; + /* + printf("contrainte %d avec QueDesVarFix\n",Cnt); + */ + PRS_DesactiverContrainte( Presolve, Cnt ); + + /* On verifie que la contrainte est satisfaite */ + if ( SensContrainte[Cnt] == '=' ) { + if ( fabs ( S - B[Cnt] ) > SEUIL_DADMISSIBILITE && ControleActive == OUI_PNE ) { + # if VERBOSE_PRS == 1 + printf("*** Phase de Presolve-> La contrainte %d ne comporte que des variables fixees dont les valeurs\n",Cnt); + printf("sont incompatibles avec la valeur du second membre.\n"); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + } + else { + /* La contrainte est de type <= */ + if ( S > B[Cnt] + SEUIL_DADMISSIBILITE && ControleActive == OUI_PNE ) { + # if VERBOSE_PRS == 1 + printf("*** Phase de Presolve-> La contrainte %d ne comporte que des variables fixees dont les valeurs\n",Cnt); + printf("sont incompatibles avec la valeur du second membre.\n"); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + } + } + +} + +#if VERBOSE_PRS + printf("-> nombre de contraintes supprimees car contenant uniquement des variables fixees %d\n",Nb); +#endif + +return; +} + + diff --git a/src/ext/Sirius_Solver/presolve/prs_sys.h b/src/ext/Sirius_Solver/presolve/prs_sys.h new file mode 100644 index 0000000000..f8707987c9 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_sys.h @@ -0,0 +1,30 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# include +# include +# include +# include +# include +/* # include */ +# include +# include +# include +# include + + + + diff --git a/src/ext/Sirius_Solver/presolve/prs_variable_probing.c b/src/ext/Sirius_Solver/presolve/prs_variable_probing.c new file mode 100644 index 0000000000..faaff7aa0c --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_variable_probing.c @@ -0,0 +1,669 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: "Probing" des variables entieres. On les fixe a 0 ou a 1 + pour en deduire des implications logiques sur les autres + variables. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# ifdef PRS_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "prs_memoire.h" +# endif + +# define SEUIL 1.e-4 +# define NOMBRE_MAX_DE_CYCLES 10 +# define VARIABLE_ENTIERE_FIXEE_SUR_UMIN 0 +# define VARIABLE_ENTIERE_FIXEE_SUR_UMAX 1 + +# define COMPILE_VARIABLE_PROBING NON_PNE + +# if COMPILE_VARIABLE_PROBING == OUI_PNE + +void PRS_VariableProbing( PRESOLVE * , char , int ); +void PRS_EtudierUneInstanciationDeVariable( PRESOLVE * , int , char * , char * , char * , + double * , char * , double * , int * , char * ); +void PRS_BornerUneContrainte( PRESOLVE * , int , char * , double * , char * , double * ); +void PRS_BornerUneVariable( PRESOLVE * , double * , double * , char * , char * , int , + char * , double * , char * , double * ) ; +void PRS_TesterLesBornesDUneVariableContinue( PRESOLVE * , int , char , double , char , + double , char * ); +void PRS_TesterLesBornesDUneVariableEntiere( PRESOLVE * , int , char , double , char , double , + char * , int * , int * , char * ); + +/*----------------------------------------------------------------------------*/ + +void PRS_VariableProbing( PRESOLVE * Presolve, char TesterToutesLesVariablesEntieres, int VariableEntiereATester ) +{ +int Cnt; int Var; int i; char * ContrainteABorner; char * VariableABorner; int Var2; int Cnt2; +int * NumeroDesVariablesEntieresFixee ; char * VariableEntiereFixeeSurUminOuSurUmax ; +char * TypeDeBorneTravSv; double * UTravSv ; double * UminTravSv; double * UmaxTravSv ; +char * MinContrainteCalcule ; char * MaxContrainteCalcule ; double * MinContrainte ; double * MaxContrainte ; +char * MinContrainteCalculeSv; char * MaxContrainteCalculeSv; double * MinContrainteSv; double * MaxContrainteSv; +char BorneInfValide ; double BorneInf ; char BorneSupValide ; double BorneSup ; +int DebutDeBoucle ; int FinDeBoucle ; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +if ( TesterToutesLesVariablesEntieres == NON_PNE ) { + if ( VariableEntiereATester < 0 || VariableEntiereATester >= Pne->NombreDeVariablesTrav ) return; +} + +ContrainteABorner = (char *) malloc( Pne->NombreDeContraintesTrav * sizeof( char ) ); +VariableABorner = (char *) malloc( Pne->NombreDeVariablesTrav * sizeof( char ) ); + +NumeroDesVariablesEntieresFixee = (int *) malloc( Pne->NombreDeVariablesTrav * sizeof( int ) ); +VariableEntiereFixeeSurUminOuSurUmax = (char *) malloc( Pne->NombreDeVariablesTrav * sizeof( char ) ); + +TypeDeBorneTravSv = (char *) malloc( Pne->NombreDeVariablesTrav * sizeof( char ) ); +UTravSv = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +UminTravSv = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); +UmaxTravSv = (double *) malloc( Pne->NombreDeVariablesTrav * sizeof( double ) ); + +MinContrainteCalcule = (char *) malloc( Pne->NombreDeContraintesTrav * sizeof( char ) ); +MaxContrainteCalcule = (char *) malloc( Pne->NombreDeContraintesTrav * sizeof( char ) ); +MinContrainte = (double *) malloc( Pne->NombreDeContraintesTrav * sizeof( double ) ); +MaxContrainte = (double *) malloc( Pne->NombreDeContraintesTrav * sizeof( double ) ); + +MinContrainteCalculeSv = (char *) malloc( Pne->NombreDeContraintesTrav * sizeof( char ) ); +MaxContrainteCalculeSv = (char *) malloc( Pne->NombreDeContraintesTrav * sizeof( char ) ); +MinContrainteSv = (double *) malloc( Pne->NombreDeContraintesTrav * sizeof( double ) ); +MaxContrainteSv = (double *) malloc( Pne->NombreDeContraintesTrav * sizeof( double ) ); + +if ( ContrainteABorner == NULL || VariableABorner == NULL || + NumeroDesVariablesEntieresFixee == NULL || VariableEntiereFixeeSurUminOuSurUmax == NULL || + TypeDeBorneTravSv == NULL || UTravSv == NULL || + UminTravSv == NULL || UmaxTravSv == NULL || + MinContrainteCalcule == NULL || MaxContrainteCalcule == NULL || + MinContrainte == NULL || MaxContrainte == NULL || + MinContrainteCalculeSv == NULL || MaxContrainteCalculeSv == NULL || + MinContrainteSv == NULL || MaxContrainteSv == NULL ) { + printf(" Solveur PNE , memoire insuffisante. Sous-programme: PRS_VariableProbing\n"); + Pne->AnomalieDetectee = OUI_PNE; + longjmp( Pne->Env , Pne->AnomalieDetectee ); +} + +/* Sauvegarde des donnees des variables du probleme */ +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + TypeDeBorneTravSv[Var] = (char) Pne->TypeDeBorneTrav[Var]; + UTravSv [Var] = Pne->UTrav[Var]; + UminTravSv [Var] = Pne->UminTrav[Var]; + UmaxTravSv [Var] = Pne->UmaxTrav[Var]; +} +/* On restaure les types de bornes et les valeurs de bornes obtenues en fin de + presolve avant liberation des bornes lorsque c'etait possible */ +for ( i = 0 ; i < Pne->NombreDeVariablesLiberees ; i++ ) { + Var = Pne->VariableLiberee[i]; + TypeDeBorneTravSv[Var] = Pne->TypeDeBorneVariableLiberee[i]; + UminTravSv [Var] = Pne->UminVariableLiberee[i]; + UmaxTravSv [Var] = Pne->UmaxVariableLiberee[i]; +} + +/* Premiere initialisation */ +for ( Var2 = 0 ; Var2 < Pne->NombreDeVariablesTrav ; Var2++ ) { + Pne->TypeDeBorneTrav[Var2] = TypeDeBorneTravSv[Var2]; + Pne->UTrav [Var2] = UTravSv[Var2]; + Pne->UminTrav [Var2] = UminTravSv[Var2]; + Pne->UmaxTrav [Var2] = UmaxTravSv[Var2]; +} +/* Calcul de toutes les bornes des contraintes */ +for ( Cnt2 = 0 ; Cnt2 < Pne->NombreDeContraintesTrav ; Cnt2++ ) { + PRS_BornerUneContrainte( Presolve, Cnt2, &BorneInfValide, &BorneInf, &BorneSupValide, &BorneSup ); + MinContrainteCalcule [Cnt2] = BorneInfValide; + MinContrainteCalculeSv[Cnt2] = BorneInfValide; + MaxContrainteCalcule [Cnt2] = BorneSupValide; + MaxContrainteCalculeSv[Cnt2] = BorneSupValide; + MinContrainte [Cnt2] = BorneInf; + MinContrainteSv [Cnt2] = BorneInf; + MaxContrainte [Cnt2] = BorneSup; + MaxContrainteSv [Cnt2] = BorneSup; +} + +for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) ContrainteABorner[Cnt] = NON_PNE; +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) VariableABorner [Var] = NON_PNE; + +DebutDeBoucle = 0; +FinDeBoucle = Pne->NombreDeVariablesTrav; +if ( TesterToutesLesVariablesEntieres == NON_PNE ) { + DebutDeBoucle = VariableEntiereATester; + FinDeBoucle = DebutDeBoucle + 1; +} +for ( Var = DebutDeBoucle ; Var < FinDeBoucle ; Var++ ) { + if ( Pne->TypeDeVariableTrav[Var] != ENTIER ) continue; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_FIXE ) continue; + +printf("-> Probing de la variable entiere %d \n",Var); + + /* Fixation de la variable a 0 */ + Pne->TypeDeBorneTrav[Var] = VARIABLE_FIXE; + Pne->UTrav [Var] = Pne->UminTrav[Var]; + /*Pne->UmaxTrav [Var] = Pne->UminTrav[Var];*/ + /* Etude de l'impact de la fixation de la variable a 0 */ + PRS_EtudierUneInstanciationDeVariable( Presolve, Var, ContrainteABorner, VariableABorner, + MinContrainteCalcule , MinContrainte , + MaxContrainteCalcule , MaxContrainte , + NumeroDesVariablesEntieresFixee , + VariableEntiereFixeeSurUminOuSurUmax ); + /* On restaure les donnees */ + for ( Var2 = 0 ; Var2 < Pne->NombreDeVariablesTrav ; Var2++ ) { + Pne->TypeDeBorneTrav[Var2] = TypeDeBorneTravSv[Var2]; + Pne->UTrav [Var2] = UTravSv[Var2]; + Pne->UminTrav [Var2] = UminTravSv[Var2]; + Pne->UmaxTrav [Var2] = UmaxTravSv[Var2]; + } + for ( Cnt2 = 0 ; Cnt2 < Pne->NombreDeContraintesTrav ; Cnt2++ ) { + MinContrainteCalcule[Cnt2] = MinContrainteCalculeSv[Cnt2]; + MaxContrainteCalcule[Cnt2] = MaxContrainteCalculeSv[Cnt2]; + MinContrainte [Cnt2] = MinContrainteSv[Cnt2]; + MaxContrainte [Cnt2] = MaxContrainteSv[Cnt2]; + } + + /* Fixation de la variable a 1 */ + Pne->TypeDeBorneTrav[Var] = VARIABLE_FIXE; + Pne->UTrav [Var] = Pne->UmaxTrav[Var]; + /*Pne->UminTrav [Var] = Pne->UmaxTrav[Var];*/ + /* Etude de l'impact de la fixation de la variable a 1 */ + PRS_EtudierUneInstanciationDeVariable( Presolve, Var, ContrainteABorner, VariableABorner, + MinContrainteCalcule , MinContrainte , + MaxContrainteCalcule , MaxContrainte , + NumeroDesVariablesEntieresFixee , + VariableEntiereFixeeSurUminOuSurUmax ); + /* On restaure les donnees */ + for ( Var2 = 0 ; Var2 < Pne->NombreDeVariablesTrav ; Var2++ ) { + Pne->TypeDeBorneTrav[Var2] = TypeDeBorneTravSv[Var2]; + Pne->UTrav [Var2] = UTravSv[Var2]; + Pne->UminTrav [Var2] = UminTravSv[Var2]; + Pne->UmaxTrav [Var2] = UmaxTravSv[Var2]; + } + for ( Cnt2 = 0 ; Cnt2 < Pne->NombreDeContraintesTrav ; Cnt2++ ) { + MinContrainteCalcule[Cnt2] = MinContrainteCalculeSv[Cnt2]; + MaxContrainteCalcule[Cnt2] = MaxContrainteCalculeSv[Cnt2]; + MinContrainte [Cnt2] = MinContrainteSv[Cnt2]; + MaxContrainte [Cnt2] = MaxContrainteSv[Cnt2]; + } + +} + +/* Restauration des variables du probleme (avant liberation des variables) */ +for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + Pne->TypeDeBorneTrav[Var] = TypeDeBorneTravSv[Var]; + Pne->UTrav [Var] = UTravSv[Var]; + Pne->UminTrav [Var] = UminTravSv[Var] ; + Pne->UmaxTrav [Var] = UmaxTravSv[Var] ; +} +/* Restauration des variables liberees */ +for ( i = 0 ; i < Pne->NombreDeVariablesLiberees ; i++ ) { + Var = Pne->VariableLiberee[i]; + Pne->TypeDeBorneTrav[Var] = VARIABLE_NON_BORNEE; + Pne->UmaxTrav [Var] = LINFINI_PNE; + Pne->UminTrav [Var] = -LINFINI_PNE; +} + +free( ContrainteABorner ); +free( VariableABorner ); +free( NumeroDesVariablesEntieresFixee ); +free( VariableEntiereFixeeSurUminOuSurUmax ); +free( TypeDeBorneTravSv ); +free( UTravSv ); +free( UminTravSv ); +free( UmaxTravSv ); +free( MinContrainteCalcule ); +free( MaxContrainteCalcule ); +free( MinContrainte ); +free( MaxContrainte ); +free( MinContrainteCalculeSv ); +free( MaxContrainteCalculeSv ); +free( MinContrainteSv ); +free( MaxContrainteSv ); + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_EtudierUneInstanciationDeVariable( PRESOLVE * Presolve, + int VariableQuiAEteFixee, + char * ContrainteABorner, + char * VariableABorner, + char * MinContrainteCalcule, + double * MinContrainte, + char * MaxContrainteCalcule, + double * MaxContrainte, + int * NumeroDesVariablesEntieresFixee, + char * VariableEntiereFixeeSurUminOuSurUmax ) +{ +int il; int ilMax; int Cnt; int Var ; char RecalculerLesBornesSurLesVariables ; char BorneModifiee ; +char RecalculerLesBornesSurLesContraintes; char BorneAmelioree; char VariableFixee; int NombreDeCycles; +char BorneInfValide; char BorneSupValide ; double BorneInf ; double BorneSup ; +int NombreDeVariablesEntieresFixee ; +char MinVariableCalcule; double MinVariable; +char MaxVariableCalcule; double MaxVariable; PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NombreDeVariablesEntieresFixee = 0; + +/* Initialisation de la liste des contraintes a borner */ +il = Pne->CdebTrav[VariableQuiAEteFixee]; +while ( il >= 0 ) { + ContrainteABorner[Pne->NumContrainteTrav[il]] = OUI_PNE; + il = Pne->CsuiTrav[il]; +} +RecalculerLesBornesSurLesContraintes = OUI_PNE; + +NombreDeCycles = 0; + +DebutDeCycle: + +RecalculerLesBornesSurLesVariables = NON_PNE; + +if ( RecalculerLesBornesSurLesContraintes == OUI_PNE ) { + for ( Cnt = 0 ; Cnt < Pne->NombreDeContraintesTrav ; Cnt++ ) { + if ( ContrainteABorner[Cnt] == NON_PNE ) continue; + ContrainteABorner[Cnt] = NON_PNE; + + PRS_BornerUneContrainte( Presolve, Cnt, &BorneInfValide, &BorneInf, &BorneSupValide, &BorneSup ); + + MinContrainteCalcule[Cnt] = BorneInfValide; + MaxContrainteCalcule[Cnt] = BorneSupValide; + + BorneAmelioree = NON_PNE; + if ( BorneInfValide == OUI_PNE && BorneInf > MinContrainte[Cnt] + SEUIL ) { +/* +printf(" borne sur contrainte %d ancienne borne min %lf nouvelle borne min %lf\n",Cnt,MinContrainte[Cnt],BorneInf); +*/ + MinContrainte[Cnt] = BorneInf; + BorneAmelioree = OUI_PNE; + } + if ( BorneSupValide == OUI_PNE && BorneSup < MaxContrainte[Cnt] - SEUIL ) { +/* +printf(" borne sur contrainte %d ancienne borne max %lf nouvelle borne max %lf\n",Cnt,MaxContrainte[Cnt],BorneSup); +*/ + MaxContrainte[Cnt] = BorneSup; + BorneAmelioree = OUI_PNE; + } + if ( BorneAmelioree == OUI_PNE ) { + RecalculerLesBornesSurLesVariables = OUI_PNE; + il = Pne->MdebTrav[Cnt]; + ilMax = il + Pne->NbTermTrav[Cnt]; + while ( il < ilMax ) { + Var = Pne->NuvarTrav[il]; + if ( Pne->TypeDeBorneTrav[Var] != VARIABLE_FIXE ) VariableABorner[Var] = OUI_PNE; + il++; + } + } + } +} + +RecalculerLesBornesSurLesContraintes = NON_PNE; + +if ( RecalculerLesBornesSurLesVariables == OUI_PNE ) { + for ( Var = 0 ; Var < Pne->NombreDeVariablesTrav ; Var++ ) { + if ( VariableABorner[Var] == NON_PNE ) continue; + VariableABorner[Var] = NON_PNE; + + /* Compte tenu des nouvelles valeurs des bornes sur les contraintes, on recalcule les bornes de + la variable */ + PRS_BornerUneVariable( Presolve, + MinContrainte , MaxContrainte, MinContrainteCalcule, MaxContrainteCalcule, Var, + &MinVariableCalcule, &MinVariable , &MaxVariableCalcule , &MaxVariable ); + + /* On controle si la variable a des bornes moins larges */ + if ( Pne->TypeDeVariableTrav[Var] != ENTIER ) { + PRS_TesterLesBornesDUneVariableContinue( Presolve, + Var , MinVariableCalcule, MinVariable, MaxVariableCalcule, + MaxVariable, &BorneAmelioree ); + } + else if ( Pne->TypeDeVariableTrav[Var] == ENTIER ) { + PRS_TesterLesBornesDUneVariableEntiere( Presolve, + Var , MinVariableCalcule, MinVariable, MaxVariableCalcule, + MaxVariable, &VariableFixee , &NombreDeVariablesEntieresFixee, + NumeroDesVariablesEntieresFixee, VariableEntiereFixeeSurUminOuSurUmax ); + } + + /* Si la variable a des bornes plus petites, on recalcule les bornes des contraintes dans lesquelles + elle intervient */ + if ( BorneAmelioree == OUI_PNE || VariableFixee == OUI_PNE ) { + RecalculerLesBornesSurLesContraintes = OUI_PNE; + il = Pne->CdebTrav[Var]; + while ( il >= 0 ) { + ContrainteABorner[Pne->NumContrainteTrav[il]] = OUI_PNE; + il = Pne->CsuiTrav[il]; + } + } + } +} + +NombreDeCycles++; +if ( RecalculerLesBornesSurLesContraintes == OUI_PNE && NombreDeCycles < NOMBRE_MAX_DE_CYCLES ) goto DebutDeCycle; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Calcul des bornes sur une contrainte (a ce stade on suppose que toutes les + contraintes sont actives) */ + +void PRS_BornerUneContrainte( PRESOLVE * Presolve, + int Cnt, + char * BorneInfValide, + double * BorneInf, + char * BorneSupValide, + double * BorneSup ) +{ +int il; int ilMax; int Var; double Smin; double Smax; double X; +PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +*BorneInfValide = OUI_PNE; +*BorneSupValide = OUI_PNE; + +Smin = 0.; +Smax = 0.; +il = Pne->MdebTrav[Cnt]; +ilMax = il + Pne->NbTermTrav[Cnt]; +while ( il < ilMax ) { + + Var = Pne->NuvarTrav[il]; + + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) { + *BorneInfValide = NON_PNE; + *BorneSupValide = NON_PNE; + return; + } + else if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_FIXE ) { + X = Pne->ATrav[il] * Pne->UTrav[Var]; + Smax+= X; + Smin+= X; + } + else { + if ( Pne->ATrav[il] > 0. ) { + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) *BorneSupValide = NON_PNE; + else Smax+= Pne->ATrav[il] * Pne->UmaxTrav[Var]; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) *BorneInfValide = NON_PNE; + else Smin+= Pne->ATrav[il] * Pne->UminTrav[Var]; + } + else { + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) *BorneSupValide = NON_PNE; + else Smax+= Pne->ATrav[il] * Pne->UminTrav[Var]; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) *BorneInfValide = NON_PNE; + else Smin+= Pne->ATrav[il] * Pne->UmaxTrav[Var]; + } + } + il++; +} + +*BorneInf = Smin; +*BorneSup = Smax; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Calcul des bornes sur une variable (a ce stade on suppose que toutes les + contraintes sont actives) */ + +void PRS_BornerUneVariable( PRESOLVE * Presolve, + double * MinContrainte, + double * MaxContrainte, + char * MinContrainteCalcule, + char * MaxContrainteCalcule, + int Var, + char * MinVariableCalcule, + double * MinVariable, + char * MaxVariableCalcule, + double * MaxVariable ) +{ +int il ; int Cnt ; double CoeffDeVar; double Smin ; double Smax ; +double AxiMin ; double AxiMax ; double XiMin ; double XiMax ; +double InfDesXiMax; double SupDesXiMin; +char InfDesXiMaxEstInitialise ; char SupDesXiMinEstInitialise ; +char SminEstValide ; char SmaxEstValide ; +char XiMinEstValide ; char XiMaxEstValide ; +PROBLEME_PNE * Pne; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +InfDesXiMaxEstInitialise = NON_PNE; +SupDesXiMinEstInitialise = NON_PNE; + +il = Pne->CdebTrav[Var]; +while ( il >= 0 ) { + + Cnt = Pne->NumContrainteTrav[il]; + + CoeffDeVar = Pne->ATrav[il]; + + SmaxEstValide = OUI_PNE; + SminEstValide = OUI_PNE; + XiMinEstValide = OUI_PNE; + XiMaxEstValide = OUI_PNE; + + if ( Pne->SensContrainteTrav[Cnt] == '=' ) { + /* Dans le cas d'une contrainte d'egalite on peut calculer une borne + min et une borne max */ + if ( CoeffDeVar > ZERO_PRESOLVE ) { + /* Coeff positif */ + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT || + MaxContrainteCalcule[Cnt] == NON_PNE ) SmaxEstValide = NON_PNE; + else Smax = MaxContrainte[Cnt] - ( CoeffDeVar * Pne->UmaxTrav[Var] ); + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT || + MinContrainteCalcule[Cnt] == NON_PNE ) SminEstValide = NON_PNE; + else Smin = MinContrainte[Cnt] - ( CoeffDeVar * Pne->UminTrav[Var] ); + AxiMin = Pne->BTrav[Cnt] - Smax; + AxiMax = Pne->BTrav[Cnt] - Smin; + if ( SmaxEstValide == NON_PNE ) XiMinEstValide = NON_PNE; + else XiMin = AxiMin / CoeffDeVar; + if ( SminEstValide == NON_PNE ) XiMaxEstValide = NON_PNE; + else XiMax = AxiMax / CoeffDeVar; + } + else if ( CoeffDeVar < -ZERO_PRESOLVE ) { + /* Coeff negatif */ + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT || + MaxContrainteCalcule[Cnt] == NON_PNE ) SmaxEstValide = NON_PNE; + else Smax = MaxContrainte[Cnt] - ( CoeffDeVar * Pne->UminTrav[Var] ); + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT || + MinContrainteCalcule[Cnt] == NON_PNE ) SminEstValide = NON_PNE; + else Smin = MinContrainte[Cnt] - ( CoeffDeVar * Pne->UmaxTrav[Var] ); + AxiMin = Pne->BTrav[Cnt] - Smax; + AxiMax = Pne->BTrav[Cnt] - Smin; + if ( SminEstValide == NON_PNE ) XiMinEstValide = NON_PNE; + else XiMin = AxiMax / CoeffDeVar; + if ( SmaxEstValide == NON_PNE ) XiMaxEstValide = NON_PNE; + else XiMax = AxiMin / CoeffDeVar; + } + else return; /* Car evaluation impossible */ + if ( XiMinEstValide == OUI_PNE ) { + if ( SupDesXiMinEstInitialise == OUI_PNE ) { + if ( XiMin > SupDesXiMin ) SupDesXiMin = XiMin; + } + else { + SupDesXiMin = XiMin; + SupDesXiMinEstInitialise = OUI_PNE; + } + } + if ( XiMaxEstValide == OUI_PNE ) { + if ( InfDesXiMaxEstInitialise == OUI_PNE ) { + if ( XiMax < InfDesXiMax ) InfDesXiMax = XiMax; + } + else { + InfDesXiMax = XiMax; + InfDesXiMaxEstInitialise = OUI_PNE; + } + } + } + else { + /* Dans le cas d'une contrainte d'inegalite on ne peut calculer qu'un seul type de borne */ + if ( CoeffDeVar > ZERO_PRESOLVE ) { + /* Coeff positif */ + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT || + MinContrainteCalcule[Cnt] == NON_PNE ) SminEstValide = NON_PNE; + if ( SminEstValide == OUI_PNE ) { + Smin = MinContrainte[Cnt] - ( CoeffDeVar * Pne->UminTrav[Var] ); + AxiMax = Pne->BTrav[Cnt] - Smin; + XiMax = AxiMax / CoeffDeVar; + if ( InfDesXiMaxEstInitialise == OUI_PNE ) { + if ( XiMax < InfDesXiMax ) InfDesXiMax = XiMax; + } + else { + InfDesXiMax = XiMax; + InfDesXiMaxEstInitialise = OUI_PNE; + } + } + } + else if ( CoeffDeVar < -ZERO_PRESOLVE ) { + /* Coeff negatif */ + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT || + MinContrainteCalcule[Cnt] == NON_PNE ) SminEstValide = NON_PNE; + if ( SminEstValide == OUI_PNE ) { + Smin = MinContrainte[Cnt] - ( CoeffDeVar * Pne->UmaxTrav[Var] ); + AxiMax = Pne->BTrav[Cnt] - Smin; + XiMin = AxiMax / CoeffDeVar; + if ( SupDesXiMinEstInitialise == OUI_PNE ) { + if ( XiMin > SupDesXiMin ) SupDesXiMin = XiMin; + } + else { + SupDesXiMin = XiMin; + SupDesXiMinEstInitialise = OUI_PNE; + } + } + } + else return; /* Car evaluation impossible */ + } + /*ContrainteSuivante:*/ + il = Pne->CsuiTrav[il]; + +} + +*MinVariableCalcule = SupDesXiMinEstInitialise; +*MinVariable = SupDesXiMin; +*MaxVariableCalcule = InfDesXiMaxEstInitialise; +*MaxVariable = InfDesXiMax; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_TesterLesBornesDUneVariableContinue( PRESOLVE * Presolve, + int Var, + char MinVariableCalcule, + double MinVariable, + char MaxVariableCalcule, + double MaxVariable, + char * BorneAmelioree ) +{ +PROBLEME_PNE * Pne; +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +*BorneAmelioree = NON_PNE; + +if ( MinVariableCalcule == OUI_PNE ) { + if ( ( MinVariable - Pne->UminTrav[Var] ) > SEUIL || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT || + Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) { +/* + printf("-> Phase de variable probing: variable %d borne inf amelioree valeur %lf nouvelle valeur %lf\n",Var,Pne->UminTrav[Var],MinVariable); +*/ + *BorneAmelioree = OUI_PNE; + Pne->UminTrav[Var] = MinVariable; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) Pne->TypeDeBorneTrav[Var] = VARIABLE_BORNEE_DES_DEUX_COTES; + else if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) Pne->TypeDeBorneTrav[Var] = VARIABLE_BORNEE_INFERIEUREMENT; + } +} + +if ( MaxVariableCalcule == OUI_PNE ) { + if ( ( Pne->UmaxTrav[Var] - MaxVariable ) > SEUIL || + Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT || + Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) { +/* + printf("-> Phase de variable probing: variable %d borne sup amelioree valeur %lf nouvelle valeur %lf\n",Var,Pne->UmaxTrav[Var],MaxVariable); +*/ + *BorneAmelioree = OUI_PNE; + Pne->UmaxTrav [Var] = MaxVariable; + if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) Pne->TypeDeBorneTrav[Var] = VARIABLE_BORNEE_DES_DEUX_COTES; + else if ( Pne->TypeDeBorneTrav[Var] == VARIABLE_NON_BORNEE ) Pne->TypeDeBorneTrav[Var] = VARIABLE_BORNEE_SUPERIEUREMENT; + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_TesterLesBornesDUneVariableEntiere( PRESOLVE * Presolve, + int Var, + char MinVariableCalcule, + double MinVariable, + char MaxVariableCalcule, + double MaxVariable, + char * VariableFixee, + int * NombreDeVariablesEntieresFixee, + int * NumeroDesVariablesEntieresFixee, + char * VariableEntiereFixeeSurUminOuSurUmax ) +{ +PROBLEME_PNE * Pne; +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +*VariableFixee = NON_PNE; + +if ( MinVariableCalcule == OUI_PNE && ( MinVariable - Pne->UminTrav[Var] ) > SEUIL ) { + printf("-> Phase de variable probing: la variable entiere %d est fixee a 1 car nouveau min = %lf\n",Var,MinVariable); + /*Pne->UminTrav [Var] = Pne->UmaxTrav[Var];*/ + Pne->UTrav [Var] = Pne->UmaxTrav[Var]; + Pne->TypeDeBorneTrav[Var] = VARIABLE_FIXE; + *VariableFixee = OUI_PNE; + NumeroDesVariablesEntieresFixee [*NombreDeVariablesEntieresFixee] = Var; + VariableEntiereFixeeSurUminOuSurUmax[*NombreDeVariablesEntieresFixee] = VARIABLE_ENTIERE_FIXEE_SUR_UMIN; + *NombreDeVariablesEntieresFixee = *NombreDeVariablesEntieresFixee + 1; +} + +if ( MaxVariableCalcule == OUI_PNE && ( Pne->UmaxTrav[Var] - MaxVariable ) > SEUIL ) { + printf("-> Phase de variable probing: la variable entiere %d est fixee a 0 car nouveau max = %lf\n",Var,MaxVariable); + /*Pne->UmaxTrav [Var] = Pne->UminTrav[Var];*/ + Pne->UTrav [Var] = Pne->UminTrav[Var]; + Pne->TypeDeBorneTrav[Var] = VARIABLE_FIXE; + *VariableFixee = OUI_PNE; + NumeroDesVariablesEntieresFixee [*NombreDeVariablesEntieresFixee] = Var; + VariableEntiereFixeeSurUminOuSurUmax[*NombreDeVariablesEntieresFixee] = VARIABLE_ENTIERE_FIXEE_SUR_UMAX; + *NombreDeVariablesEntieresFixee = *NombreDeVariablesEntieresFixee + 1; +} + +return; +} + +# endif + + diff --git a/src/ext/Sirius_Solver/presolve/prs_variables_duales_ameliorer_bornes.c b/src/ext/Sirius_Solver/presolve/prs_variables_duales_ameliorer_bornes.c new file mode 100644 index 0000000000..6bb1bcaa5a --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_variables_duales_ameliorer_bornes.c @@ -0,0 +1,222 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Amelioration des bornes sur les variables duales. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" + +# include "pne_define.h" + +# include "prs_define.h" + +# define VALEUR_NULLE 1.e-8 +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void PRS_AmeliorerBornesDesVariablesDuales( PRESOLVE * Presolve, + int Var, + char TypeBrn, + double MinSommeDesAiFoisLambda, + char MinSommeDesAiFoisLambdaValide, + double MaxSommeDesAiFoisLambda, + char MaxSommeDesAiFoisLambdaValide, + int * NbModifications ) +{ +int il; int Cnt; double CoeffDeVar; PROBLEME_PNE * Pne; double * LambdaMin; +double * LambdaMax; double * Lambda; int * Cdeb; int * Csui; int * NumContrainte; +char * ContrainteInactive; char * ConnaissanceDeLambda; double * A; double X; +char SensCoutReduit; double CBarreMin; double CBarreMax; + +if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) SensCoutReduit = '>'; +else if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) SensCoutReduit = '<'; +else if ( TypeBrn == VARIABLE_NON_BORNEE ) SensCoutReduit = '='; +else return; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; + +CBarreMin = Pne->LTrav[Var] - MaxSommeDesAiFoisLambda; +CBarreMax = Pne->LTrav[Var] - MinSommeDesAiFoisLambda; + +LambdaMin = Presolve->LambdaMin; +LambdaMax = Presolve->LambdaMax; +Lambda = Presolve->Lambda; +ConnaissanceDeLambda = Presolve->ConnaissanceDeLambda; +ContrainteInactive = Presolve->ContrainteInactive; + +if ( MinSommeDesAiFoisLambdaValide == OUI_PNE ) { + if ( SensCoutReduit == '>' || SensCoutReduit == '=' ) { + /* Le cout reduit est soit positif ou nul, soit nul */ + il = Cdeb[Var]; + while ( il >= 0 ) { + Cnt = NumContrainte[il]; + if ( ContrainteInactive[Cnt] == OUI_PNE ) goto ContrainteSuivante_1; + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_CONNU ) goto ContrainteSuivante_1; + CoeffDeVar = A[il]; + if ( fabs( CoeffDeVar ) < VALEUR_NULLE ) goto ContrainteSuivante_1; + if ( CoeffDeVar > 0.0 ) { + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + X = ( CBarreMax / CoeffDeVar ) + LambdaMin[Cnt]; + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( X < LambdaMax[Cnt] ) { + LambdaMax[Cnt] = X; + *NbModifications = *NbModifications + 1; + # if TRACES == 1 + printf("LambdaMax ameliore sur la contrainte %d: %e\n",Cnt,LambdaMax[Cnt]); + # endif + } + } + else { + /* Borne sur LambdaMax */ + LambdaMax[Cnt] = X; + *NbModifications = *NbModifications + 1; + # if TRACES == 1 + printf("LambdaMax ameliore sur la contrainte %d: %e\n",Cnt,LambdaMax[Cnt]); + # endif + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU ) ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_ET_MAX_CONNU; + else ConnaissanceDeLambda[Cnt] = LAMBDA_MAX_CONNU; + } + } + } + else { + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + X = ( CBarreMax / CoeffDeVar ) + LambdaMax[Cnt]; + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( X > LambdaMin[Cnt] ) { + LambdaMin[Cnt] = X; + *NbModifications = *NbModifications + 1; + # if TRACES == 1 + printf("LambdaMin ameliore sur la contrainte %d: %e\n",Cnt,LambdaMax[Cnt]); + # endif + } + } + else { + /* Borne sur LambdaMin */ + LambdaMin[Cnt] = X; + *NbModifications = *NbModifications + 1; + # if TRACES == 1 + printf("LambdaMin ameliore sur la contrainte %d: %e\n",Cnt,LambdaMax[Cnt]); + # endif + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU ) ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_ET_MAX_CONNU; + else ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_CONNU; + } + } + } + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( fabs( LambdaMin[Cnt] - LambdaMax[Cnt] ) < VALEUR_NULLE ) { + Lambda[Cnt] = 0.5 * ( LambdaMin[Cnt] + LambdaMax[Cnt] ); + LambdaMin[Cnt] = Lambda[Cnt]; + LambdaMax[Cnt] = Lambda[Cnt]; + ConnaissanceDeLambda[Cnt] = LAMBDA_CONNU; + *NbModifications = *NbModifications + 1; + } + } + ContrainteSuivante_1: + il = Csui[il]; + } + } +} + +if ( MaxSommeDesAiFoisLambdaValide == OUI_PNE ) { + if ( SensCoutReduit == '<' || SensCoutReduit == '=' ) { + /* Le cout reduit est soit negatif ou nul, soit nul */ + il = Cdeb[Var]; + while ( il >= 0 ) { + Cnt = NumContrainte[il]; + if ( ContrainteInactive[Cnt] == OUI_PNE ) goto ContrainteSuivante_2; + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_CONNU ) goto ContrainteSuivante_2; + CoeffDeVar = A[il]; + if ( fabs( CoeffDeVar ) < VALEUR_NULLE ) goto ContrainteSuivante_2; + if ( CoeffDeVar > 0.0 ) { + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + X = ( CBarreMin / CoeffDeVar ) + LambdaMax[Cnt]; + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( X > LambdaMin[Cnt] ) { + LambdaMin[Cnt] = X; + *NbModifications = *NbModifications + 1; + # if TRACES == 1 + printf("LambdaMin ameliore sur la contrainte %d: %e\n",Cnt,LambdaMax[Cnt]); + # endif + } + } + else { + /* Borne sur LambdaMin */ + LambdaMin[Cnt] = X; + *NbModifications = *NbModifications + 1; + # if TRACES == 1 + printf("LambdaMin ameliore sur la contrainte %d: %e\n",Cnt,LambdaMax[Cnt]); + # endif + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU ) ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_ET_MAX_CONNU; + else ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_CONNU; + } + } + } + else { + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + X = ( CBarreMin / CoeffDeVar ) + LambdaMin[Cnt]; + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MAX_CONNU || ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( X < LambdaMax[Cnt] ) { + LambdaMax[Cnt] = X; + *NbModifications = *NbModifications + 1; + # if TRACES == 1 + printf("LambdaMax ameliore sur la contrainte %d: %e\n",Cnt,LambdaMax[Cnt]); + # endif + } + } + else { + /* Borne sur LambdaMax */ + LambdaMax[Cnt] = X; + *NbModifications = *NbModifications + 1; + # if TRACES == 1 + printf("LambdaMax ameliore sur la contrainte %d: %e\n",Cnt,LambdaMax[Cnt]); + # endif + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_CONNU ) ConnaissanceDeLambda[Cnt] = LAMBDA_MIN_ET_MAX_CONNU; + else ConnaissanceDeLambda[Cnt] = LAMBDA_MAX_CONNU; + } + } + } + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) { + if ( fabs( LambdaMin[Cnt] - LambdaMax[Cnt] ) < VALEUR_NULLE ) { + Lambda[Cnt] = 0.5 * ( LambdaMin[Cnt] + LambdaMax[Cnt] ); + LambdaMin[Cnt] = Lambda[Cnt]; + LambdaMax[Cnt] = Lambda[Cnt]; + ConnaissanceDeLambda[Cnt] = LAMBDA_CONNU; + *NbModifications = *NbModifications + 1; + } + } + ContrainteSuivante_2: + il = Csui[il]; + } + } +} + +return; + +} + diff --git a/src/ext/Sirius_Solver/presolve/prs_variables_duales_et_couts_reduits.c b/src/ext/Sirius_Solver/presolve/prs_variables_duales_et_couts_reduits.c new file mode 100644 index 0000000000..fcf5302df0 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_variables_duales_et_couts_reduits.c @@ -0,0 +1,539 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On essai de voir si les contraintes d'admissibilite duale + peuvent conduire a ameliorer des variables duales. + On essaie de voir s'il est possible de fixer des variables + sur la base des couts reduits. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" + +# include "pne_define.h" + +# include "prs_define.h" + +# define ZERO_CBARRE 1.e-7 +# define VALEUR_NULLE 1.e-8 +# define MX_ITER 10 + +# define TRACES 0 +# define TRACES_VARIABLES_FAIBLEMENT_DOMINEES 0 + +# define ELIMINATION_DES_COLONNES_FAIBLEMENT_DOMINEES NON_PNE + +/*----------------------------------------------------------------------------*/ +/* On regarde si on peut fixer des variables entieres ou + resserer des bornes sur les variables */ + +void PRS_VariablesDualesEtCoutsReduits( PRESOLVE * Presolve, int * BorneAmelioree ) +{ +int Var; int NbCycles; PROBLEME_PNE * Pne; int * TypeDeBornePourPresolve; +int NombreDeVariables; int NbModifications; int NbSv; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; + +*BorneAmelioree = NON_PNE; +NbCycles = 0; +NbModifications = 0; + +/* Scanner les colonnes pour resserer les bornes sur la variable qui correspond + a la colonne */ + +while ( NbCycles < MX_ITER ) { + NbCycles++; + NbSv = NbModifications; + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) continue; + PRS_AmeliorerOuCalculerCoutsReduits( Presolve, Var, &NbModifications ); + if ( Pne->YaUneSolution == PROBLEME_INFAISABLE ) return; + } + if ( NbModifications == NbSv ) break; +} + +#if VERBOSE_PRS + printf("-> Examen des couts reduits. Nombre de bornes amelioree ou de variables fixees %d\n",NbModifications); +#endif + +if ( NbModifications > 0 ) *BorneAmelioree = OUI_PNE; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_AmeliorerOuCalculerCoutsReduits( PRESOLVE * Presolve, + int Var, + int * NbModifications ) +{ +int il; int Cnt; double CoeffDeVar; PROBLEME_PNE * Pne; double * LambdaMin; double * LambdaMax; +double * Lambda; int * Cdeb; int * Csui; int * NumContrainte; double * CoutLineaire; +double CBarre; char * ContrainteInactive; double CBarreMin; double CBarreMax; +int NbTCol; int CntInvalide; double CoeffDeVarCntInvalide; char * ConnaissanceDeLambda; +double * A; char TypeBrn; double * ValeurDeXPourPresolve; double * BorneInfPourPresolve; +int * TypeDeVariableNative; double * BorneSupPourPresolve; int * TypeDeBornePourPresolve; +int * TypeDeBorneNative; double * BorneInfNative; double * BorneSupNative; char * SensContrainte; +char * ConserverLaBorneInfDuPresolve; char * ConserverLaBorneSupDuPresolve; +double X; double SommeDesAiFoisLambda; double MinSommeDesAiFoisLambda; double MaxSommeDesAiFoisLambda; +char SommeDesAiFoisLambdaValide; char MinSommeDesAiFoisLambdaValide; char MaxSommeDesAiFoisLambdaValide; +int NbTSommeDesAiFoisLambda; int NbTMinSommeDesAiFoisLambda; int NbTMaxSommeDesAiFoisLambda; +int CntMaxInvalide; double CoeffDeVarCntMaxInvalide; int CntMinInvalide; double CoeffDeVarCntMinInvalide; +char ConnaissanceDeLambdaCnt; char * TypeDeValeurDeBorneInf; char * TypeDeValeurDeBorneSup; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +SensContrainte = Pne->SensContrainteTrav; +A = Pne->ATrav; + +CoutLineaire = Pne->LTrav; +TypeDeVariableNative = Pne->TypeDeVariableTrav; +BorneInfNative = Pne->UminTrav; +BorneSupNative = Pne->UmaxTrav; +TypeDeBorneNative = Pne->TypeDeBorneTrav; + +LambdaMin = Presolve->LambdaMin; +LambdaMax = Presolve->LambdaMax; +Lambda = Presolve->Lambda; +ConnaissanceDeLambda = Presolve->ConnaissanceDeLambda; +ContrainteInactive = Presolve->ContrainteInactive; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +TypeDeValeurDeBorneInf = Presolve->TypeDeValeurDeBorneInf; +TypeDeValeurDeBorneSup = Presolve->TypeDeValeurDeBorneSup; +ConserverLaBorneInfDuPresolve = Presolve->ConserverLaBorneInfDuPresolve; +ConserverLaBorneSupDuPresolve = Presolve->ConserverLaBorneSupDuPresolve; + +/* Produit scalaire du vecteur des variables duales et de la colonne de la variable */ +SommeDesAiFoisLambda = 0.; +SommeDesAiFoisLambdaValide = OUI_PNE; +MinSommeDesAiFoisLambda = 0.; +MinSommeDesAiFoisLambdaValide = OUI_PNE; +MaxSommeDesAiFoisLambda = 0.; +MaxSommeDesAiFoisLambdaValide = OUI_PNE; + +NbTCol = 0; +NbTSommeDesAiFoisLambda = 0; +NbTMinSommeDesAiFoisLambda = 0; +NbTMaxSommeDesAiFoisLambda = 0; + +CntInvalide = -1; +CoeffDeVarCntInvalide = 0.; +CntMaxInvalide = -1; +CoeffDeVarCntMaxInvalide = 0.; +CntMinInvalide = -1; +CoeffDeVarCntMinInvalide = 0.; + +CoeffDeVar = 1.; /* Pour eviter les warning de compilation */ +il = Cdeb[Var]; +while ( il >= 0 ) { + + Cnt = NumContrainte[il]; + if ( ContrainteInactive[Cnt] == OUI_PNE ) goto ContrainteSuivante; + + CoeffDeVar = A[il]; + + if ( CoeffDeVar != 0.0 ) { + NbTCol++; + ConnaissanceDeLambdaCnt = ConnaissanceDeLambda[Cnt]; + if ( ConnaissanceDeLambdaCnt == LAMBDA_CONNU ) { + X = Lambda[Cnt] * CoeffDeVar; + SommeDesAiFoisLambda += X; + MinSommeDesAiFoisLambda += X; + MaxSommeDesAiFoisLambda += X; + NbTSommeDesAiFoisLambda++; + NbTMinSommeDesAiFoisLambda++; + NbTMaxSommeDesAiFoisLambda++; + } + else { + CntInvalide = Cnt; + CoeffDeVarCntInvalide = CoeffDeVar; + SommeDesAiFoisLambdaValide = NON_PNE; + if ( CoeffDeVar > 0.0 ) { + /* MaxSommeDesAiFoisLambda */ + if ( ConnaissanceDeLambdaCnt == LAMBDA_MAX_CONNU || ConnaissanceDeLambdaCnt == LAMBDA_MIN_ET_MAX_CONNU ) { + MaxSommeDesAiFoisLambda += CoeffDeVar * LambdaMax[Cnt]; + NbTMaxSommeDesAiFoisLambda++; + } + else { + MaxSommeDesAiFoisLambdaValide = NON_PNE; + CntMaxInvalide = Cnt; + CoeffDeVarCntMaxInvalide = CoeffDeVar; + } + /* MinSommeDesAiFoisLambda */ + if ( ConnaissanceDeLambdaCnt == LAMBDA_MIN_CONNU || ConnaissanceDeLambdaCnt == LAMBDA_MIN_ET_MAX_CONNU ) { + MinSommeDesAiFoisLambda += CoeffDeVar * LambdaMin[Cnt]; + NbTMinSommeDesAiFoisLambda++; + } + else { + MinSommeDesAiFoisLambdaValide = NON_PNE; + CntMinInvalide = Cnt; + CoeffDeVarCntMinInvalide = CoeffDeVar; + } + } + else { + /* CoeffDeVar < 0 */ + /* MaxSommeDesAiFoisLambda */ + if ( ConnaissanceDeLambdaCnt == LAMBDA_MIN_CONNU || ConnaissanceDeLambdaCnt == LAMBDA_MIN_ET_MAX_CONNU ) { + MaxSommeDesAiFoisLambda += CoeffDeVar * LambdaMin[Cnt]; + NbTMaxSommeDesAiFoisLambda++; + } + else { + MaxSommeDesAiFoisLambdaValide = NON_PNE; + CntMaxInvalide = Cnt; + CoeffDeVarCntMaxInvalide = CoeffDeVar; + } + /* MinSommeDesAiFoisLambda */ + if ( ConnaissanceDeLambdaCnt == LAMBDA_MAX_CONNU || ConnaissanceDeLambdaCnt == LAMBDA_MIN_ET_MAX_CONNU ) { + MinSommeDesAiFoisLambda += CoeffDeVar * LambdaMax[Cnt]; + NbTMinSommeDesAiFoisLambda++; + } + else { + MinSommeDesAiFoisLambdaValide = NON_PNE; + CntMinInvalide = Cnt; + CoeffDeVarCntMinInvalide = CoeffDeVar; + } + } + } + } + + ContrainteSuivante: + if ( SommeDesAiFoisLambdaValide == NON_PNE && MinSommeDesAiFoisLambdaValide == NON_PNE && MaxSommeDesAiFoisLambdaValide == NON_PNE ) { + if ( ( NbTCol - NbTSommeDesAiFoisLambda != 1 ) && ( NbTCol - NbTMinSommeDesAiFoisLambda != 1 ) && ( NbTCol - NbTMaxSommeDesAiFoisLambda != 1 ) ) break; + } + il = Csui[il]; +} + +if ( NbTCol <= 0 ) return; + +/* Examen des couts reduits */ +if ( SommeDesAiFoisLambdaValide == NON_PNE ) { + if ( MinSommeDesAiFoisLambdaValide == OUI_PNE && MaxSommeDesAiFoisLambdaValide == OUI_PNE ) { + if ( fabs( MinSommeDesAiFoisLambda - MaxSommeDesAiFoisLambda ) < VALEUR_NULLE ) { + SommeDesAiFoisLambdaValide = OUI_PNE; + SommeDesAiFoisLambda = 0.5 * ( MinSommeDesAiFoisLambda + MaxSommeDesAiFoisLambda ); + MinSommeDesAiFoisLambda = SommeDesAiFoisLambda; + MaxSommeDesAiFoisLambda = SommeDesAiFoisLambda; + } + } +} +X = CoutLineaire[Var]; +CBarre = X - SommeDesAiFoisLambda; +CBarreMin = X - MaxSommeDesAiFoisLambda; +CBarreMax = X - MinSommeDesAiFoisLambda; + +/* Determination du type de borne le mieux adapte pour contraindre le signe du cout reduit */ +TypeBrn = PRS_ChoisirLaBorneLaPlusContraignantePourLesVariablesDuales( + TypeDeBorneNative[Var], TypeDeBornePourPresolve[Var], + BorneInfPourPresolve[Var], BorneInfNative[Var], + BorneSupPourPresolve[Var], BorneSupNative[Var], + ConserverLaBorneInfDuPresolve[Var], ConserverLaBorneSupDuPresolve[Var], + TypeDeValeurDeBorneInf[Var], TypeDeValeurDeBorneSup[Var] ); + +/* Amelioration des bornes sur les variables duales */ +PRS_AmeliorerBornesDesVariablesDuales( Presolve, Var, TypeBrn, MinSommeDesAiFoisLambda, MinSommeDesAiFoisLambdaValide, + MaxSommeDesAiFoisLambda, MaxSommeDesAiFoisLambdaValide, NbModifications ); + +if ( SommeDesAiFoisLambdaValide == OUI_PNE ) { + if ( CBarre > ZERO_CBARRE ) { + /* Le cout reduit est toujours positif: la variable est sur borne inf */ + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT || TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES ) { + # if TRACES == 1 + printf("-> CBarreValide %e: variable %d fixee a %e UminTrav = %e \n",CBarre,Var,BorneInfPourPresolve[Var],Pne->UminTrav[Var]); + # endif + *NbModifications = *NbModifications + 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneInfPourPresolve[Var] ); return; + } + else { + # if TRACES == 1 + printf("-> variable non bornee %d cout reduit non nul %e cout lineaire %e. Le probleme n'a pas de solution.\n",Var,CoutLineaire[Var],CBarre); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + } + return; + } + if ( CBarre < -ZERO_CBARRE ) { + /* Le cout reduit est toujours negatif: la variable est sur borne sup */ + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT || TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES ) { + # if TRACES == 1 + printf("-> CBarreValide %e: variable %d fixee a %e UmaxTrav = %e\n",CBarre,Var,BorneSupPourPresolve[Var],Pne->UmaxTrav[Var]); + # endif + *NbModifications = *NbModifications + 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneSupPourPresolve[Var] ); return; + } + else { + # if TRACES == 1 + printf("-> variable non bornee %d cout reduit non nul %e cout lineaire %e. Le probleme n'a pas de solution.\n",Var,CoutLineaire[Var],CBarre); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + } + return; + } + + # if ELIMINATION_DES_COLONNES_FAIBLEMENT_DOMINEES == OUI_PNE + else { + /* Cout reduit nul */ + /* Attention pas de variable faiblement dominee si elle est bornee des 2 cotes */ + if ( NbTCol > 1 ) { + /* Weakly dominated column */ + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + /* On fixe la variable sur sa borne inf sauf si c'est une colonne singleton */ + # if TRACES_VARIABLES_FAIBLEMENT_DOMINEES == 1 + printf("-> 1- Variable faiblement dominee %d CBarre % e fixee a sa borne inf\n",Var,CBarre); + printf(" La variable est de type VARIABLE_BORNEE_INFERIEUREMENT\n"); + # endif + *NbModifications = *NbModifications + 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneInfPourPresolve[Var] ); return; + } + else if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + /* On fixe la variable sur sa borne sup sauf si c'est une colonne singleton */ + # if TRACES_VARIABLES_FAIBLEMENT_DOMINEES == 1 + printf("-> 2- Variable faiblement dominee %d CBarre % e fixee a sa borne sup\n",Var,CBarre); + printf(" La variable est de type VARIABLE_BORNEE_SUPERIEUREMENT\n"); + # endif + *NbModifications = *NbModifications + 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneSupPourPresolve[Var] ); return; + } + } + } + # endif + +} + +if ( MaxSommeDesAiFoisLambdaValide == OUI_PNE ) { + /* On dispose donc de CBarreMin */ + + # if TRACES == 1 + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) printf("Variable %d CBarreMin %e VARIABLE_BORNEE_INFERIEUREMENT NbTCol %d\n",Var,CBarreMin,NbTCol); + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) printf("Variable %d CBarreMin %e VARIABLE_BORNEE_SUPERIEUREMENT NbTCol %d\n",Var,CBarreMin,NbTCol); + if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES ) printf("Variable %d CBarreMin %e VARIABLE_BORNEE_DES_DEUX_COTES NbTCol %d\n",Var,CBarreMin,NbTCol); + if ( TypeBrn == VARIABLE_NON_BORNEE ) printf("Variable %d CBarreMin %e VARIABLE_NON_BORNEE NbTCol %d\n",Var,CBarreMin,NbTCol); + # endif + + if ( CBarreMin > ZERO_CBARRE ) { + /* Le cout reduit est toujours positif: la variable est sur borne inf */ + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT || TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES ) { + # if TRACES == 1 + printf("-> CBarreMinValide %e: variable %d fixee a %e UminTrav = %e\n",CBarreMin,Var,BorneInfPourPresolve[Var],Pne->UminTrav[Var]); + # endif + *NbModifications = *NbModifications + 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneInfPourPresolve[Var] ); return; + } + else { + # if TRACES == 1 + if ( TypeBrn == VARIABLE_NON_BORNEE ) { + printf("-> variable non bornee %d cout reduit min %e cout lineaire %e. Le probleme n'a pas de solution\n", + Var,CBarreMin,CoutLineaire[Var]); + } + else if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + printf("-> variable non bornee %d cout reduit min %e cout lineaire %e. Le probleme n'a pas de solution\n", + Var,CoutLineaire[Var],CBarreMin); + } + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + } + else if ( fabs( CBarreMin ) < VALEUR_NULLE ) { + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + # if TRACES == 1 + printf("->Forcing dual constraint grace a CBarreMin nul\n"); + # endif + /* On doit mettre au max */ + il = Cdeb[Var]; + while ( il >= 0 ) { + Cnt = NumContrainte[il]; + if ( ContrainteInactive[Cnt] == NON_PNE && A[il] != 0.0 ) { + if ( ConnaissanceDeLambda[Cnt] != LAMBDA_CONNU ) { + if ( A[il] > 0.0 ) { Lambda[Cnt] = LambdaMax[Cnt]; LambdaMin[Cnt] = Lambda[Cnt]; } + else { Lambda[Cnt] = LambdaMin[Cnt]; LambdaMax[Cnt] = Lambda[Cnt]; } + ConnaissanceDeLambda[Cnt] = LAMBDA_CONNU; + *NbModifications = *NbModifications + 1; + } + } + il = Csui[il]; + } + } + + # if ELIMINATION_DES_COLONNES_FAIBLEMENT_DOMINEES == OUI_PNE + /* Weakly dominated column */ + /* Attention pas de variable faiblement dominee si elle est bornee des 2 cotes */ + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + /* On fixe la variable sur sa borne inf sauf si c'est une colonne singleton */ + if ( NbTCol > 1 ) { + # if TRACES_VARIABLES_FAIBLEMENT_DOMINEES == 1 + printf("-> 1- Variable faiblement dominee %d CBarreMin %e fixee a sa borne inf\n",Var,CBarreMin); + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) printf(" Variable de type VARIABLE_BORNEE_INFERIEUREMENT\n"); + if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES ) printf(" Variable de type VARIABLE_BORNEE_DES_DEUX_COTES\n"); + # endif + *NbModifications = *NbModifications + 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneInfPourPresolve[Var] ); return; + } + } + # endif + + } +} + +if ( MinSommeDesAiFoisLambdaValide == OUI_PNE ) { + /* On dispose donc de CBarreMax */ + + # if TRACES == 1 + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) printf("Variable %d CBarreMax %e VARIABLE_BORNEE_INFERIEUREMENT NbTCol %d\n",Var,CBarreMax,NbTCol); + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) printf("Variable %d CBarreMax %e VARIABLE_BORNEE_SUPERIEUREMENT NbTCol %d\n",Var,CBarreMax,NbTCol); + if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES ) printf("Variable %d CBarreMax %e VARIABLE_BORNEE_DES_DEUX_COTES NbTCol %d\n",Var,CBarreMax,NbTCol); + if ( TypeBrn == VARIABLE_NON_BORNEE ) printf("Variable %d CBarreMax %e VARIABLE_NON_BORNEE NbTCol %d\n",Var,CBarreMax,NbTCol); + # endif + + if ( CBarreMax < -ZERO_CBARRE ) { + /* Le cout reduit est toujours negatif: la variable est sur borne sup */ + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT || TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES ) { + # if TRACES == 1 + printf("->CBarreMaxValide %e: variable %d fixee a %e UmaxTrav = %e\n",CBarreMax,Var,BorneSupPourPresolve[Var],Pne->UmaxTrav[Var]); + # endif + *NbModifications = *NbModifications + 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneSupPourPresolve[Var] ); return; + } + else { + # if TRACES == 1 + printf("-> variable non bornee %d cout reduit max %e cout lineaire %e. Le probleme n'a pas de solution\n", + Var,CBarreMax,CoutLineaire[Var]); + # endif + Pne->YaUneSolution = PROBLEME_INFAISABLE; + return; + } + } + else if ( fabs( CBarreMax ) < VALEUR_NULLE ) { + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + # if TRACES == 1 + printf("-> Forcing dual constraint grace a CBarreMax nul\n"); + # endif + /* On doit mettre ua au min */ + il = Cdeb[Var]; + while ( il >= 0 ) { + Cnt = NumContrainte[il]; + if ( ContrainteInactive[Cnt] == NON_PNE && A[il] != 0.0 ) { + if ( ConnaissanceDeLambda[Cnt] != LAMBDA_CONNU ) { + if ( A[il] > 0.0 ) { Lambda[Cnt] = LambdaMin[Cnt]; LambdaMax[Cnt] = Lambda[Cnt]; } + else { Lambda[Cnt] = LambdaMax[Cnt]; LambdaMin[Cnt] = Lambda[Cnt]; } + ConnaissanceDeLambda[Cnt] = LAMBDA_CONNU; + *NbModifications = *NbModifications + 1; + } + } + il = Csui[il]; + } + } + + # if ELIMINATION_DES_COLONNES_FAIBLEMENT_DOMINEES == OUI_PNE + /* Variable dite "weakly dominated ?" */ + /* Attention pas de variable faiblement dominee si elle est bornee des 2 cotes */ + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + /* On fixe la variable sur sa borne sup sauf si c'est une colonne singleton */ + if ( NbTCol > 1 ) { + # if TRACES_VARIABLES_FAIBLEMENT_DOMINEES == 1 + printf("-> 2- Variable faiblement dominee %d CBarreMax %e fixee a sa borne sup\n",Var,CBarreMax); + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) printf(" Variable de type VARIABLE_BORNEE_SUPERIEUREMENT\n"); + if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES ) printf(" Variable de type VARIABLE_BORNEE_DES_DEUX_COTES\n"); + # endif + *NbModifications = *NbModifications + 1; + PRS_FixerUneVariableAUneValeur( Presolve, Var, BorneSupPourPresolve[Var] ); return; + } + } + # endif + + } +} + +/* Tentative d'amelioration des bornes sur les variables duales */ + +if ( ( CntInvalide >= 0 && CoeffDeVarCntInvalide != 0.0 ) || + ( CntMaxInvalide >= 0 && CoeffDeVarCntMaxInvalide != 0.0 ) || + ( CntMinInvalide >= 0 && CoeffDeVarCntMinInvalide != 0.0 ) ) { + /* On essaie de calculer des variables duales ou des bornes a l'aide la partie disponible de CBarre */ + if ( SommeDesAiFoisLambdaValide == NON_PNE && CntInvalide >= 0 && CoeffDeVarCntInvalide != 0.0 ) { + if ( NbTCol - NbTSommeDesAiFoisLambda == 1 ) { + /* On dispose de CBarre sauf pour une variable duale */ + if ( TypeBrn == VARIABLE_NON_BORNEE ) { + # if TRACES == 1 + printf("On peut calculer un lambda grace a la variable non bornee %d pour la contrainte %d\n",Var,CntInvalide); + # endif + PRS_MajVariableDuale( Presolve, CntInvalide, CBarre, CoeffDeVarCntInvalide, '=', NbModifications ); + } + else if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + # if TRACES == 1 + printf("On peut calculer un lambda min ou max grace a la variable bornee inferieurement %d pour la contrainte %d\n",Var,CntInvalide); + # endif + /* On doit avoir CBarre >= 0 */ + PRS_MajVariableDuale( Presolve, CntInvalide, CBarre, CoeffDeVarCntInvalide, '>', NbModifications ); + } + else if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + # if TRACES == 1 + printf("On peut calculer un lambda min ou max grace a la variable bornee superieurement %d pour la contrainte %d\n",Var,CntInvalide); + # endif + /* On doit avoir CBarre <= 0 */ + PRS_MajVariableDuale( Presolve, CntInvalide, CBarre, CoeffDeVarCntInvalide, '<', NbModifications ); + } + } + } + + if ( MinSommeDesAiFoisLambdaValide == NON_PNE && CntMinInvalide >= 0 && CoeffDeVarCntMinInvalide != 0.0 ) { + if ( NbTCol - NbTMinSommeDesAiFoisLambda == 1 ) { + /* On dispose de CBarreMax sauf pour une variable duale */ + if ( TypeBrn == VARIABLE_BORNEE_INFERIEUREMENT ) { + # if TRACES == 1 + printf("On peut calculer un lambda min ou max grace a la variable bornee inferieurement %d pour la contrainte %d\n",Var,CntInvalide); + # endif + /* On doit avoir CBarre >= 0 */ + PRS_MajVariableDuale( Presolve, CntMinInvalide, CBarreMax, CoeffDeVarCntMinInvalide, '>', NbModifications ); + return; + } + } + } + + if ( MaxSommeDesAiFoisLambdaValide == NON_PNE && CntMaxInvalide >= 0 && CoeffDeVarCntMaxInvalide != 0.0 ) { + if ( NbTCol - NbTMaxSommeDesAiFoisLambda == 1 ) { + /* On dispose de CBarreMin sauf pour une variable duale */ + if ( TypeBrn == VARIABLE_BORNEE_SUPERIEUREMENT ) { + # if TRACES == 1 + printf("On peut calculer un lambda min ou max grace a la variable bornee superieurement %d pour la contrainte %d\n",Var,CntInvalide); + # endif + /* On doit avoir CBarre <= 0 */ + PRS_MajVariableDuale( Presolve, CntMaxInvalide, CBarreMin, CoeffDeVarCntMaxInvalide, '<', NbModifications ); + return; + } + } + } +} + +return; + +} + diff --git a/src/ext/Sirius_Solver/presolve/prs_variables_duales_non_bornees.c b/src/ext/Sirius_Solver/presolve/prs_variables_duales_non_bornees.c new file mode 100644 index 0000000000..907012971b --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_variables_duales_non_bornees.c @@ -0,0 +1,117 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Pour les variables duales dont une seule ou aucune borne n'est + connue on cherche des variables qui permettent d'etablir la + borne manquante. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES 0 +# define MAX_ITER 10 + +/*----------------------------------------------------------------------------*/ + +void PRS_BornerLesVariablesDualesNonBornees( PRESOLVE * Presolve, int * NombreDeBornesCalculees ) +{ +int NbIter; int Nb; int il; int ilMax; int Cnt; int NombreDeContraintes; int Var; +char TypeBrn; char BorneInfCalculee; char BorneSupCalculee; double BorneInf; double BorneSup; +double * BorneInfPourPresolve; double * BorneInfNative; double * BorneSupPourPresolve; +double * BorneSupNative; int * Mdeb; int * NbTerm; int * Nuvar; int * TypeDeBorneNative; +int * TypeDeBornePourPresolve; char * ContrainteInactive; char * ConnaissanceDeLambda; +char * ConserverLaBorneInfDuPresolve; char * ConserverLaBorneSupDuPresolve; double * A; +char UneBorneAEteCalculee; char * TypeDeValeurDeBorneInf; char * TypeDeValeurDeBorneSup; +PROBLEME_PNE * Pne; + +*NombreDeBornesCalculees = 0; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NombreDeContraintes = Pne->NombreDeContraintesTrav; +Mdeb = Pne->MdebTrav; +NbTerm = Pne->NbTermTrav; +Nuvar = Pne->NuvarTrav; +A = Pne->ATrav; + +TypeDeBorneNative = Pne->TypeDeBorneTrav; +BorneInfNative = Pne->UminTrav; +BorneSupNative = Pne->UmaxTrav; + +ContrainteInactive = Presolve->ContrainteInactive; +ConnaissanceDeLambda = Presolve->ConnaissanceDeLambda; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +TypeDeValeurDeBorneInf = Presolve->TypeDeValeurDeBorneInf; +TypeDeValeurDeBorneSup = Presolve->TypeDeValeurDeBorneSup; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +ConserverLaBorneInfDuPresolve = Presolve->ConserverLaBorneInfDuPresolve; +ConserverLaBorneSupDuPresolve = Presolve->ConserverLaBorneSupDuPresolve; + +NbIter = 0; +while ( NbIter < MAX_ITER ) { + NbIter++; + Nb = *NombreDeBornesCalculees; + for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ContrainteInactive[Cnt] == OUI_PNE ) continue; + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_CONNU ) continue; + if ( ConnaissanceDeLambda[Cnt] == LAMBDA_MIN_ET_MAX_CONNU ) continue; + + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( A[il] == 0 ) goto NextIl; + Var = Nuvar[il]; + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) goto NextIl; + TypeBrn = PRS_ChoisirLaBorneLaPlusContraignantePourLesVariablesDuales( + TypeDeBorneNative[Var], TypeDeBornePourPresolve[Var], + BorneInfPourPresolve[Var], BorneInfNative[Var], + BorneSupPourPresolve[Var], BorneSupNative[Var], + ConserverLaBorneInfDuPresolve[Var], ConserverLaBorneSupDuPresolve[Var], + TypeDeValeurDeBorneInf[Var], TypeDeValeurDeBorneSup[Var] ); + if ( TypeBrn == VARIABLE_BORNEE_DES_DEUX_COTES ) goto NextIl; + /* On peut etablir une contrainte sur le cout reduit */ + PRS_CalculeBorneSurVariableDualeEnFonctionDeLaVariable( Presolve, Cnt, Var, TypeBrn, + &BorneInfCalculee, &BorneInf, + &BorneSupCalculee, &BorneSup ); + PRS_MettreAJourLesBornesDUneVariableDuale( Presolve, Cnt, + BorneInfCalculee, BorneInf, BorneSupCalculee, BorneSup, + &UneBorneAEteCalculee ); + if ( UneBorneAEteCalculee == OUI_PNE ) *NombreDeBornesCalculees = *NombreDeBornesCalculees + 1; + NextIl: + il++; + } + } + if ( *NombreDeBornesCalculees == Nb ) break; +} + +#if VERBOSE_PRS + printf("-> Nombre de bornes duales infinies qui ont pu etre ramenees a une valeur finie: %d\n",*NombreDeBornesCalculees); +#endif + +return; +} diff --git a/src/ext/Sirius_Solver/presolve/prs_variables_hors_contraintes.c b/src/ext/Sirius_Solver/presolve/prs_variables_hors_contraintes.c new file mode 100644 index 0000000000..0c5c752085 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_variables_hors_contraintes.c @@ -0,0 +1,124 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Cas lineaire pur: on regarde si une variable n'intervient + pas dans les contraintes. Dans ce cas, on la fixe sur une + borne en fonctions du signe de son cout lineaire. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +/*----------------------------------------------------------------------------*/ + +void PRS_VariablesHorsContraintes( PRESOLVE * Presolve, int * NbModifications ) +{ +int Cnt; int il; int Var; char LaVariableEstContrainte; int Nbs; int NombreDeVariables; +double * ValeurDeXPourPresolve; int * TypeDeBornePourPresolve; int * Cdeb; int * Csui; +int * NumContrainte; double * A; char * ContrainteInactive; double * CoutLineaire; +double * BorneInfPourPresolve; double * BorneSupPourPresolve; PROBLEME_PNE * Pne; +int * TypeDeBorneNative; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NombreDeVariables = Pne->NombreDeVariablesTrav; +CoutLineaire = Pne->LTrav; +TypeDeBorneNative = Pne->TypeDeVariableTrav; + +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; +A = Pne->ATrav; + +ValeurDeXPourPresolve = Presolve->ValeurDeXPourPresolve; +BorneInfPourPresolve = Presolve->BorneInfPourPresolve; +BorneSupPourPresolve = Presolve->BorneSupPourPresolve; +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ContrainteInactive = Presolve->ContrainteInactive; + +Nbs = 0; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) continue; + LaVariableEstContrainte = NON_PNE; + il = Cdeb[Var]; + while ( il >= 0 ) { + Cnt = NumContrainte[il]; + if ( A[il] != 0.0 ) { + if ( ContrainteInactive[Cnt] == NON_PNE ) { + /* Dans ce cas la variable est contrainte et on ne fait rien */ + LaVariableEstContrainte = OUI_PNE; + break; + } + } + il = Csui[il]; + } + + if ( LaVariableEstContrainte == OUI_PNE ) continue; + + /* La variable n'est contrainte que par ses bornes */ + Nbs++; + if ( CoutLineaire[Var] > 0. ) { + if ( TypeDeBornePourPresolve[Var] == VARIABLE_NON_BORNEE || + TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + *NbModifications = 0; + Pne->YaUneSolution = PROBLEME_NON_BORNE; + printf("*** Phase de Presolve. Pas de solution car la variable %d est hors contraintes, son cout est %lf et elle est de type ", + Var,CoutLineaire[Var]); + return; + } + else ValeurDeXPourPresolve[Var] = BorneInfPourPresolve[Var]; + } + else if ( CoutLineaire[Var] < 0. ) { + if ( TypeDeBornePourPresolve[Var] == VARIABLE_NON_BORNEE || + TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + *NbModifications = 0; + Pne->YaUneSolution = PROBLEME_NON_BORNE; + printf("*** Phase de Presolve. Pas de solution car la variable %d est hors contraintes, son cout est %lf et elle est de type ", + Var,CoutLineaire[Var]); + return; + } + else ValeurDeXPourPresolve[Var] = BorneSupPourPresolve[Var]; + } + else { + /* Le cout de la variable est nul, on la met a 0 */ + ValeurDeXPourPresolve[Var] = 0.; + } + TypeDeBornePourPresolve[Var] = VARIABLE_FIXE; + + TypeDeBorneNative[Var] = REEL; /* On change le type pour etre tranquille */ +} + +#if VERBOSE_PRS + printf("-> Nombre de variables supprimees car n'intervenant pas dans les contraintes: %d\n",Nbs); +#endif + +*NbModifications = Nbs; + +return; +} + + diff --git a/src/ext/Sirius_Solver/presolve/prs_variables_non_bornees.c b/src/ext/Sirius_Solver/presolve/prs_variables_non_bornees.c new file mode 100644 index 0000000000..e4f6c8d7e9 --- /dev/null +++ b/src/ext/Sirius_Solver/presolve/prs_variables_non_bornees.c @@ -0,0 +1,117 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Pour les variables dont une seule ou aucune borne n'est connue + on cherche des contraintes qui permettent d'etablir la borne + manquante. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "prs_sys.h" + +# include "prs_fonctions.h" +# include "prs_define.h" + +# include "pne_fonctions.h" +# include "pne_define.h" + +# define TRACES 0 +# define MAX_ITER 10 + +/*----------------------------------------------------------------------------*/ + +void PRS_BornerLesVariablesNonBornees( PRESOLVE * Presolve, int * NombreDeBornesCalculees ) +{ +int Cnt; int * Cdeb; int * Csui; int NombreDeVariables; char * ContrainteInactive; +int * NumContrainte; int ic; int Var; double * A; int * TypeDeBornePourPresolve; +int Nb; int NbIter; PROBLEME_PNE * Pne; + +*NombreDeBornesCalculees = 0; + +Pne = (PROBLEME_PNE *) Presolve->ProblemePneDuPresolve; + +NombreDeVariables = Pne->NombreDeVariablesTrav; + +A = Pne->ATrav; +Cdeb = Pne->CdebTrav; +Csui = Pne->CsuiTrav; +NumContrainte = Pne->NumContrainteTrav; + +TypeDeBornePourPresolve = Presolve->TypeDeBornePourPresolve; +ContrainteInactive = Presolve->ContrainteInactive; + +NbIter = 0; +while ( NbIter < MAX_ITER ) { + NbIter++; + Nb = *NombreDeBornesCalculees; + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) continue; + if ( TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) continue; + /* On cherche une contrainte qui pourrait permettre de borner la variable */ + ic = Cdeb[Var]; + while ( ic >= 0 ) { + if ( A[ic] != 0 ) { + Cnt = NumContrainte[ic]; + if ( ContrainteInactive[Cnt] != OUI_PNE ) { + PRS_TenterUnCalculDeBorne( Presolve, Cnt, Var, NombreDeBornesCalculees ); + /* Le type de borne a pu changer */ + if ( TypeDeBornePourPresolve[Var] == VARIABLE_FIXE ) break; + if ( TypeDeBornePourPresolve[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) break; + } + } + ic = Csui[ic]; + } + } + if ( *NombreDeBornesCalculees == Nb ) break; +} + +#if VERBOSE_PRS + printf("-> Nombre de bornes infinies qui ont pu etre ramenees a une valeur finie: %d\n",*NombreDeBornesCalculees); +#endif + +return; +} + +/*----------------------------------------------------------------------------*/ + +void PRS_TenterUnCalculDeBorne( PRESOLVE * Presolve, int Cnt, int VarTest, int * NombreDeBornesCalculees ) +{ +char BorneInfCalculee; char BorneSupCalculee; double BorneInf; double BorneSup; +char UneBorneAEteCalculee; + +UneBorneAEteCalculee = NON_PNE; + +PRS_CalculeBorneSurVariableEnFonctionDeLaContrainte( Presolve, Cnt, VarTest, &BorneInfCalculee, &BorneInf, + &BorneSupCalculee, &BorneSup ); + +if ( BorneInfCalculee == NON_PNE && BorneSupCalculee == NON_PNE ) return; + +/* Remarque: on est forcement dans le cas ou il manque 1 ou 2 bornes */ + +PRS_MettreAJourLesBornesDUneVariable( Presolve, VarTest, + BorneInfCalculee, BorneInf, Cnt, + BorneSupCalculee, BorneSup, Cnt, + &UneBorneAEteCalculee ); + +if ( UneBorneAEteCalculee == OUI_PNE ) *NombreDeBornesCalculees = *NombreDeBornesCalculees + 1; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_allouer_lu.c b/src/ext/Sirius_Solver/simplexe/lu/lu_allouer_lu.c new file mode 100644 index 0000000000..bc68a3ae1f --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_allouer_lu.c @@ -0,0 +1,900 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Allouer / desallouer les tableaux pour la factoristion LU + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +# define COEFF_MULT 1.5 + +/*----------------------------------------------------------------------------*/ +/* On initialise et on alloue les zones de travail */ + +void LU_AllouerLU( MATRICE * Matrice, + double * ValeurDesTermesDeLaMatrice, + int * IndicesDeLigne , + int * Ideb, + int * NbTermesDesColonnes, + int * NbColonnes + ) + +{ +int i ; int il ; int ilk ; int NbTrm; int NbCol; +int NbTrm_L; int NbTrm_U; int NbTrmAux; int Dispo; + +/* Decompte du nombre de termes */ +NbCol = *NbColonnes; +for ( NbTrm = 0 , i = 0 ; i < NbCol ; i++ ) NbTrm+= NbTermesDesColonnes[i]; + +#if VERBOSE_LU + printf("LU_AllouerLU: Nombre de termes non nuls de la matrice %d\n",NbTrm); +#endif + +/********* Pour sortir la matrice si debogage necessaire **********/ +/* +{ +FILE * Flot; int ilMax; + +Flot = fopen( "Matrice.mtx", "w" ); +if( Flot == NULL ) { + printf("Erreur ouverture du fichier pour l'ecriture de la matrice \n"); + exit(0); +} + +fprintf(Flot,"%d %d %d\n",NbCol,NbCol,NbTrm); + +for ( i = 0 ; i < NbCol ; i++ ) { + il = Ideb[i]; + ilMax = il + NbTermesDesColonnes[i]; + while ( il < ilMax ) { + fprintf(Flot,"%d %d %e\n",IndicesDeLigne[il]+1,i+1,ValeurDesTermesDeLaMatrice[il]); + il++; + } +} +fclose(Flot); +} +*/ +/******************************************************************/ +Matrice->NombreDeTermesDeLaMatriceAFactoriser = NbTrm; +Matrice->NombreDeTermes = NbTrm; + +NbTrm_L = NbTrm + INCREMENT_DALLOCATION_DE_L; +NbTrm_U = NbTrm + INCREMENT_DALLOCATION_DE_U; +/* Calcul de la marge disponible pour la creation des termes */ +/* On ajoute du disponible par rapport ŕ la matrice d'entree */ +Dispo = NbTrm; +Matrice->MargePourCreationDeTermesLignes = (int) floor( (double)Dispo / NbCol ) + 1; +if ( Matrice->MargePourCreationDeTermesLignes < MARGE_MINIMALE_POUR_CREATION_DE_TERMES ) { + Matrice->MargePourCreationDeTermesLignes = MARGE_MINIMALE_POUR_CREATION_DE_TERMES; +} +Matrice->MargePourCreationDeTermesColonnes = Matrice->MargePourCreationDeTermesLignes << 1; + +/* Calcul du total a allouer */ + +/* Prevoir de doubler au lieu d'ajouter les increments */ + +Matrice->TailleAlloueeLignes = NbTrm + ( NbCol * Matrice->MargePourCreationDeTermesLignes ) + + L_INCREMENT_DALLOCATION; +Matrice->TailleAlloueeColonnes = NbTrm + ( NbCol * Matrice->MargePourCreationDeTermesColonnes ) + + C_INCREMENT_DALLOCATION; + +Matrice->TailleAlloueeLignes = (int) ( Matrice->TailleAlloueeLignes * COEFF_MULT ); +Matrice->TailleAlloueeColonnes = (int) ( Matrice->TailleAlloueeColonnes * COEFF_MULT ); + +Matrice->LDernierIndexLibrePossible = Matrice->TailleAlloueeLignes - 1; +Matrice->CDernierIndexLibrePossible = Matrice->TailleAlloueeColonnes - 1; +/* +printf(" Matrice.TailleAllouee %d MargePourCreationDeTermes %d\n",Matrice->TailleAlloueeLignes,Matrice->MargePourCreationDeTermesLignes); +*/ + +Matrice->LIncrementDallocation = L_INCREMENT_DALLOCATION; +Matrice->CIncrementDallocation = C_INCREMENT_DALLOCATION; + +Matrice->IncrementDallocationDeL = INCREMENT_DALLOCATION_DE_L; +Matrice->IncrementDallocationDeU = INCREMENT_DALLOCATION_DE_U; + +Matrice->LignePrecedente = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->LigneSuivante = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->Ldeb = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->LNbTerm = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->LDernierPossible = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->LIndiceColonne = (int *) malloc( Matrice->TailleAlloueeLignes * sizeof( int ) ); +Matrice->Elm = (double *) malloc( Matrice->TailleAlloueeLignes * sizeof( double) ); + +Matrice->ColonnePrecedente = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->ColonneSuivante = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->Cdeb = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->CNbTerm = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->CNbTermMatriceActive = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->CDernierPossible = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->CIndiceLigne = (int *) malloc( Matrice->TailleAlloueeColonnes * sizeof( int ) ); + +if ( Matrice->UtiliserLesSuperLignes == OUI_LU ) { + Matrice->SuperLigneDeLaLigne = (SUPER_LIGNE_DE_LA_MATRICE **) malloc( NbCol * sizeof( void * ) ); + Matrice->SuperLigneAScanner = (SUPER_LIGNE_DE_LA_MATRICE **) malloc( NbCol * sizeof( void * ) ); + Matrice->SuperLigne = (SUPER_LIGNE_DE_LA_MATRICE **) malloc( NbCol * sizeof( void * ) ); + Matrice->PoidsDesColonnes = (int *) malloc( NbCol * sizeof( int ) ); + + Matrice->HashModuloSize = NbCol; + Matrice->HashCodeLigne = (unsigned int *) malloc( NbCol * sizeof( unsigned int ) ); + Matrice->HashCodeSuperLigne = (unsigned int *) malloc( NbCol * sizeof( unsigned int ) ); + Matrice->HashModuloPrem = (int *) malloc( NbCol * sizeof( int ) ); + Matrice->HashNbModuloIdentiques = (int *) malloc( NbCol * sizeof( int ) ); + i = 2 * NbCol; + Matrice->TypeDeClassementHashCodeAFaire = (char *) malloc( i * sizeof( char ) ); + Matrice->HashModuloSuiv = (int *) malloc( i * sizeof( int ) ); + Matrice->HashModuloPrec = (int *) malloc( i * sizeof( int ) ); +} + +Matrice->LigneRejeteeTemporairementPourPivotage = (char *) malloc( NbCol * sizeof( char ) ); +Matrice->ColonneRejeteeTemporairementPourPivotage = (char *) malloc( NbCol * sizeof( char ) ); + +Matrice->AbsDuPlusGrandTermeDeLaLigne = (double *) malloc( NbCol * sizeof( double ) ); + +Matrice->PremLigne = (int *) malloc( ( NbCol + 1 ) * sizeof( int ) ); +Matrice->SuivLigne = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->PrecLigne = (int *) malloc( NbCol * sizeof( int ) ); + +Matrice->PremColonne = (int *) malloc( ( NbCol + 1 ) * sizeof( int ) ); +Matrice->SuivColonne = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->PrecColonne = (int *) malloc( NbCol * sizeof( int ) ); + +Matrice->W = (double *) malloc( NbCol * sizeof( double ) ); +Matrice->Marqueur = (char *) malloc( NbCol * sizeof( char ) ); + +Matrice->OrdreLigne = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->InverseOrdreLigne = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->OrdreColonne = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->InverseOrdreColonne = (int *) malloc( NbCol * sizeof( int ) ); + +Matrice->NbTermesParColonneDeL = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->CdebParColonneDeL = (int *) malloc( NbCol * sizeof( int ) ); +Matrice->ElmDeL = (double *) malloc( NbTrm_L * sizeof( double ) ); +Matrice->IndiceLigneDeL = (int *) malloc( NbTrm_L * sizeof( int ) ); + +Matrice->SolutionIntermediaire = (double *) malloc( NbCol * sizeof( double ) ); + +if ( + Matrice->LignePrecedente == NULL || + Matrice->LigneSuivante == NULL || + Matrice->Ldeb == NULL || + Matrice->LNbTerm == NULL || + Matrice->LDernierPossible == NULL || + Matrice->LIndiceColonne == NULL || + Matrice->Elm == NULL || + + Matrice->ColonnePrecedente == NULL || + Matrice->ColonneSuivante == NULL || + Matrice->Cdeb == NULL || + Matrice->CNbTerm == NULL || + Matrice->CNbTermMatriceActive == NULL || + Matrice->CDernierPossible == NULL || + Matrice->CIndiceLigne == NULL || + + ( Matrice->UtiliserLesSuperLignes == OUI_LU && + ( Matrice->SuperLigneDeLaLigne == NULL || + Matrice->SuperLigneAScanner == NULL || + Matrice->SuperLigne == NULL || + Matrice->PoidsDesColonnes == NULL || + + Matrice->HashCodeLigne == NULL || + Matrice->HashCodeSuperLigne == NULL || + Matrice->HashModuloPrem == NULL || + Matrice->HashNbModuloIdentiques == NULL || + + Matrice->TypeDeClassementHashCodeAFaire == NULL || + Matrice->HashModuloSuiv == NULL || + Matrice->HashModuloPrec == NULL + ) + ) || + + Matrice->LigneRejeteeTemporairementPourPivotage == NULL || + Matrice->ColonneRejeteeTemporairementPourPivotage == NULL || + + Matrice->AbsDuPlusGrandTermeDeLaLigne == NULL || + + Matrice->PremLigne == NULL || + Matrice->SuivLigne == NULL || + Matrice->PrecLigne == NULL || + + Matrice->PremColonne == NULL || + Matrice->SuivColonne == NULL || + Matrice->PrecColonne == NULL || + + Matrice->W == NULL || + Matrice->Marqueur == NULL || + + Matrice->OrdreLigne == NULL || + Matrice->InverseOrdreLigne == NULL || + Matrice->OrdreColonne == NULL || + Matrice->InverseOrdreColonne == NULL || + + Matrice->NbTermesParColonneDeL == NULL || + Matrice->CdebParColonneDeL == NULL || + Matrice->ElmDeL == NULL || + Matrice->IndiceLigneDeL == NULL || + + Matrice->SolutionIntermediaire == NULL + + ) + { + + printf("Factorisation LU, sous-programme LU_AllouerLU: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); + +} + +if ( Matrice->UtiliserLesSuperLignes == OUI_LU ) { + il = (int) floor( 0.5 * RAND_MAX ); + for ( i = 0 ; i < NbCol ; i++ ) { + Matrice->SuperLigneDeLaLigne[i]= NULL; + if ( rand() < il ) Matrice->PoidsDesColonnes[i] = i; + else Matrice->PoidsDesColonnes[i] = i << 1; + } + Matrice->NombreDeSuperLignes = 0; +} + +if ( Matrice->FaireScaling == OUI_LU ) { + Matrice->ScaleX = (double *) malloc( NbCol * sizeof( double ) ); + Matrice->ScaleB = (double *) malloc( NbCol * sizeof( double ) ); + if ( Matrice->ScaleX == NULL || Matrice->ScaleB == NULL ) { + printf("Factorisation LU, sous-programme LU_AllouerLU: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); + } +} + +# ifdef HYPER_CREUX + Matrice->ListeDesNoeuds = NULL; + Matrice->NoeudDansLaliste = NULL; + Matrice->PseudoPile = NULL; +# endif + +if ( Matrice->FaireDuPivotageDiagonal == OUI_LU) { + Matrice->AbsValeurDuTermeDiagonal = (double *) malloc( NbCol * sizeof( double ) ); + if ( Matrice->AbsValeurDuTermeDiagonal == NULL ) { + printf("Factorisation LU, sous-programme LU_AllouerLU: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); + } +} + +/* Recherche du plus grand index adressable dans la matrice d'entree */ +NbTrmAux = -1; +for ( i = 0 ; i < NbCol ; i++ ) { + ilk = Ideb[i] + NbTermesDesColonnes[i] - 1; + if ( ilk > NbTrmAux ) NbTrmAux = ilk; +} +NbTrmAux++; + +LU_ConstruireProbleme( Matrice, ValeurDesTermesDeLaMatrice, IndicesDeLigne, Ideb, NbTermesDesColonnes, + NbCol, NbTrm_L, NbTrm_U ); + +Matrice->NombreDeLuUpdates = 0; /* Car utilise dans la resolution */ + +Matrice->SauvegardeDuResultatIntermediaire = NON_LU; /* Car utilise dans la resolution */ + +if ( Matrice->ContexteDeLaFactorisation == LU_SIMPLEXE ) { + + Matrice->NombreDeVecteursHAlloues = NOMBRE_INITIAL_DE_VECTEURS_H_ALLOUES; + i = Matrice->NombreDeVecteursHAlloues * sizeof( int ); + Matrice->HDeb = (int *) malloc( i ); + Matrice->HLigne = (int *) malloc( i ); + Matrice->HNbTerm = (int *) malloc( i ); + + /* En moyenne 10% de termes par colonne par rapport au nombre de lignes de la matrice */ + /*i = (int) (0.1 * (float) NbCol);*/ + /* Il ne faut pas etre trop restrictif sinon on refactorise trop souvent ce qui nuit a l'efficacite de la LU update */ + i = (int) (0.4 * (float) NbCol); + if ( i < 100 ) i = 100; + + Matrice->NombreDElementsHAlloues = Matrice->NombreDeVecteursHAlloues * i; + + Matrice->HIndiceColonne = (int *) malloc( Matrice->NombreDElementsHAlloues * sizeof( int ) ); + Matrice->HValeur = (double *) malloc( Matrice->NombreDElementsHAlloues * sizeof( double ) ); + + Matrice->IndicesLignesDuSpike = (int *) malloc( Matrice->Rang * sizeof( int ) ); + Matrice->ValeurElmSpike = (double *) malloc( Matrice->Rang * sizeof( double ) ); + + /* Matrice->NombreDeLuUpdates = 0; */ + Matrice->IndexHLibre = 0; + + Matrice->NbTermesCreesLuUpdate = 0; + +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* On augmente la taille d'une ligne de la matrice active */ + +void LU_AugmenterLaTailleDeLaMatriceActive( MATRICE * Matrice , int Ligne , int TailleDemandee ) +{ +int NbElements; int MargePourCreationDeTermesLignes; int il; int ilMax; int Nb; int ix; +int ilNew; int NbElemNew; int L; int L1; int L2; int CapaciteRestante; +int * Ldeb; int * LNbTerm;int * LIndiceColonne; double * Elm; int * LDernierPossible; +int * LIndiceColonneNew; double * ElmNew; int * LignePrecedente; int * LigneSuivante; +int Kp; int * InverseOrdreLigne; + +/*printf("LU_AugmenterLaTailleDeLaMatriceActive Ligne %d Kp %d\n",Ligne,Matrice->Kp);*/ + +MargePourCreationDeTermesLignes = Matrice->MargePourCreationDeTermesLignes; + +/* S'il y a assez de place a la fin, on l'utilise */ +NbElements = TailleDemandee + MargePourCreationDeTermesLignes; +if ( Matrice->LIndexLibre + NbElements - 1 <= Matrice->LDernierIndexLibrePossible ) { + DeplacerLigne: + il = Matrice->Ldeb[Ligne]; + Nb = Matrice->LNbTerm[Ligne]; + ix = Matrice->LDernierPossible[Ligne]; + memcpy( (char *) &(Matrice->LIndiceColonne[Matrice->LIndexLibre]), (char *) &(Matrice->LIndiceColonne[il]), Nb * sizeof( int ) ); + memcpy( (char *) &(Matrice->Elm[Matrice->LIndexLibre]) , (char *) &(Matrice->Elm[il]) , Nb * sizeof( double ) ); + Matrice->Ldeb [Ligne] = Matrice->LIndexLibre; + Matrice->LDernierPossible[Ligne] = Matrice->LIndexLibre + NbElements - 1; + Matrice->LIndexLibre += NbElements; + L1 = Matrice->LignePrecedente[Ligne]; + L2 = Matrice->LigneSuivante[Ligne]; + if ( L1 >= 0 ) { + Matrice->LDernierPossible[L1] = ix; + if ( L2 >= 0 ) { + Matrice->LigneSuivante [L1] = L2; + Matrice->LignePrecedente [L2] = L1; + } + } + else { + if ( L2 >= 0 ) Matrice->LignePrecedente[L2] = -1; + } + if ( Ligne != Matrice->DerniereLigne ) { + Matrice->LignePrecedente[Ligne] = Matrice->DerniereLigne; + Matrice->LigneSuivante[Matrice->DerniereLigne] = Ligne; + Matrice->LigneSuivante[Ligne] = -1; + Matrice->DerniereLigne = Ligne; + } + return; +} +else { + /* Il faut redimensionner tout le triangle */ + # if VERBOSE_LU + printf(" Redimensionnement lignes necessaire Kp %d Rang %d\n",Matrice->Kp,Matrice->Rang); + # endif + /* On reconstitue les marges et on ajoute un increment */ + NbElemNew = 0; + Kp = Matrice->Kp; + InverseOrdreLigne = Matrice->InverseOrdreLigne; + LNbTerm = Matrice->LNbTerm; + NbElemNew = 0; + for ( L = 0 ; L < Matrice->Rang ; L++ ) { + NbElemNew += LNbTerm[L]; + if ( InverseOrdreLigne[L] > Kp ) NbElemNew += MargePourCreationDeTermesLignes; + } + NbElemNew += NbElements + Matrice->LIncrementDallocation; + if ( Matrice->LIncrementDallocation < L_INCREMENT_DALLOCATION << SHIFT_MAX_INCREMENT ) { + Matrice->LIncrementDallocation *= 2; + } + NbElemNew = (int) ( NbElemNew * COEFF_MULT ); + LIndiceColonneNew = (int *) malloc( NbElemNew * sizeof( int ) ); + ElmNew = (double *) malloc( NbElemNew * sizeof( double ) ); + if ( LIndiceColonneNew == NULL || ElmNew == NULL ) { + printf("Factorisation LU, sous-programme LU_AugmenterLaTailleDeLaMatriceActive: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); + } + /* On recopie terme a terme pour recuperer aussi la place qu'on perdue en supprimant une ligne + qui se trouvait etre la premiere dans le stockage, et les extensions exagerees */ + Matrice->LDernierIndexLibrePossible = NbElemNew - 1; + + ilNew = 0; + LignePrecedente = Matrice->LignePrecedente; + LigneSuivante = Matrice->LigneSuivante; + Ldeb = Matrice->Ldeb; + LIndiceColonne = Matrice->LIndiceColonne; + Elm = Matrice->Elm; + LDernierPossible = Matrice->LDernierPossible; + for ( L = 0 ; L < Matrice->Rang ; L++ ) { + il = Ldeb[L]; + Nb = LNbTerm[L]; + ilMax = il + Nb; + + if ( InverseOrdreLigne[L] > Kp ) { + /* + CapaciteRestante = LDernierPossible[L] - ilMax + 1; + if ( CapaciteRestante > MargePourCreationDeTermesLignes ) CapaciteRestante = MargePourCreationDeTermesLignes; + else if ( CapaciteRestante < 0 ) CapaciteRestante = MargePourCreationDeTermesLignes; + */ + CapaciteRestante = MargePourCreationDeTermesLignes; + if ( L == Ligne ) CapaciteRestante += TailleDemandee; + } + else CapaciteRestante = 0; + + Ldeb[L] = ilNew; + while ( il < ilMax ) { + LIndiceColonneNew[ilNew] = LIndiceColonne[il]; + ElmNew [ilNew] = Elm[il]; + ilNew++; + il++; + } + LignePrecedente[L] = L - 1; + LigneSuivante [L] = L + 1; + LDernierPossible[L] = CapaciteRestante + ilNew - 1; + ilNew = LDernierPossible[L] + 1; + } + Matrice->LIndexLibre = ilNew; + + LignePrecedente[0] = -1; + LigneSuivante [Matrice->Rang - 1] = -1; + Matrice->DerniereLigne = Matrice->Rang - 1; + + free( Matrice->LIndiceColonne ); + free( Matrice->Elm ); + Matrice->LIndiceColonne = LIndiceColonneNew; + Matrice->Elm = ElmNew; + + goto DeplacerLigne; + +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void LU_AugmenterLaTailleDeLaMatriceActiveParColonne( MATRICE * Matrice , int Colonne , int TailleDemandee ) +{ +int NbElements; int ic; int Nb; int ix; int icNew; int icMax; int C1; int C2; +int C; int NbElemNew; int CapaciteRestante; +int * Cdeb; int * CNbTerm; int * CIndiceLigne; int * CDernierPossible; +int * CIndiceLigneNew; int MargePourCreationDeTermesColonnes; +int * ColonnePrecedente; int * ColonneSuivante; int Kp; int * InverseOrdreColonne; +int * CNbTermMatriceActive; + +/*printf("LU_AugmenterLaTailleDeLaMatriceActiveParColonne Colonne %d Kp %d\n",Colonne,Matrice->Kp);*/ + +MargePourCreationDeTermesColonnes = Matrice->MargePourCreationDeTermesColonnes; + +/* S'il y a assez de place a la fin, on l'utilise */ +NbElements = TailleDemandee + MargePourCreationDeTermesColonnes; +if ( Matrice->CIndexLibre + NbElements - 1 <= Matrice->CDernierIndexLibrePossible ) { + /* Compacter la colonne "Colonne" */ + if ( Matrice->CNbTerm[Colonne] != Matrice->CNbTermMatriceActive[Colonne] ) { + LU_SupprimerTermesInutilesDansColonne( Matrice , Colonne , Matrice->Cdeb[Colonne] ); + } + DeplacerColonne: + ic = Matrice->Cdeb[Colonne]; + Nb = Matrice->CNbTerm[Colonne]; + ix = Matrice->CDernierPossible[Colonne]; + memcpy( (char *) &(Matrice->CIndiceLigne[Matrice->CIndexLibre]), (char *) &(Matrice->CIndiceLigne[ic]), Nb * sizeof( int ) ); + Matrice->Cdeb [Colonne] = Matrice->CIndexLibre; + Matrice->CDernierPossible[Colonne] = Matrice->CIndexLibre + NbElements - 1; + Matrice->CIndexLibre += NbElements; + C1 = Matrice->ColonnePrecedente[Colonne]; + C2 = Matrice->ColonneSuivante[Colonne]; + if ( C1 >= 0 ) { + Matrice->CDernierPossible[C1] = ix; + if ( C2 >= 0 ) { + Matrice->ColonneSuivante [C1] = C2; + Matrice->ColonnePrecedente[C2] = C1; + } + } + else { + if ( C2 >= 0 ) Matrice->ColonnePrecedente[C2] = -1; + } + if ( Colonne != Matrice->DerniereColonne ) { + Matrice->ColonnePrecedente[Colonne] = Matrice->DerniereColonne; + Matrice->ColonneSuivante[Matrice->DerniereColonne] = Colonne; + Matrice->ColonneSuivante[Colonne] = -1; + Matrice->DerniereColonne = Colonne; + } + return; +} +else { + # if VERBOSE_LU + printf(" Redimensionnement colonnes necessaire Kp %d Rang %d\n",Matrice->Kp,Matrice->Rang); + # endif + /* On reconstitue les marges et on ajoute un increment */ + NbElemNew = 0; + Kp = Matrice->Kp; + InverseOrdreColonne = Matrice->InverseOrdreColonne; + CNbTerm = Matrice->CNbTerm; + CNbTermMatriceActive = Matrice->CNbTermMatriceActive; + Cdeb = Matrice->Cdeb; + NbElemNew = 0; + for ( C = 0 ; C < Matrice->Rang ; C++ ) { + /* Compacter toutes les colonnes */ + if ( CNbTerm[C] != CNbTermMatriceActive[C] ) { + LU_SupprimerTermesInutilesDansColonne( Matrice , C , Cdeb[C] ); + } + NbElemNew += CNbTerm[C]; + if ( InverseOrdreColonne[C] > Kp ) NbElemNew += MargePourCreationDeTermesColonnes; + } + NbElemNew += NbElements + Matrice->CIncrementDallocation; + if ( Matrice->CIncrementDallocation < C_INCREMENT_DALLOCATION << SHIFT_MAX_INCREMENT ) { + Matrice->CIncrementDallocation *= 2; + } + NbElemNew = (int) ( NbElemNew * COEFF_MULT ); + CIndiceLigneNew = (int *) malloc( NbElemNew * sizeof( int ) ); + if ( CIndiceLigneNew == NULL ) { + printf("Factorisation LU, sous-programme LU_AugmenterLaTailleDeLaMatriceActiveParColonne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); + } + /* On recopie terme a terme pour recuperer aussi la place qu'on a perdu en supprimant une ligne + qui se trouvait etre la premiere dans le stockage, et les extensions exagerees */ + Matrice->CDernierIndexLibrePossible = NbElemNew - 1; + + icNew = 0; + ColonnePrecedente = Matrice->ColonnePrecedente; + ColonneSuivante = Matrice->ColonneSuivante; + CIndiceLigne = Matrice->CIndiceLigne; + CDernierPossible = Matrice->CDernierPossible; + for ( C = 0 ; C < Matrice->Rang ; C++ ) { + ic = Cdeb[C]; + Nb = CNbTerm[C]; + icMax = ic + Nb; + + if ( InverseOrdreColonne[C] > Kp ) { + CapaciteRestante = MargePourCreationDeTermesColonnes; + if ( C == Colonne ) CapaciteRestante += TailleDemandee; + } + else CapaciteRestante = 0; + + Cdeb[C] = icNew; + while ( ic < icMax ) { + CIndiceLigneNew[icNew] = CIndiceLigne[ic]; + icNew++; + ic++; + } + ColonnePrecedente[C] = C - 1; + ColonneSuivante [C] = C + 1; + CDernierPossible[C] = CapaciteRestante + icNew - 1; + icNew = CDernierPossible[C] + 1; + } + Matrice->CIndexLibre = icNew; + + ColonnePrecedente[0] = -1; + ColonneSuivante [Matrice->Rang - 1] = -1; + Matrice->DerniereColonne = Matrice->Rang - 1; + + free( CIndiceLigne ); + Matrice->CIndiceLigne = CIndiceLigneNew; + + goto DeplacerColonne; + +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void LU_AugmenterLaTailleDuTriangleL( MATRICE * Matrice , int TailleDemandee ) +{ +int NbElemNew; int NbElemAv; + +/*printf("LU_AugmenterLaTailleDuTriangleL \n");*/ + +NbElemAv = Matrice->DernierIndexLibreDeL + 1; +NbElemNew = NbElemAv + TailleDemandee + Matrice->IncrementDallocationDeL; + +if ( Matrice->IncrementDallocationDeL < INCREMENT_DALLOCATION_DE_L << SHIFT_MAX_INCREMENT ) { + Matrice->IncrementDallocationDeL*= 2; +} + +/*Matrice.IndexLibreDeL = NbElemAv;*/ +Matrice->DernierIndexLibreDeL = NbElemNew - 1; +/* +printf("-- Nouvelle valeur du nombre d elements alloues %d \n",NbElemNew); +*/ +Matrice->ElmDeL = (double *) realloc( Matrice->ElmDeL , NbElemNew * sizeof( double ) ); +Matrice->IndiceLigneDeL = (int *) realloc( Matrice->IndiceLigneDeL , NbElemNew * sizeof( int ) ); + +if ( Matrice->ElmDeL == NULL || Matrice->IndiceLigneDeL == NULL ) { + printf(" LU_AugmenterLaTailleDuTriangleL \n"); + printf(" Etape de factorisation, memoire insuffisante. Nombre de termes atteint: %d \n", NbElemAv); + + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); + +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void LU_AugmenterLaTailleDuTriangleU( MATRICE * Matrice , int TailleDemandee ) +{ +int NbElemNew; int NbElemAv; + +/*printf("LU_AugmenterLaTailleDuTriangleU\n");*/ + +NbElemAv = Matrice->DernierIndexLibreDeU + 1; +NbElemNew = NbElemAv + TailleDemandee + Matrice->IncrementDallocationDeU; + +if ( Matrice->IncrementDallocationDeU < INCREMENT_DALLOCATION_DE_U << SHIFT_MAX_INCREMENT ) { + Matrice->IncrementDallocationDeU*= 2; +} + +/*Matrice.IndexLibreDeU = NbElemAv;*/ +Matrice->DernierIndexLibreDeU = NbElemNew - 1; +/* +printf("-- Nouvelle valeur du nombre d elements alloues %d \n",NbElemNew); +*/ +Matrice->ElmDeU = (double *) realloc( Matrice->ElmDeU , NbElemNew * sizeof( double ) ); +Matrice->IndiceColonneDeU = (int *) realloc( Matrice->IndiceColonneDeU , NbElemNew * sizeof( int ) ); + +if ( Matrice->LuUpdateEnCours == OUI_LU ) { + Matrice->StockageLigneVersColonneDeU = (int *) realloc( Matrice->StockageLigneVersColonneDeU , NbElemNew * sizeof( int ) ); +} + +if ( Matrice->ElmDeU == NULL || Matrice->IndiceColonneDeU == NULL || + (Matrice->LuUpdateEnCours == OUI_LU && Matrice->StockageLigneVersColonneDeU == NULL) ) { + printf(" LU_AugmenterLaTailleDuTriangleU \n"); + printf(" Etape de factorisation, memoire insuffisante. Nombre de termes atteint: %d \n", NbElemAv); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} +if ( Matrice->LuUpdateEnCours == OUI_LU ) { + if ( Matrice->StockageLigneVersColonneDeU == NULL ) { + printf(" LU_AugmenterLaTailleDuTriangleU \n"); + printf(" Etape de factorisation, memoire insuffisante. Nombre de termes atteint: %d \n", NbElemAv); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void LU_AugmenterLaTailleDuTriangleUParColonne( MATRICE * Matrice , int TailleDemandee ) +{ +int NbElemNew; int NbElemAv; + +/*printf("LU_AugmenterLaTailleDuTriangleUParColonne \n");*/ + +NbElemAv = Matrice->DernierIndexLibreDeUParColonne + 1; +NbElemNew = NbElemAv + TailleDemandee + Matrice->IncrementDallocationDeU; + +if ( Matrice->IncrementDallocationDeU < INCREMENT_DALLOCATION_DE_U << SHIFT_MAX_INCREMENT ) { + Matrice->IncrementDallocationDeU*= 2; +} + +/*Matrice.IndexLibreDeU = NbElemAv;*/ +Matrice->DernierIndexLibreDeUParColonne = NbElemNew - 1; +/* +printf("-- Nouvelle valeur du nombre d elements alloues %d \n",NbElemNew); +*/ +Matrice->IndiceLigneParColonneDeU = (int *) realloc( Matrice->IndiceLigneParColonneDeU , NbElemNew * sizeof( int ) ); +if ( Matrice->IndiceLigneParColonneDeU == NULL ) { + printf("LU_AugmenterLaTailleDuTriangleUParColonne \n"); + printf("Etape de factorisation, memoire insuffisante. Nombre de termes atteint: %d \n", NbElemAv); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} + +if ( Matrice->LuUpdateEnCours == OUI_LU ) { + Matrice->StockageColonneVersLigneDeU = (int *) realloc( Matrice->StockageColonneVersLigneDeU, NbElemNew * sizeof( int ) ); + Matrice->ElmDeUParColonne = (double *) realloc( Matrice->ElmDeUParColonne , NbElemNew * sizeof( double ) ); + if ( Matrice->StockageColonneVersLigneDeU == NULL || Matrice->ElmDeUParColonne == NULL ) { + printf("LU_AugmenterLaTailleDuTriangleUParColonne \n"); + printf("Etape de factorisation, memoire insuffisante. Nombre de termes atteint: %d \n", NbElemAv); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void LU_LibererLesTableauxTemporaires( MATRICE * Matrice ) +{ + +free( Matrice->LigneRejeteeTemporairementPourPivotage ); + +free( Matrice->ColonneRejeteeTemporairementPourPivotage ); + +/* On reutilise la place */ +Matrice->SecondMembreSV = Matrice->AbsDuPlusGrandTermeDeLaLigne; + +free( Matrice->PremLigne ); +free( Matrice->SuivLigne ); +free( Matrice->PrecLigne ); + +free( Matrice->PremColonne ); +free( Matrice->SuivColonne ); +free( Matrice->PrecColonne ); + +if ( Matrice->ContexteDeLaFactorisation != LU_SIMPLEXE ) { + free( Matrice->W ); + free( Matrice->Marqueur ); +} + +if ( Matrice->FaireDuPivotageDiagonal == OUI_LU) { + free( Matrice->AbsValeurDuTermeDiagonal ); +} + +if ( Matrice->UtiliserLesSuperLignes == OUI_LU ) { + free( Matrice->SuperLigneDeLaLigne ); + free( Matrice->SuperLigneAScanner ); + free( Matrice->SuperLigne ); + free( Matrice->PoidsDesColonnes ); + + free( Matrice->HashCodeLigne ); + free( Matrice->HashCodeSuperLigne ); + free( Matrice->HashModuloPrem ); + free( Matrice->HashNbModuloIdentiques ); + free( Matrice->TypeDeClassementHashCodeAFaire ); + free( Matrice->HashModuloSuiv ); + free( Matrice->HashModuloPrec ); +} + +/* Conserve pour la LU Update et la refactorisation +free( Matrice->InverseOrdreLigne ); +free( Matrice->InverseOrdreColonne ); +*/ + +/* Conserve pour la resolution hyper creux */ +/*free( Matrice->LDernierPossible );*/ + +free( Matrice->Cdeb ); +free( Matrice->CNbTerm ); +free( Matrice->CNbTermMatriceActive ); +free( Matrice->CDernierPossible ); +free( Matrice->CIndiceLigne ); + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Methode systematique: apres avoir libere une zone memoire on met NULL. Car + selon le contexte, 2 tableaux peuvent partager une meme zone (simple changement + de nom )*/ +void LU_LibererMemoireLU( MATRICE * Matrice ) +{ + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + MEM_Quit( Matrice->Tas ); + return; +# endif + +free( Matrice->OrdreLigne ); + +free( Matrice->OrdreColonne ); + +free( Matrice->NbTermesParColonneDeL ); +free( Matrice->CdebParColonneDeL ); +free( Matrice->ElmDeL ); +free( Matrice->IndiceLigneDeL ); + +free( Matrice->CapaciteParLigneDeU ); + +free( Matrice->ElmDeUParColonne ); +free( Matrice->IndiceLigneParColonneDeU ); +free( Matrice->CapaciteParColonneDeU ); + +free( Matrice->StockageColonneVersLigneDeU ); +free( Matrice->StockageLigneVersColonneDeU ); + +free( Matrice->SolutionIntermediaire ); + +free( Matrice->AbsDuPlusGrandTermeDeLaLigne ); +free( Matrice->SolutionSV ); + +free( Matrice->NumeroDeTriangleDeLaVariable ); + +free( Matrice->InverseOrdreLigne ); +free( Matrice->InverseOrdreColonne ); + +/* Car: Matrice->FaireScaling peut avoir ete mis a NON_LU dans CalculerLeScaling */ +if ( Matrice->ScaleX != NON_LU ) free( Matrice->ScaleX ); +if ( Matrice->ScaleB != NON_LU ) free( Matrice->ScaleB ); + +if ( Matrice->ContexteDeLaFactorisation == LU_SIMPLEXE ) { + free( Matrice->HDeb ); + free( Matrice->HLigne ); + free( Matrice->HNbTerm ); + free( Matrice->HIndiceColonne ); + free( Matrice->HValeur ); + + free( Matrice->W ); + free( Matrice->Marqueur ); + + free( Matrice->IndicesLignesDuSpike ); + free( Matrice->ValeurElmSpike ); + + free( Matrice->OrdreUcolonne ); + free( Matrice->InverseOrdreUcolonne ); + + free( Matrice->LdebParLigneDeL ); + free( Matrice->NbTermesParLigneDeL ); + free( Matrice->IndiceColonneParLigneDeL ); + free( Matrice->ElmDeLParLigne ); +} + +if ( Matrice->ContexteDeLaFactorisation == LU_POINT_INTERIEUR ) { + free( Matrice->DebutInfosAdressesQueKpModifie ); + free( Matrice->AdresseDeUModifie ); + free( Matrice->AdresseUHaut ); + free( Matrice->DebutInfosLignesQueKpModifie ); + free( Matrice->NombreDeLignesQueKpModifie ); + free( Matrice->AdresseUGauche ); + free( Matrice->NombreDeTermesParLigneQueKpModifie ); + free( Matrice->IndexKpDeUouL ); +} + +# ifdef HYPER_CREUX + /* free( Matrice->PseudoPile ); <- car on reutilise Matrice->Ldeb */ + /* free( Matrice->ListeDesNoeuds ); <- car on reutilise Matrice->LNbTerm; */ + /* free( Matrice->NoeudDansLaliste ); <- car on reutilise Matrice->LDernierPossible; */ +# endif + +free( Matrice->LignePrecedente ); +free( Matrice->LigneSuivante ); + +free( Matrice->Ldeb ); +free( Matrice->LNbTerm ); +free( Matrice->Elm ); +free( Matrice->LIndiceColonne ); +free( Matrice->LDernierPossible ); + +if ( Matrice->ContexteDeLaFactorisation != LU_GENERAL ) { + free( Matrice->ElmDeU ); + free( Matrice->IndiceColonneDeU ); +} + +free( Matrice->ColonnePrecedente ); +free( Matrice->ColonneSuivante ); + +free( Matrice ); + +return; +} + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_calculs_markowitz.c b/src/ext/Sirius_Solver/simplexe/lu/lu_calculs_markowitz.c new file mode 100644 index 0000000000..f7d1ec6c1b --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_calculs_markowitz.c @@ -0,0 +1,422 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU de la base. + Calculs des nombres de Markowitz. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_PlusGrandTermeDeLaLigne( MATRICE * Matrice , int Ligne , int Colonne , int * IndexRecherche ) +{ +int il; int ilDeb; double X ; double ElmMax; double * Elm ; int * LIndiceColonne; +int NombreDeTermes; char LigneDansSuperLigne; + +ElmMax = 0.9999 * Matrice->PivotMin; + +LigneDansSuperLigne = NON_LU; + +if ( Matrice->UtiliserLesSuperLignes == OUI_LU ) { + if ( Matrice->SuperLigneDeLaLigne[Ligne] != NULL ) { + /* Il vaut mieux proceder a une recherche special dans la super ligne plutot que de passer + par une recopie */ + LU_RecopierUneLigneDeSuperLigneDansLigne( Matrice, Matrice->SuperLigneDeLaLigne[Ligne], Ligne ); + LigneDansSuperLigne = OUI_LU; + } +} + +ilDeb = Matrice->Ldeb[Ligne]; +NombreDeTermes = Matrice->LNbTerm[Ligne]; +Elm = Matrice->Elm; +LIndiceColonne = Matrice->LIndiceColonne; + +if ( Colonne >= 0 ) { + for ( il = ilDeb ; il < ilDeb + NombreDeTermes ; il++ ) { + X = fabs( Elm[il] ); + if ( X > ElmMax ) ElmMax = X; + if ( LIndiceColonne[il] == Colonne ) { + if ( LigneDansSuperLigne == NON_LU ) *IndexRecherche = il; + else *IndexRecherche = il - ilDeb; + il++; + break; + } + } + for ( ; il < ilDeb + NombreDeTermes ; il++ ) { + X = fabs( Elm[il] ); + if ( X > ElmMax ) ElmMax = X; + } +} +else { + for ( il = ilDeb ; il < ilDeb + NombreDeTermes ; il++ ) { + X = fabs( Elm[il] ); + if ( X > ElmMax ) ElmMax = X; + } +} +Matrice->AbsDuPlusGrandTermeDeLaLigne[Ligne] = ElmMax; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_InitMinMarkowitzDeLigne( MATRICE * Matrice , int Ligne , int * ColonneDeMarkowitz , double * ValeurMarkowitz ) +{ +int il; int ilDeb; int Nb; double MinMarkowitz; double Y; int Select; int ColonneDeMinMarkowitz; +double SeuilMarkowitz; int NbTMinCol; int NbTCol; double Ysv; double AbsMaxLig; +int NombreDeTermes; int * LIndiceColonne; double * Elm; int * CNbTermMatriceActive; +int * Cdeb; + +*ColonneDeMarkowitz = -1; +*ValeurMarkowitz = Matrice->RangAuCarrePlus1 + 1.; /* Car on teste une egalite dans selection pivot */ + +AbsMaxLig = Matrice->AbsDuPlusGrandTermeDeLaLigne[Ligne]; +if ( AbsMaxLig < 0. ) { + LU_PlusGrandTermeDeLaLigne( Matrice , Ligne , -1 , &il ); + AbsMaxLig = Matrice->AbsDuPlusGrandTermeDeLaLigne[Ligne]; +} + +if ( AbsMaxLig < Matrice->PivotMin ) return; + +SeuilMarkowitz = Matrice->SeuilDePivotage * AbsMaxLig; +ColonneDeMinMarkowitz = -1; +NbTMinCol = Matrice->Rang + 10; +MinMarkowitz = NbTMinCol; + +Ysv = -1.; + +if ( Matrice->UtiliserLesSuperLignes == OUI_LU ) { + if ( Matrice->SuperLigneDeLaLigne[Ligne] != NULL ) { + LU_RecopierUneLigneDeSuperLigneDansLigne( Matrice, Matrice->SuperLigneDeLaLigne[Ligne], Ligne ); + } +} + +ilDeb = Matrice->Ldeb[Ligne]; +NombreDeTermes = Matrice->LNbTerm[Ligne]; +Elm = Matrice->Elm; +LIndiceColonne = Matrice->LIndiceColonne; + +Nb = NombreDeTermes - 1; + +Cdeb = Matrice->Cdeb; +CNbTermMatriceActive = Matrice->CNbTermMatriceActive; + +for ( il = ilDeb ; il < ilDeb + NombreDeTermes ; il++ ) { + NbTCol = CNbTermMatriceActive[LIndiceColonne[il]] - 1; + if ( NbTCol <= NbTMinCol ) { + Y = fabs( Elm[il] ); + if ( Y > SeuilMarkowitz && Y > Matrice->PivotMin ) { + Select = OUI_LU; + if ( NbTCol == NbTMinCol ) { + if ( Y < Ysv ) Select = NON_LU; + } + /* */ + if ( Select == OUI_LU ) { + MinMarkowitz = Nb * NbTCol; + ColonneDeMinMarkowitz = LIndiceColonne[il]; + NbTMinCol = NbTCol; + Ysv = Y; + } + } + } +} + +if ( ColonneDeMinMarkowitz >= 0 ) { + *ColonneDeMarkowitz = ColonneDeMinMarkowitz; + *ValeurMarkowitz = MinMarkowitz; +} +else { + if ( Matrice->ExclureLesEchecsMarkowitz == OUI_LU ) { + Matrice->LigneRejeteeTemporairementPourPivotage[Ligne] = OUI_LU; + } +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* On elimine les termes qui correspondent a des lignes deja eliminees. En sortie on a + CNbTerm = CNbTermMatriceActive */ +void LU_SupprimerTermesInutilesDansColonne( MATRICE * Matrice, int Colonne, int ic1Deb ) +{ +int Kp; int NbTerm; int ic1; int ic2; int * InverseOrdreLigne; int * CIndiceLigne; + +Kp = Matrice->Kp; +InverseOrdreLigne = Matrice->InverseOrdreLigne; +CIndiceLigne = Matrice->CIndiceLigne; + +NbTerm = 0; +ic2 = ic1Deb + Matrice->CNbTerm[Colonne] - 1; +for ( ic1 = ic1Deb ; ic1 <= ic2 ; ic1++ ) { + if ( InverseOrdreLigne[CIndiceLigne[ic1]] >= Kp ) { + NbTerm++; + continue; + } + /* La ligne a deja ete eliminee => on peut compacter */ + while ( ic2 > ic1 ) { + if ( InverseOrdreLigne[CIndiceLigne[ic2]] >= Kp ) { + /* On peut utiliser le terme */ + CIndiceLigne[ic1] = CIndiceLigne[ic2]; + NbTerm++; + ic2--; + break; + } + ic2--; + } +} + +if ( NbTerm != Matrice->CNbTermMatriceActive[Colonne] ) { + printf("BUG dans LU_SupprimerTermesInutilesDansColonne NbTerm %d CNbTermMatriceActive %d\n", + NbTerm, Matrice->CNbTermMatriceActive[Colonne]); +} +Matrice->CNbTerm[Colonne] = NbTerm; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_InitMinMarkowitzDeColonne( MATRICE * Matrice , int Colonne , int * LigneDeMarkowitz , double * ValeurMarkowitz ) +{ +int ic; int icDeb; int ilDeb; int il; int Nb; int * CIndiceLigne; double MinMarkowitz; int Ligne; +double Y; int Select; int LigneDeMinMarkowitz; double SeuilMarkowitz; int NbTMinLig; int NbTLig; +double Ysv; double AbsMaxLig; int NombreDeTermes; int * LIndiceColonne; int * LNbTerm; int * Ldeb; +double * Elm; int * IndiceColonne; + +SUPER_LIGNE_DE_LA_MATRICE * SuperLigne; int i ; char UtiliserLesSuperLignes; +SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneDeLaLigne; + +UtiliserLesSuperLignes = Matrice->UtiliserLesSuperLignes; +SuperLigneDeLaLigne = Matrice->SuperLigneDeLaLigne; + +*LigneDeMarkowitz = -1; +*ValeurMarkowitz = Matrice->RangAuCarrePlus1 + 1; /* Car on teste une egalite dans selection pivot */ + +/* On cherche le meilleur puis on verifie les conditions de stabilite. Si elle ne sont pas verifiees alors on fait + le calcul complet */ +LigneDeMinMarkowitz = -1; +NbTMinLig = Matrice->Rang + 10; +MinMarkowitz = NbTMinLig; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +icDeb = Matrice->Cdeb[Colonne]; +NombreDeTermes = Matrice->CNbTerm[Colonne]; +CIndiceLigne = Matrice->CIndiceLigne; + +Nb = NombreDeTermes - 1; + +if ( NombreDeTermes != Matrice->CNbTermMatriceActive[Colonne] ) { + LU_SupprimerTermesInutilesDansColonne( Matrice, Colonne, icDeb ); + NombreDeTermes = Matrice->CNbTerm[Colonne]; + Nb = NombreDeTermes - 1; +} + +for ( ic = icDeb ; ic < icDeb + NombreDeTermes; ic++ ) { + Ligne = CIndiceLigne[ic]; + if ( UtiliserLesSuperLignes == OUI_LU) { + if ( SuperLigneDeLaLigne[Ligne] != NULL ) { + NbTLig = SuperLigneDeLaLigne[Ligne]->NombreDeTermes - 1; + } + else { + NbTLig = LNbTerm[Ligne] - 1; + } + } + else { + NbTLig = LNbTerm[Ligne] - 1; + } + + if ( NbTLig < NbTMinLig ) { + MinMarkowitz = Nb * NbTLig; + LigneDeMinMarkowitz = Ligne; + NbTMinLig = NbTLig; + } +} + +if ( LigneDeMinMarkowitz >= 0 ) { + /* Verification de la condition de stabilite */ + AbsMaxLig = Matrice->AbsDuPlusGrandTermeDeLaLigne[LigneDeMinMarkowitz]; + if ( AbsMaxLig < 0. ) { + LU_PlusGrandTermeDeLaLigne( Matrice , LigneDeMinMarkowitz , Colonne , &il); + AbsMaxLig = Matrice->AbsDuPlusGrandTermeDeLaLigne[LigneDeMinMarkowitz]; + if ( AbsMaxLig < 0. ) goto RechercheComplete; + } + else { + /* Recherche de l'index auquel on trouve la valeur du terme pivot potentiel */ + if ( UtiliserLesSuperLignes == OUI_LU) { + if ( SuperLigneDeLaLigne[LigneDeMinMarkowitz] != NULL ) { + ilDeb = 0; + IndiceColonne = SuperLigneDeLaLigne[LigneDeMinMarkowitz]->IndiceColonne; + } + else { + ilDeb = Ldeb[LigneDeMinMarkowitz]; + IndiceColonne = LIndiceColonne; + } + } + else { + ilDeb = Ldeb[LigneDeMinMarkowitz]; + IndiceColonne = LIndiceColonne; + } + for ( il = ilDeb ; IndiceColonne[il] != Colonne ; il++ ); + } + SeuilMarkowitz = -1.; + if ( Nb > 0 ) { + SeuilMarkowitz = Matrice->SeuilDePivotage * AbsMaxLig; + /* Comme on ne compare pas les pivots a meme nombre de Markowitz, on augmente + un peu le seuil */ + SeuilMarkowitz*= 1.5; + } + + if ( UtiliserLesSuperLignes == OUI_LU) { + if ( SuperLigneDeLaLigne[LigneDeMinMarkowitz] != NULL ) { + SuperLigne = SuperLigneDeLaLigne[LigneDeMinMarkowitz]; + il = SuperLigne->CapaciteDesColonnes * il; + for ( i = 0 ; i < SuperLigne->NombreDeLignesDeLaSuperLigne ; i++ ) { + if ( SuperLigne->NumerosDesLignesDeLaSuperLigne[i] == LigneDeMinMarkowitz ) { + il+= i; + break; + } + } + Y = fabs( SuperLigne->ElmColonneDeSuperLigne[il] ); + } + else { + Y = fabs( Elm[il] ); + } + } + else { + Y = fabs( Elm[il] ); + } + + if ( Y > SeuilMarkowitz && Y > Matrice->PivotMin ) { + /* Condition de stabilite verifiee, on peut enteriner le choix */ + goto FinCalculMinMarkowitzColonne; + } +} + +RechercheComplete: +/* Condition de stabilite pas verifiee, on repart sur un calcul complet */ +LigneDeMinMarkowitz = -1; +NbTMinLig = Matrice->Rang + 10; +Ysv = -1.; + +for ( ic = icDeb ; ic < icDeb + NombreDeTermes; ic++ ) { + Ligne = CIndiceLigne[ic]; + + if ( UtiliserLesSuperLignes == OUI_LU ) { + if ( SuperLigneDeLaLigne[Ligne] != NULL ) { + NbTLig = SuperLigneDeLaLigne[Ligne]->NombreDeTermes - 1; + } + else { + NbTLig = LNbTerm[Ligne] - 1; + } + } + else { + NbTLig = LNbTerm[Ligne] - 1; + } + + if ( NbTLig <= NbTMinLig ) { + AbsMaxLig = Matrice->AbsDuPlusGrandTermeDeLaLigne[Ligne]; + if ( AbsMaxLig < 0. ) { + LU_PlusGrandTermeDeLaLigne( Matrice , Ligne , Colonne , &il); + AbsMaxLig = Matrice->AbsDuPlusGrandTermeDeLaLigne[Ligne]; + if ( AbsMaxLig < 0. ) continue; + } + else { + /* Recherche de l'index auquel on trouve la valeur du terme pivot potentiel */ + if ( UtiliserLesSuperLignes == OUI_LU ) { + if ( SuperLigneDeLaLigne[Ligne] != NULL ) { + ilDeb = 0; + IndiceColonne = SuperLigneDeLaLigne[Ligne]->IndiceColonne; + } + else { + ilDeb = Ldeb[Ligne]; + IndiceColonne = LIndiceColonne; + } + } + else { + ilDeb = Ldeb[Ligne]; + IndiceColonne = LIndiceColonne; + } + for ( il = ilDeb ; IndiceColonne[il] != Colonne ; il++ ); + } + SeuilMarkowitz = -1.; + if ( Nb > 0 ) SeuilMarkowitz = Matrice->SeuilDePivotage * AbsMaxLig; + + if ( UtiliserLesSuperLignes == OUI_LU ) { + if ( SuperLigneDeLaLigne[Ligne] != NULL ) { + SuperLigne = SuperLigneDeLaLigne[Ligne]; + il = SuperLigne->CapaciteDesColonnes * il; + for ( i = 0 ; i < SuperLigne->NombreDeLignesDeLaSuperLigne ; i++ ) { + if ( SuperLigne->NumerosDesLignesDeLaSuperLigne[i] == Ligne ) { + il+= i; + break; + } + } + Y = fabs( SuperLigne->ElmColonneDeSuperLigne[il] ); + } + else { + Y = fabs( Elm[il] ); + } + } + else { + Y = fabs( Elm[il] ); + } + + if ( Y > SeuilMarkowitz && Y > Matrice->PivotMin ) { + Select = OUI_LU; + if ( NbTLig == NbTMinLig ) { + if ( Y < Ysv ) Select = NON_LU; + } + /* */ + if ( Select == OUI_LU ) { + MinMarkowitz = Nb * NbTLig; + LigneDeMinMarkowitz = Ligne; + NbTMinLig = NbTLig; + Ysv = Y; + } + } + } +} + +FinCalculMinMarkowitzColonne: +if ( LigneDeMinMarkowitz >= 0 ) { + *LigneDeMarkowitz = LigneDeMinMarkowitz; + *ValeurMarkowitz = MinMarkowitz; +} +else { + if ( Matrice->ExclureLesEchecsMarkowitz == OUI_LU ) { + Matrice->ColonneRejeteeTemporairementPourPivotage[Colonne] = OUI_LU; + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_classement_lignes_colonnes.c b/src/ext/Sirius_Solver/simplexe/lu/lu_classement_lignes_colonnes.c new file mode 100644 index 0000000000..13bb0ac5a8 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_classement_lignes_colonnes.c @@ -0,0 +1,204 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU de la base. + Classement des lignes et des colonnes en fonction du + nombre de termes. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------------------------------------------*/ +/* Classement de toutes les lignes et de toutes les colonnes en fonction de leur nombre de termes */ + +void LU_ClasserToutesLesLignesEtToutesLesColonnes( MATRICE * Matrice ) +{ +int i; int il; int ilDeb; double X; char FaireDuPivotageDiagonal; double * Elm; int * IndiceColonne; +int * Ldeb; int * LNbTerm; int * CNbTerm; + +FaireDuPivotageDiagonal = Matrice->FaireDuPivotageDiagonal; + +if ( FaireDuPivotageDiagonal == OUI_LU ) { + memset( (char *) Matrice->AbsValeurDuTermeDiagonal , 0 , Matrice->Rang * sizeof( double ) ); +} + + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +Elm = Matrice->Elm; +IndiceColonne = Matrice->LIndiceColonne; + +CNbTerm = Matrice->CNbTerm; + +for ( i = 0 ; i < Matrice->Rang ; i++ ) { + LU_ClasserUneLigne( Matrice , i , LNbTerm[i] ); + if ( FaireDuPivotageDiagonal != OUI_LU ) { + LU_ClasserUneColonne( Matrice , i , CNbTerm[i] ); + } + /* Si l'on a choisi l'option du pivotage diagonal */ + if ( FaireDuPivotageDiagonal == OUI_LU ) { + ilDeb = Ldeb[i]; + for ( il = ilDeb ; il < ilDeb + LNbTerm[i] ; il++ ) { + if ( IndiceColonne[il] == i ) { + X = fabs( Elm[il] ); + if ( X < Matrice->PivotMin ) { + /* Pivot non eligible, on declasse la ligne */ + /* Attention ca peut poser des pb car on declasse les lignes dans Elimination des lignes */ + /* LU_DeClasserUneLigne( Matrice , i , ptLigne->NombreDeTermes ); */ + } + else { + Matrice->AbsValeurDuTermeDiagonal[i] = X; + } + break; + } + } + } +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Classement d'une ligne en fonction de son nombre de termes */ + +void LU_ClasserUneLigne( MATRICE * Matrice , int Ligne , int NbTermes ) +{ +int SuivLigne; + +if ( NbTermes <= 1 ) { + if ( Matrice->LigneRejeteeTemporairementPourPivotage[Ligne] == OUI_LU ) { + goto FinClasserUneLigne; + } +} + +SuivLigne = Matrice->PremLigne[NbTermes]; +Matrice->PremLigne[NbTermes] = Ligne; +Matrice->SuivLigne[Ligne] = SuivLigne; + +if ( SuivLigne >= 0 ) Matrice->PrecLigne[SuivLigne] = Ligne; + +FinClasserUneLigne: +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* En enleve la ligne de son chainage en fonction de son nombre de termes + (elle sera reclassée ensuite). Remarque: une ligne doit etre dechainee avant + d'etre chainee a nouveau */ + +void LU_DeClasserUneLigne( MATRICE * Matrice , int Ligne , int NbTermes ) +{ +int LPrec; int LSuiv; + +if ( Matrice->PremLigne[NbTermes] == Ligne ) { + /* C'est le premier element qu'on enleve */ + Matrice->PremLigne[NbTermes] = Matrice->SuivLigne[Ligne]; + Matrice->PrecLigne[Ligne] = -1; + goto FinDeClasserUneLigne; +} + +/* On enleve un element qui n'est pas le premier */ + +LPrec = Matrice->PrecLigne[Ligne]; +if ( LPrec < 0 ) return; /* La ligne n'est pas classee (pour left looking) */ +LSuiv = Matrice->SuivLigne[Ligne]; +Matrice->SuivLigne[LPrec] = LSuiv; +if ( LSuiv >= 0 ) Matrice->PrecLigne[LSuiv] = LPrec; +Matrice->PrecLigne[Ligne] = -1; + +FinDeClasserUneLigne: +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Classement d'une colonne en fonction de son nombre de termes */ + +void LU_ClasserUneColonne( MATRICE * Matrice , int Colonne , int NbTermes ) +{ +int SuivColonne; + +if ( NbTermes <= 1 ) { + if ( Matrice->ColonneRejeteeTemporairementPourPivotage[Colonne] == OUI_LU ) { + /*printf("Refus de la tentative de reintroduction de la colonne %d\n",Colonne);*/ + goto FinClasserUneColonne; + } +} + +SuivColonne = Matrice->PremColonne[NbTermes]; +Matrice->PremColonne[NbTermes] = Colonne; +Matrice->SuivColonne[Colonne] = SuivColonne; + +if ( SuivColonne >= 0 ) Matrice->PrecColonne[SuivColonne] = Colonne; + +FinClasserUneColonne: +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* En enleve la colonne de son chainage en fonction de son nombre de termes + (elle sera reclassée ensuite). Remarque: une colonne doit etre dechainee avant + d'etre chainee a nouveau */ + +void LU_DeClasserUneColonne( MATRICE * Matrice , int Colonne , int NbTermes ) +{ +int CPrec; int CSuiv; + +if ( Matrice->PremColonne[NbTermes] == Colonne ) { + /* C'est le premier element qu'on enleve */ + Matrice->PremColonne[NbTermes] = Matrice->SuivColonne[Colonne]; + Matrice->PrecColonne[Colonne] = -1; + goto FinDeClasserUneColonne; +} + +/* On enleve un element qui n'est pas le premier */ + +CPrec = Matrice->PrecColonne[Colonne]; +if ( CPrec < 0 ) return; /* La colonne n'est pas classee */ +CSuiv = Matrice->SuivColonne[Colonne]; +Matrice->SuivColonne[CPrec] = CSuiv; +if ( CSuiv >= 0 ) Matrice->PrecColonne[CSuiv] = CPrec; +Matrice->PrecColonne[Colonne] = -1; + +FinDeClasserUneColonne: +return; +} + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_constantes_externes.h b/src/ext/Sirius_Solver/simplexe/lu/lu_constantes_externes.h new file mode 100644 index 0000000000..67987e6f9e --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_constantes_externes.h @@ -0,0 +1,42 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef CONSTANTES_EXTERNES_LU_DEJA_DEFINIES +/*******************************************************************************************/ +/* + Definition des constantes symboliques a utiliser par le module appelant la + factorisation lu +*/ + +# define OUI_LU 1 +# define NON_LU 0 +# define SATURATION_MEMOIRE 2 +# define MATRICE_SINGULIERE 3 +# define PRECISION_DE_RESOLUTION_NON_ATTEINTE 4 /* Quand on fait du raffinement iteratif, si on atteint + pas la precision demandee */ + +/* Les contextes d'utilisation de la factorisation */ +# define LU_SIMPLEXE 1 +# define LU_POINT_INTERIEUR 2 +# define LU_GENERAL 3 + +/*******************************************************************************************/ +# define CONSTANTES_EXTERNES_LU_DEJA_DEFINIES +# endif + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_constantes_internes.h b/src/ext/Sirius_Solver/simplexe/lu/lu_constantes_internes.h new file mode 100644 index 0000000000..4d1dfec5af --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_constantes_internes.h @@ -0,0 +1,110 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef DEFINITIONS_CONSTANTES_INTERNES_LU_FAITE +/***********************************************************************************************************************/ + +# define LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE +# undef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + +# define VERBOSE_LU 0 +# define VERBOSE_SCALING 0 + +# define HYPER_CREUX + /*# undef HYPER_CREUX*/ +# define NOEUD_HORS_LISTE 0 /* Pour l'hyper creux */ +# define NOEUD_DANS_LISTE 1 /* Pour l'hyper creux */ + +# define COMPACT_LU 1 /* Les valeurs non nulles sont compactees au debut du vecteur */ +# define ADRESSAGE_INDIRECT_LU 2 /* Adressage indirect des valeurs non nulles */ +# define VECTEUR_LU 3 /* Pas d'adressage particulier */ + +# define RECURSION_OK 1 +# define RECURSION_NOT_OK 2 +# define POURSUITE_RESOLUTION_HYPER_CREUX 3 +# define ARRET_RESOLUTION_HYPER_CREUX 4 + +# define NOMBRE_MAX_ITER_DE_RAFFINEMENT 100 + +# define NOMBRE_INITIAL_DE_VECTEURS_H_ALLOUES 150 /*150*/ /* grand nombre => cycle conduit par le fillin */ + +# define MARGE_MINIMALE_POUR_CREATION_DE_TERMES 5 /*10*/ + +# define L_INCREMENT_DALLOCATION 10000 +# define C_INCREMENT_DALLOCATION 10000 + +# define INCREMENT_DALLOCATION_DE_L 10000 +# define INCREMENT_DALLOCATION_DE_U 10000 + +# define SHIFT_MAX_INCREMENT 5 + +/* Pour les super lignes */ + # define ELEMENT_HASCODE_A_NE_PAS_CLASSER 1 /* Attention c'est pour mettre dans un char */ + # define ELEMENT_HASCODE_A_DECLASSER 2 /* Attention c'est pour mettre dans un char */ + # define ELEMENT_HASCODE_A_RECLASSER 3 /* Attention c'est pour mettre dans un char */ + # define ELEMENT_HASCODE_CLASSE 4 /* Attention c'est pour mettre dans un char */ + # define ELEMENT_HASCODE_A_CLASSER 5 /* Attention c'est pour mettre dans un char */ + + # define SEUIL_NB_SUPER_LIGNES_A_GROUPER 2 + # define SEUIL_1_NB_LIGNES_A_GROUPER 5 + # define SEUIL_2_NB_LIGNES_A_GROUPER 2 +/* Fin super lignes */ + +# define PIVOT_MIN_SIMPLEXE 1.e-6 /*6*/ +# define PIVOT_MIN_EXTREME_SIMPLEXE 1.e-10 /*10*/ +# define PIVOT_MIN_FINAL 1.e-15 /*1.e-15 Valeur de pivot min pour l'elimination du dernier pivot */ + +# define PIVOT_MIN_AUTRES_CONTEXTES 1.e-9 +# define PIVOT_MIN_EXTREME_AUTRES_CONTEXTES 1.e-10 + +# define NOMBRE_MAX_DE_CHANGEMENTS_DE_SEUIL_DE_PIVOTAGE_SIMPLEXE 4 +# define NOMBRE_MAX_DE_CHANGEMENTS_DE_SEUIL_DE_PIVOTAGE_AUTRES_CONTEXTES 0 + +# define PREMIER_SEUIL_DE_PIVOTAGE 0.050 /*0.050*/ +# define INCREMENT_DE_SEUIL_DE_PIVOTAGE 0.025 /*0.025*/ + +# define SEUIL_DE_REINTRODUCTION 10.0 + +# define POURCENTAGE_MAX_DE_TERMES_CREES_PAR_LU_UPDATE 0.4 /*0.1*/ /* Il ne faut pas etre trop restrictif sinon, dans le + cas ou le remplissage est important pendant la + factorisation, on sera conduit a refactoriser trop + souvent pendant la LU update */ + +# define LINFINI_LU 1.e+80 + +/* Pour le reglage des zeros ci-dessous il faudrait une methode automatique */ +# define ZERO_POUR_LE_RESULTAT_DE_LA_RESOLUTION 1.e-20 /*1.e-18*/ /*1.e-17*/ /*1.e-16*/ /* Que pour les Simplexe */ +# define ZERO_POUR_LE_RESULTAT_DE_LA_RESOLUTION_TRANSPOSEE 1.e-20 /*1.e-18*/ /*1.e-17*/ /*1.e-16*/ /* Que pour les Simplexe */ +# define ZERO_POUR_SPIKE 1.e-20 /*1.e-19*/ +# define VALEUR_NULLE_DE_LAMBDA_POUR_LU_UPDATE 1.e-30 + +/*****************************************************************************/ +/* Super lignes dans le cas de la factorisation des matrices non symetriques: en test + utilise pour diminuer le temps passe dans scan ligne */ + +# define INCREMENT_ALLOC_NB_LIGNES_DE_SUPER_LIGNE 0 /* Correspond aux lignes ajoutees dans super ligne */ +# define INCREMENT_ALLOC_NB_COLONNES_DE_SUPER_LIGNE 50 /* Correspond aux nouveaux termes crees */ + +/*****************************************************************************/ + +/*******************************************************************************************/ +# define DEFINITIONS_CONSTANTES_INTERNES_LU_FAITE +# endif + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_construire_probleme.c b/src/ext/Sirius_Solver/simplexe/lu/lu_construire_probleme.c new file mode 100644 index 0000000000..8e9128474d --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_construire_probleme.c @@ -0,0 +1,300 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Allouer / desallouer les tableaux pour la factoristion LU + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void LU_ConstruireProbleme( + MATRICE * Matrice, + double * ValeurDesTermesDeLaMatrice, + int * IndicesDeLigne, + int * Ideb, + int * NbTermesDesColonnes, + int NbCol, + int NbTrm_L, + int NbTrm_U + ) +{ +int icCourant; int il; long ilDeb; int i; int Ligne; int Colonne; int ic; +int icMax; int Rang; char Trouve; int MargePourCreationDeTermesLignes; +int MargePourCreationDeTermesColonnes; int * IndexCourant; +int * Ldeb; int * LNbTerm; int * LDernierPossible; int * LIndiceColonne; double * Elm; +int * LignePrecedente; int * LigneSuivante; +int * Cdeb; int * CNbTerm; int * CDernierPossible; int * CIndiceLigne; +int * ColonnePrecedente;int * ColonneSuivante; + +Matrice->Rang = NbCol; /* C'est le rang en etant optimiste */ +Rang = Matrice->Rang ; + +Matrice->RangAuCarre = (double) Rang * (double) Rang; +Matrice->RangAuCarrePlus1 = Matrice->RangAuCarre + 1; + +Matrice->MaxScan = 3; +if ( Matrice->ContexteDeLaFactorisation != LU_SIMPLEXE ) Matrice->MaxScan = 10; + +Matrice->PivotMin = Matrice->ValeurDuPivotMin; + +Matrice->EtapeSinguliere = Rang; + +Matrice->LuUpdateEnCours = NON_LU; + +Matrice->SecondMembreCreux = NON_LU; + +Matrice->FactoriserEnMatricePleine = NON_LU; + +i = Rang + 1; +Matrice->PlusPetitNombreDeTermesDesLignes = i; +Matrice->PlusPetitNombreDeTermesDesColonnes = i; + +/* Transferts dans les tableaux de travail */ +/* Initialisations */ + +for ( i = 0 ; i < Rang; i++ ) Matrice->AbsDuPlusGrandTermeDeLaLigne[i] = -1.; +memset( (char *) Matrice->ColonneRejeteeTemporairementPourPivotage, NON_LU , Rang * sizeof( char ) ); +memset( (char *) Matrice->LigneRejeteeTemporairementPourPivotage , NON_LU , Rang * sizeof( char ) ); +for ( i = 0 ; i <= Rang; i++ ) Matrice->PremLigne[i] = -1; +for ( i = 0 ; i < Rang; i++ ) Matrice->OrdreLigne[i] = i; +for ( i = 0 ; i < Rang; i++ ) Matrice->InverseOrdreLigne[i] = i; +for ( i = 0 ; i < Rang; i++ ) Matrice->OrdreColonne[i] = i; +for ( i = 0 ; i < Rang; i++ ) Matrice->InverseOrdreColonne[i] = i; + +MargePourCreationDeTermesLignes = Matrice->MargePourCreationDeTermesLignes; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LDernierPossible = Matrice->LDernierPossible; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; +LignePrecedente = Matrice->LignePrecedente; +LigneSuivante = Matrice->LigneSuivante; + +Cdeb = Matrice->Cdeb; +CNbTerm = Matrice->CNbTerm; +CDernierPossible = Matrice->CDernierPossible; +CIndiceLigne = Matrice->CIndiceLigne; +ColonnePrecedente = Matrice->ColonnePrecedente; +ColonneSuivante = Matrice->ColonneSuivante; + +for ( i = 0 ; i < Rang ; i++ ) { + LignePrecedente [i] = i-1; + ColonnePrecedente[i] = i-1; + LigneSuivante [i] = i+1; + ColonneSuivante [i] = i+1; +} +LigneSuivante [Rang - 1] = -1; +ColonneSuivante[Rang - 1] = -1; + +memset( (char *) LNbTerm, 0, Rang * sizeof( int ) ); +for ( Colonne = 0 ; Colonne < Rang ; Colonne++ ) { + ic = Ideb[Colonne]; + icMax = ic + NbTermesDesColonnes[Colonne]; + while ( ic < icMax ) { + LNbTerm[IndicesDeLigne[ic]]++; + ic++; + } +} + +IndexCourant = (int *) Matrice->W; +il = 0; +for ( Ligne = 0 ; Ligne < Rang ; Ligne++ ) { + Ldeb[Ligne] = il; + IndexCourant[Ligne] = il; + il += LNbTerm[Ligne] + MargePourCreationDeTermesLignes; + LDernierPossible[Ligne] = il - 1; +} +Matrice->LIndexLibre = il; +Matrice->DerniereLigne = Rang - 1; + +/* Stockage des lignes */ +if ( Matrice->FaireDuPivotageDiagonal == NON_LU ) { + for ( Colonne = 0 ; Colonne < Rang ; Colonne++ ) { + ic = Ideb[Colonne]; + icMax = ic + NbTermesDesColonnes[Colonne]; + while ( ic < icMax ) { + il = IndexCourant[IndicesDeLigne[ic]]; + IndexCourant[IndicesDeLigne[ic]]++; + Elm[il] = ValeurDesTermesDeLaMatrice[ic]; + LIndiceColonne[il] = Colonne; + ic++; + } + } +} +else { + /* Si on fait du pivotage diagonal on met le terme diagonal en premier */ + /* Attention, il faut absolument qu'il y ait un terme diagonal meme nul */ + for ( Colonne = 0 ; Colonne < Rang ; Colonne++ ) { + ic = Ideb[Colonne]; + icMax = ic + NbTermesDesColonnes[Colonne]; + while ( ic < icMax ) { + Ligne = IndicesDeLigne[ic]; + il = IndexCourant[Ligne]; + IndexCourant[Ligne]++; + if ( Ligne == Colonne ) { + ilDeb = Ldeb[Ligne]; + /* On inverse */ + Elm [il] = Elm[ilDeb]; + LIndiceColonne[il] = LIndiceColonne[ilDeb]; + Elm [ilDeb] = ValeurDesTermesDeLaMatrice[ic]; + LIndiceColonne[ilDeb] = Colonne; + ic++; + goto SansTest; + } + else { + Elm [il] = ValeurDesTermesDeLaMatrice[ic]; + LIndiceColonne[il] = Colonne; + } + ic++; + } + + /* Si on ne trouve pas de terme diagonal, on en met un qui vaut 0. On tape un peu dans la marge allouee + mais comme elle n'est pas nulle, ca passe */ + Ligne = Colonne; + ilDeb = Ldeb[Ligne]; + il = ilDeb + LNbTerm[Ligne]; + Elm [il] = Elm[ilDeb]; + LIndiceColonne[il] = LIndiceColonne[ilDeb]; + Elm [ilDeb] = 0.0; + LIndiceColonne[ilDeb] = Colonne; + LNbTerm[Ligne]++; + /* Comme on a cree un terme qui ne figurait pas dans la matrice d'entree, il faut en tenir compte + dans le nombre de termes de la matrice */ + Matrice->NombreDeTermes++; + Matrice->LIndexLibre++; + + SansTest: + while ( ic < icMax ) { + il = IndexCourant[IndicesDeLigne[ic]]; + IndexCourant[IndicesDeLigne[ic]]++; + Elm [il] = ValeurDesTermesDeLaMatrice[ic]; + LIndiceColonne[il] = Colonne; + ic++; + } + } +} + +/* Stockage des colonnes si necessaire */ +if ( Matrice->LaMatriceEstSymetriqueEnStructure == OUI_LU ) { + /* Pas besoin du stockage par colonne */ + goto FinDesOperationsDeStockage; +} + +if ( Matrice->LaMatriceEstSymetrique == OUI_LU ) { + /* Pas besoin du stockage par colonne */ + goto FinDesOperationsDeStockage; +} + +/* Stockage par colonnes */ +for ( i = 0 ; i <= Rang; i++ ) Matrice->PremColonne[i] = -1; + +MargePourCreationDeTermesColonnes = Matrice->MargePourCreationDeTermesColonnes; + +/* Colonne de la matrice */ +icCourant = 0; +if ( Matrice->FaireDuPivotageDiagonal == NON_LU ) { + for ( Colonne = 0 ; Colonne < Rang ; Colonne++ ) { + ic = Ideb[Colonne]; + icMax = ic + NbTermesDesColonnes[Colonne]; + Cdeb [Colonne] = icCourant; + CNbTerm[Colonne] = NbTermesDesColonnes[Colonne]; + while ( ic != icMax ) { + CIndiceLigne[icCourant] = IndicesDeLigne[ic]; + icCourant++; + ic++; + } + icCourant += MargePourCreationDeTermesColonnes; + CDernierPossible[Colonne] = icCourant - 1; + } +} +else { + /* Pivotage diagonal demande */ + Trouve = NON_LU; + for ( Colonne = 0 ; Colonne < Rang ; Colonne++ ) { + ic = Ideb[Colonne]; + icMax = ic + NbTermesDesColonnes[Colonne]; + Cdeb [Colonne] = icCourant; + CNbTerm[Colonne] = NbTermesDesColonnes[Colonne]; + while ( ic != icMax ) { + Ligne = IndicesDeLigne[ic]; + if ( Ligne == Colonne ) Trouve = OUI_LU; + /* */ + CIndiceLigne[icCourant] = Ligne; + icCourant++; + /* */ + ic++; + } + /* Si on a demande le pivotage diagonal et qu'il n'y a pas de terme diagonal on en cree un */ + /* On tape dans la marge d'allocation */ + if ( Trouve == NON_LU ) { + CIndiceLigne[icCourant] = Colonne; + CNbTerm[Colonne]++; + } + icCourant += MargePourCreationDeTermesColonnes; + CDernierPossible[Colonne] = icCourant - 1; + } +} +Matrice->CIndexLibre = CDernierPossible[Rang - 1] + 1; +Matrice->DerniereColonne = Rang - 1; + +FinDesOperationsDeStockage: + +Matrice->Kp = 0; + +/* Informations pour les triangles */ +Matrice->IndexLibreDeL = 0; +Matrice->DernierIndexLibreDeL = NbTrm_L - 1; + +Matrice->IndexLibreDeU = 0; +Matrice->DernierIndexLibreDeU = NbTrm_U - 1; + +memset( Matrice->W , 0 , Rang * sizeof( double ) ); +memset( Matrice->Marqueur , 0 , Rang * sizeof( char ) ); + +/* CNbTerm et CNbTermMatriceActive inutile dans le cas des matrices symetriques ou symetriques en topologie */ +/* On pourrait donc dans ce cas ne pas les allouer non plus */ +memcpy( (char *) Matrice->CNbTermMatriceActive, (char *) Matrice->CNbTerm, Rang * sizeof( int ) ); + +/* Scaling eventuel */ +if ( Matrice->FaireScaling == OUI_LU ) LU_CalculerLeScaling( Matrice ); +/* Attention: Matrice->FaireScaling peut etre mis a NON_LU dans LU_CalculerLeScaling */ +if ( Matrice->FaireScaling == OUI_LU ) LU_Scaling( Matrice ); + +return; +} + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_define.h b/src/ext/Sirius_Solver/simplexe/lu/lu_define.h new file mode 100644 index 0000000000..b7bd54fa1e --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_define.h @@ -0,0 +1,341 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef LU_DEFINE_DEJA_DEFINI +/*****************************************************************************/ + +# include "lu_sys.h" +# include "lu_constantes_externes.h" +# include "lu_definition_arguments.h" +# include "lu_constantes_internes.h" + +/*****************************************************************************/ +/* Super lignes dans le cas de la factorisation des matrices non symetriques: en test + utilise pour diminuer le temps passe dans scan ligne */ + +typedef struct { +int NumeroDeLaSuperLigne; +int ScannerLaSuperLigne; /* Vaut OUI ou NON */ +int NombreDeLignesDeLaSuperLigne; +int * NumerosDesLignesDeLaSuperLigne; +int * IndexDuTermeDiagonal; +/* Modele de la ligne */ +int NombreDeTermes; /* Correspond aussi au nombre de colonnes de la super ligne */ +int * IndiceColonne; +int Capacite; /* C'est le nombre de colonnes qu'on peut mettre dans la super ligne */ +/* Pointeur sur les colonnes de la super ligne */ +double * ElmColonneDeSuperLigne; +/* Colonnes de la super ligne */ +int CapaciteDesColonnes; /* C'est le nombre de termes qu'on peut mettre dans chaque colonne d'une super ligne */ +} SUPER_LIGNE_DE_LA_MATRICE; + +/*****************************************************************************/ + +typedef struct { +/* Pour les outils de gestion memoire */ +void * Tas; +/* */ +int IncrementDallocationDeL; +int IncrementDallocationDeU; +/* Contexte de la factorisation */ +char ContexteDeLaFactorisation; /* Vaut: + * LU_SIMPLEXE si la factorisation est utilisee par le simplexe + * LU_POINT_INTERIEUR si la factorisation est utilisee par le point interieur + * LU_GENERAL si la factorisation est utilisee dans les autres cas + */ +char UtiliserLesSuperLignes; /* Vaut OUI_LU ou NON_LU */ +char LaMatriceEstSymetriqueEnStructure; /* Vaut OUI_LU ou NON_LU */ +/* Remarque: prevu pour les matrices carrees seulement */ +int NombreDeTermesDeLaMatriceAFactoriser; +int MargePourCreationDeTermesLignes; +int MargePourCreationDeTermesColonnes; + +int Rang; /* Matrice supposee de rang plein => Rang = nombre de colonnes */ +double RangAuCarre; +double RangAuCarrePlus1; + +int MaxScan; + +double PivotMin; /* Plus petite valeur de pivot acceptable */ +double SeuilDePivotage; /* Seuil d'acceptabilite d'un pivot par rapport au plus grand terme de la ligne */ +int NombreDeChangementsDeSeuilDePivotage; + +/* Pour le pivotage de Markowitz */ +char * LigneRejeteeTemporairementPourPivotage; +char * ColonneRejeteeTemporairementPourPivotage; +double * AbsDuPlusGrandTermeDeLaLigne; +int PlusPetitNombreDeTermesDesLignes; +int PlusPetitNombreDeTermesDesColonnes; + +/* Pour la factorisation en matrice pleine */ +char FactoriserEnMatricePleine; +double ValeurDuPlusGrandTerme; +int LigneDuPlusGrandTerme; +int ColonneDuPlusGrandTerme; + +/* Stockage par ligne de la matrice active */ +int LIndexLibre; +int LDernierIndexLibrePossible; +int DerniereLigne; +int LIncrementDallocation; +int * LignePrecedente; +int * LigneSuivante; + +int * Ldeb; +int * LNbTerm; +int * LDernierPossible; +int * LIndiceColonne; +double * Elm; + +/* Chainage par colonne de la matrice active */ +int CIndexLibre; +int CDernierIndexLibrePossible; +int DerniereColonne; +int CIncrementDallocation; +int * ColonnePrecedente; +int * ColonneSuivante; + +int * Cdeb; +int * CNbTerm; +int * CNbTermMatriceActive; +int * CDernierPossible; +int * CIndiceLigne; + +/* Pointeur vers la super ligne si la ligne est dans une super ligne */ + char MatricePleineDansUneSeuleSuperLigne; + char LaMatriceEstPleine; + SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneDeLaLigne; + SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneAScanner; + SUPER_LIGNE_DE_LA_MATRICE ** SuperLigne; + int NombreDeSuperLignes; + int * PoidsDesColonnes; + /* Hash code */ + int HashModuloSize; + /* Valable pour les lignes et les super lignes */ + unsigned int * HashCodeLigne; + unsigned int * HashCodeSuperLigne; + + int * HashModuloPrem; + int * HashNbModuloIdentiques; + + char * TypeDeClassementHashCodeAFaire; + int * HashModuloSuiv; + int * HashModuloPrec; + /* Pour le declenchement */ + char OnDeclenche; + int NbFois; + int CycleDeBase; + int Cycle; + int NombreDePassagesDansSuperLignes; + double SeuilDeVariationDeBase; + double SeuilDeVariation; + double TauxPrec; + int SeuilNombreDeSuperLigneAGrouper; + int SeuilNombreDeLignesAGrouper; +/* Fin super lignes */ + +/* Pour le chainage des lignes en fonction du nombre de termes */ +int * PremLigne; +int * SuivLigne; +int * PrecLigne; + +/* Pour le chainage des colonne en fonction du nombre de termes */ +int * PremColonne; +int * SuivColonne; +int * PrecColonne; + +/* Termes de la matrice active */ +int TailleAlloueeLignes; +int PremierEmplacementDisponibleLigne; +int TailleAlloueeColonnes; +int PremierEmplacementDisponibleColonne; + +/* Infos de travail */ +double * W; +char * Marqueur; +/* + double * ValeurDesTermesDeLaColonnePivot; + int * LigneDesTermesDeLaColonnePivot; +*/ +int NbFillIn; /* Nombre de termes crees par la factorisation */ +int Kp; /* Etape de la factorisation */ + +char ExclureLesEchecsMarkowitz; +char LuUpdateEnCours; + +int CompteurExclusionMarkowitz; + +/* Permutations */ +char FaireDuPivotageDiagonal; /* OUI_LU ou NON_LU */ +char LaMatriceEstSymetrique; /* OUI_LU ou NON_LU */ +int * OrdreLigne; +int * InverseOrdreLigne; +int * OrdreColonne; +int * InverseOrdreColonne; + +/* Le triangle inferieur stocke par colonne */ +int IndexLibreDeL; +int DernierIndexLibreDeL; +int * NbTermesParColonneDeL; +int * CdebParColonneDeL; +double * ElmDeL; +int * IndiceLigneDeL; +int * IndexKpDeUouL; /* Utilise que par le point interieur */ + +/* Le triangle superieur stocke par ligne */ +int IndexLibreDeU; +int DernierIndexLibreDeU; +int * NbTermesParLigneDeU; +int * LdebParLigneDeU; +double * ElmDeU; +int * IndiceColonneDeU; +int * CapaciteParLigneDeU; + +char SecondMembreCreux; /* Vaut OUI_LU ou NON_LU */ + +/* Le triangle inferieur stocke par ligne */ +int * LdebParLigneDeL; +int * NbTermesParLigneDeL; +int * IndiceColonneParLigneDeL; +double * ElmDeLParLigne; + +/* Le triangle superieur stocke par colonne */ +int IndexLibreDeUParColonne; +int DernierIndexLibreDeUParColonne; +int * CdebParColonneDeU; +int * NbTermesParColonneDeU; +int * IndiceLigneParColonneDeU; +int * CapaciteParColonneDeU; +double * ElmDeUParColonne; +/* */ +int * StockageColonneVersLigneDeU; +/* */ +int * StockageLigneVersColonneDeU; +/* */ +int LimiteUpdatePourRefactorisation; +/* */ + +/* Vecteur temporaire pour les resolutions */ +double * SolutionIntermediaire; + +/* Pour l'hyper creux (simplexe uniquement) */ +char * NoeudDansLaliste; +int * ListeDesNoeuds; +int TailleAlloueeDePseudoPile; +int * PseudoPile; + +double RatioMoyen; +int NombreDeRatios; +int NbTermesAuDepart; + +double RatioMoyenTransposee; +int NombreDeRatiosTransposee; +int NbTermesAuDepartTransposee; + +/* En cas d'anomalie */ +int AnomalieDetectee; +jmp_buf Env; + +/* En cas de matrice singuliere */ +int EtapeSinguliere; /* Numero de l'etape de la factorisation a laquelle la matrice est singuliere */ +int * NumeroDeTriangleDeLaVariable; /* Permet de savoir si la variable est indeterminee ou si elle se trouve dans un triangle factorise */ + +/* Permutation pour la LU update */ +int * OrdreUcolonne; +int * InverseOrdreUcolonne; + +int NombreDeVecteursHAlloues; +int NombreDElementsHAlloues; + +int NombreDeLuUpdates; + +int * HDeb; +int * HLigne; +int * HNbTerm; +int * HIndiceColonne; +double * HValeur; +int IndexHLibre; + +double * ValeurElmSpike; +int * IndicesLignesDuSpike; +int NbTermesNonNulsDuSpike; +char SauvegardeDuResultatIntermediaire; /* Vaut OUI_LU ou NON_LU */ + +int MxTermesCreesLuUpdate; +int NbTermesCreesLuUpdate; + +/* Fin des donnees pour la LU_update */ + +/* Pour le Scaling s'il est demande */ +char FaireScaling; +char ScalingEnPuissanceDe2; +double * ScaleX; +double * ScaleB; + +/* Pour le pivotage diagonal s'il est demande */ +double * AbsValeurDuTermeDiagonal; + +/* Les seuils */ +char UtiliserLesValeursDePivotNulParDefaut; /* Vaut OUI_LU ou NON_LU ( valeur conseillee: OUI_LU ) */ +double ValeurDuPivotMin; /* Si UtiliserLesValeursDePivotNulParDefaut est egal a NON_LU, alors le module */ +double ValeurDuPivotMinExtreme; /* de factorisation utilise ces valeurs de pivot min */ +int NombreMaxDeChangementsDeSeuilDePivotage; + +/* Pour la refactorisation (specifique point interieur) */ +int * DebutInfosAdressesQueKpModifie; /* Nombre de lignes/colonnes */ +double ** AdresseDeUModifie; +double ** AdresseUHaut; +int * DebutInfosLignesQueKpModifie; /* Nombre de lignes/colonnes */ +int * NombreDeLignesQueKpModifie; /* Nombre de lignes/colonnes */ +double ** AdresseUGauche; +int * NombreDeTermesParLigneQueKpModifie; +int PremierKpParCalculClassique; + +/* Stockage du pointeur vers la matrice d'entree */ +MATRICE_A_FACTORISER * MatriceEntree; + +/* Pour le raffinement iteratif */ +double * SecondMembreSV; +double * SolutionSV; + +/* Pour la mise au point des super lignes */ +int NbScanSuperLignes; +int NbLignesSuperLignes; +int NbScanMin; +int NombreDeTermes; + +/* Pour la regularisation dans le cas du point interieur */ +double ValeurDeRegularisation; +char OnARegularise; +char OnPeutRegulariser; +double * TermeDeRegularisation; + +} MATRICE; + +/*******************************************************************************************/ +# define LU_DEFINE_DEJA_DEFINI +# endif +# ifdef __cplusplus + } +# endif + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_definition_arguments.h b/src/ext/Sirius_Solver/simplexe/lu/lu_definition_arguments.h new file mode 100644 index 0000000000..8338976975 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_definition_arguments.h @@ -0,0 +1,165 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef MATRICE_A_FACTORISER_DEJA_DEFINI +/*******************************************************************************************/ +/* + Le passage des informations a la routine de factorisation lu se fait par un pointeur + a la structure C definie ci-apres. + + Le fichier lu_definition_arguments.h doit etre inclus dans le code de l'appelant, + il contient la definition de la structure C exploitee par la fonction de factorisation. + Apres avoir renseigne les champs, le module utilisateur appelle la fonction + LU_Factorisation avec, pour argument d'appel, un pointeur a la structure ci-dessous. + LU_Factorisation retourne un pointeur ŕ un objet de type MATRICE. En cas d'erreur interne + telle que saturation memoire, la valeur de ce pointeur vaut NULL. + + + Exemple d'utilisation : + + MATRICE_A_FACTORISER Ma_Matrice; <- definition d'une structure "Ma_Matrice" de type MATRICE_A_FACTORISER + + MATRICE * MatriceFactorisee; <- Contient la valuer du pointeur ŕ un objet de type MATRICE renvoyé + par LU_Factorisation + + Remplissage des champs de la structure: + + Ma_Matrice.ValeurDesTermesDeLaMatrice = adresse du vecteur contenant les termes de la matrice a factoriser; + Ma_Matrice.IndicesDeLigne = adresse du vecteur contenant les indices de lignes; + Ma_Matrice.IndexDebutDesColonnes = adresse du vecteur contenant les index debut des colonnes; + Ma_Matrice.NbTermesDesColonnes = adresse du vecteur contenant le nombre de termes de chaque colonne; + etc.. + + Appel de la fonction: + + MatriceFactorisee = LU_Factorisation( &Matrice ); + +*/ + +typedef struct { + /* Contexte d'utilisation de la factorisation */ + char ContexteDeLaFactorisation; /* L'utilisateur doit positionner cet indicateur a l'une des + valeurs suivantes: + * LU_SIMPLEXE si la factorisation est utilisee par le simplexe + * LU_POINT_INTERIEUR si la factorisation est utilisee par le point interieur + * LU_GENERAL si la factorisation est utilisee dans les autres cas + */ + char UtiliserLesSuperLignes; /* Vaut OUI_LU ou NON_LU */ + char LaMatriceEstSymetriqueEnStructure; /* Vaut OUI_LU ou NON_LU */ + /* La matrice a factoriser */ + double * ValeurDesTermesDeLaMatrice; /* Tout est dit dans le nom (c'est un long vecteur) */ + int * IndicesDeLigne; /* Vecteur parallele a "ValeurDesTermesDeLaMatrice". + Pour chaque terme d'une colonne il donne son indice + de ligne. Attention, les termes d'une meme colonne + doivent etre ranges dans l'ordre croissant des + indices de ligne */ + int * IndexDebutDesColonnes; /* Pour chaque colonne de la matrice, index debut des valeurs de ses termes + dans "ValeurDesTermesDeLaMatrice" */ + int * NbTermesDesColonnes; + int NombreDeColonnes; /* On suppose que le nombre de lignes est egal au nombre de colonnes */ + /* Code retour de la factorisation */ + int ProblemeDeFactorisation; /* Le code retour ( NON_LU si tout s'est bien passe ) */ + + /* Les options de factorisation */ + int FaireScalingDeLaMatrice; /* L'utilisateur doit positionner cet indicateur a: + * OUI_LU s'il veut que la factorisation fasse du + scaling automatiquement. + * NON_LU dans le cas contraire */ + + char UtiliserLesValeursDePivotNulParDefaut; /* Vaut OUI_LU ou NON_LU ( valeur conseillee: OUI_LU ) */ + double ValeurDuPivotMin; /* Si UtiliserLesValeursDePivotNulParDefaut est egal a NON_LU, alors le module */ + double ValeurDuPivotMinExtreme; /* de factorisation utilise ces valeurs de pivot min */ + + char SeuilPivotMarkowitzParDefaut; /* Vaut OUI_LU ou NON_LU ( valeur conseillee: OUI_LU ) */ + double ValeurDuPivotMarkowitz; /* Lorsque "SeuilPivotMarkowitzParDefaut" est positionne a OUI_LU, + La valeur "ValeurDuPivotMarkowitz" remplace la valeur par defaut. + "ValeurDuPivotMarkowitz" doit etre inferieure ou egale a 1. + - Lorsqu'elle vaut 1 l'algorithme ne peut que pivoter sur le plus grand + terme de la ligne ce qui conduit a un remplissage important + de la matrice factorisee. + - Plus la valeur est petite, moins la factorisee sera pleine. Mais un seuil + trop petit peut conduire a des instabilites numeriques. + - Avec une grande valeur, plus la factorisee sera numeriquement plus stable, + avec en contrepartie un factorisee plus pleine. Petit bemol: ceci c'est de la + theorie car en pratique si le nombre de termes de la factorisee augmente, + le nombre d'operations aussi et donc l'impact des erreurs d'arrondi + machine aussi. Donc, rester raisonnable SVP. + - Il est conseille de ne jamais descendre en dessous de 0.01 Plus*/ + + char FaireDuPivotageDiagonal; /* Vaut OUI_LU ou NON_LU */ + char LaMatriceEstSymetrique; /* Vaut OUI_LU ou NON_LU, cette information n'est prise en compte + que si FaireDuPivotageDiagonal est egal a OUI_LU */ + + /*************************************************************************************************/ + /* Ci-dessous resultats specifiques pour l'observabilite numerique de l'estimation d'etat: + ces infos ne sont plus utilisees par l'estimation d'etat. On les garde encore quelque temps + au cas ou ..*/ + + /* En retour, les triangles L et U de la factorisee */ + /* Le triangle L stocke par colonne */ + /* Le premier terme de chaque colonne vaut 1. Les termes suivant de la colonne ne sont + pas classes dans un ordre specifique. */ + int * IndexDebutDesColonnesDeL; + int * NbTermesDesColonnesDeL; + double * ValeurDesTermesDeL; + int * IndicesDeLigneDeL; /* Remarque: correspond aussi a l'indice ligne "natif" du terme */ + + /* Le triangle U stocke par ligne */ + /* Le premier terme de chaque ligne est egal a l'inverse du pivot. Les termes suivants + de la ligne ne sont pas classes dans un ordre specifique. */ + int * IndexDebutDesLignesDeU; + int * NbTermesDesLignesDeU; + double * ValeurDesTermesDeU; + int * IndicesDeColonneDeU; /* Remarque: correspond ausss a l'indice colonne "natif" du terme */ + + /* Fin des resultats specifiques pour l'observabilite numerique de l'estimation d'etat */ + /*************************************************************************************************/ + + /*************************************************************************************************/ + /* Ci-dessous resultats specifiques pour le point interieur du solveur */ + + /* Informations supplementaires qui sont utilisees uniquement pour le point interieur c'est a dire + lorsque "ContexteDeLaFactorisation" vaut "LU_POINT_INTERIEUR" */ + double ValeurDeRegularisation; /* Valeur de remplacement du pivot nul: a fournir par l'utilisateur. + Typiquement mettre 1.e-8 mais pas en dessous */ + char OnARegularise; /* Information renvoyee par la factorisation. Elle vaut OUI_LU si + la factorisation a ete obligee de regularise, NON_LU sinon. */ + double * TermeDeRegularisation; /* Ce vecteur doit etre alloue par l'utilisation. Sa dimension + doit etre egale au nombre de colonnes (ou de lignes) de la matrice. + L'utilisateur doit imperativement initialiser ce vecteur. + La premiere fois il doit l'initialiser a 0. Les fois suivantes, + il peut, soit reinitialiser a 0, soit conserver les valeurs qu'il y a + deja dedans. + Lorsque la factorisation est obligee de regulariser, i.e. remplacer + un terme diagonal nul par une petite valeur, elle ajoute aussi cette + valeur de regularisation a la valeur contenue dans le vecteur (pour + la colonne consideree. */ + /* Fin des resultats specifiques pour le point interieur du solveur */ + /*************************************************************************************************/ + +} MATRICE_A_FACTORISER; + +/*******************************************************************************************/ +# define MATRICE_A_FACTORISER_DEJA_DEFINI +# endif +# ifdef __cplusplus + } +# endif + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne.c b/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne.c new file mode 100644 index 0000000000..d8885e27cd --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne.c @@ -0,0 +1,564 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU de la base. Elimination de la ligne pivot. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_EliminationDUneLigne( MATRICE * Matrice , int LignePivot , int ColonnePivot ) +{ +int il; int ilDeb; int ic; int icDeb; int i; int ilDebLignePivot; double X; int ilDer; int j; int NbNonuLignePivot; +double UnSurValeurDuPivot; int NbTermesLignePivot; int NbTermesColonnePivot; +int Ligne; int Colonne; char * T ; double * W; int * IndiceColonne ; +double ValTermeColonnePivot; char FaireDuPivotageDiagonal ; int CapaciteDesColonnes ; +double * AbsDuPlusGrandTermeDeLaLigne ; double PivotMin; double * AbsValeurDuTermeDiagonal; +char ContexteDeLaFactorisation; char LignePivotDansSuperLigne; +char StockageLignesRedimensionne; char StockageColonnesRedimensionne; + +int * IndiceLigneDeL; double * ElmDeL; int ilL; int ilColonnePivot; + +int * Ldeb; int * LNbTerm; int * LDernierPossible; int * LIndiceColonne; double * Elm; +int * Cdeb; int * CNbTermMatriceActive; int * CDernierPossible; int * CIndiceLigne; + +/* Pour les super lignes */ +SUPER_LIGNE_DE_LA_MATRICE * SuperLigne ; SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneDeLaLigne ; +SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneAScanner ; double * ElmColonneDeSuperLigne ; +int * NumerosDesLignesDeLaSuperLigne; int k ; char * TypeDeClassementHashCodeAFaire ; +int NombreDeTermesDeLaSuperLigne; int Element ; int icDebColonnePivot; +double * ValeurDesTermesDeColonnePivot ; SUPER_LIGNE_DE_LA_MATRICE * SuperLigneDeLaLignePivot; +int * PoidsDesColonnes; int NombreDeSuperLignesAScanner ; +int NombreDePassagesDansSuperLignes ; unsigned int * HashCodeLigne ; +char UtiliserLesSuperLignes; + +/* Fin super lignes */ + +/* +printf("Matrice->Kp = %d LignePivot %d ColonnePivot %d rang %d\n",Matrice->Kp,LignePivot,ColonnePivot,Matrice->Rang); +*/ + +UtiliserLesSuperLignes = Matrice->UtiliserLesSuperLignes; + +ContexteDeLaFactorisation = Matrice->ContexteDeLaFactorisation; + +FaireDuPivotageDiagonal = Matrice->FaireDuPivotageDiagonal; +PivotMin = Matrice->PivotMin; +AbsValeurDuTermeDiagonal = Matrice->AbsValeurDuTermeDiagonal; +AbsDuPlusGrandTermeDeLaLigne = Matrice->AbsDuPlusGrandTermeDeLaLigne; + +LignePivotDansSuperLigne = NON_LU; + +if ( UtiliserLesSuperLignes == OUI_LU ) { + NombreDePassagesDansSuperLignes = Matrice->NombreDePassagesDansSuperLignes; + /* Utilisation des super lignes */ + NombreDeSuperLignesAScanner = 0; + SuperLigneDeLaLigne = Matrice->SuperLigneDeLaLigne; + SuperLigneAScanner = Matrice->SuperLigneAScanner; + TypeDeClassementHashCodeAFaire = Matrice->TypeDeClassementHashCodeAFaire; + HashCodeLigne = Matrice->HashCodeLigne; + PoidsDesColonnes = Matrice->PoidsDesColonnes; + /* Si la ligne pivot se trouve dans une SuperLigne, on la recopie dans un tableau particulier, + et on fait pointer IndiceColonne et Elm vers ces tableaux, puis on l'enleve de la SuperLigne */ + SuperLigneDeLaLignePivot = SuperLigneDeLaLigne[LignePivot]; + if ( SuperLigneDeLaLigne[LignePivot] != NULL ) { + /* Recopie de la ligne pivot vers le stockage standard des lignes */ + LU_RecopierUneLigneDeSuperLigneDansLigne( Matrice, SuperLigneDeLaLigne[LignePivot], LignePivot ); + LignePivotDansSuperLigne = OUI_LU; + /* Suppression de la LignePivot dans la SuperLigne */ + LU_SupprimerUneLigneDansUneSuperLigne( Matrice , SuperLigneDeLaLigne[LignePivot] , LignePivot , ColonnePivot ); + } +} + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LDernierPossible = Matrice->LDernierPossible; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +Cdeb = Matrice->Cdeb; +CNbTermMatriceActive = Matrice->CNbTermMatriceActive; +CDernierPossible = Matrice->CDernierPossible; +CIndiceLigne = Matrice->CIndiceLigne; + +ilDebLignePivot = Ldeb[LignePivot]; +NbTermesLignePivot = LNbTerm[LignePivot]; + +icDebColonnePivot = Cdeb[ColonnePivot]; +NbTermesColonnePivot = CNbTermMatriceActive[ColonnePivot]; + +Matrice->IndexLibreDeU += NbTermesLignePivot; /* Servira a allouer le triangle U */ + +/* On enleve deja le nombre de termes de la ligne pivot */ +Matrice->NombreDeTermes-= NbTermesLignePivot; + +if ( FaireDuPivotageDiagonal == OUI_LU ) { + if ( LignePivotDansSuperLigne == OUI_LU ) { + /* Si la ligne etait dans une super ligne il faut remettre le terme diagonal en premier car il a pu changer de place */ + for ( il = ilDebLignePivot ; LIndiceColonne[il] != ColonnePivot ; il++ ); + LIndiceColonne[il] = LIndiceColonne[ilDebLignePivot]; + LIndiceColonne[ilDebLignePivot] = ColonnePivot; + X = Elm[ilDebLignePivot]; + Elm[ilDebLignePivot] = Elm[il]; + Elm[il] = X; + } +} + +W = Matrice->W; +T = Matrice->Marqueur; + +UnSurValeurDuPivot = 1.; /* Pour pas etre emmerde par les warning a la con */ +/* Transfert de la ligne dans un tableau de travail */ +if ( NbTermesColonnePivot > 1 ) { + if ( FaireDuPivotageDiagonal == NON_LU ) { + for ( il = ilDebLignePivot ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + if ( Colonne == ColonnePivot ) ilColonnePivot = il; + W[Colonne] = Elm[il]; + T[Colonne] = 1; + /* Il faut dechainer la colonne du chainage fonction du nombre de termes car son nombre de termes changera */ + LU_DeClasserUneColonne( Matrice , Colonne , CNbTermMatriceActive[Colonne] ); + } + UnSurValeurDuPivot = 1. / W[ColonnePivot]; + W[ColonnePivot] = 0.0; + T[ColonnePivot] = 0; + } + else { + /* Si l'on a choisi l'option du pivotage diagonal, le terme diagonal est toujours range en premier */ + ilColonnePivot = ilDebLignePivot; + for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + W[Colonne] = Elm[il]; + T[Colonne] = 1; + } + UnSurValeurDuPivot = 1. / Elm[ilDebLignePivot]; + } +} +else { + /* Pas besoin de W et T */ + if ( FaireDuPivotageDiagonal == NON_LU ) { + for ( il = ilDebLignePivot ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + if ( Colonne == ColonnePivot ) { + UnSurValeurDuPivot = 1. / Elm[il]; + ilColonnePivot = il; + } + LU_DeClasserUneColonne( Matrice , Colonne , CNbTermMatriceActive[Colonne] ); + } + } + else { + ilColonnePivot = ilDebLignePivot; + UnSurValeurDuPivot = 1. / Elm[ilDebLignePivot]; + } +} + +/* Il faut dechainer la ligne pivot du chainage fonction du nombre de termes (la colonne pivot a ete dechainee ci-dessus + dans la foulee) */ +LU_DeClasserUneLigne( Matrice , LignePivot , NbTermesLignePivot ); + +/* On inverse tout de suite le pivot */ +X = Elm[ilDebLignePivot]; +Elm[ilDebLignePivot] = UnSurValeurDuPivot; +if ( ilColonnePivot != ilDebLignePivot ) { + Elm[ilColonnePivot] = X; + LIndiceColonne[ilColonnePivot] = LIndiceColonne[ilDebLignePivot]; + LIndiceColonne[ilDebLignePivot] = ColonnePivot; +} + +ElmDeL = Matrice->ElmDeL; +IndiceLigneDeL = Matrice->IndiceLigneDeL; +/* Transfert de la colonne pivot dans la triangulaire inferieure L et modification de la matrice active */ +/* Le terme diagonal vaut 1 et est stocke pour beneficier de l'indice ligne */ +if ( Matrice->IndexLibreDeL + NbTermesColonnePivot > Matrice->DernierIndexLibreDeL ) { + LU_AugmenterLaTailleDuTriangleL( Matrice , NbTermesColonnePivot ); + ElmDeL = Matrice->ElmDeL; + IndiceLigneDeL = Matrice->IndiceLigneDeL; +} + +Matrice->NbTermesParColonneDeL[Matrice->Kp] = NbTermesColonnePivot; + +ilL = Matrice->IndexLibreDeL; +Matrice->CdebParColonneDeL[Matrice->Kp] = ilL; + +/* Initialisaton de ElmDeL */ +ElmDeL [ilL] = 1.; +IndiceLigneDeL[ilL] = LignePivot; +ilL++; + +if ( UtiliserLesSuperLignes == OUI_LU ) { + /* Si la ligne pivot est dans une super ligne on ne met pas a jour son type de classement au cas ou + elle aurait deja ete declassee */ + if ( SuperLigneDeLaLigne[LignePivot] == NULL ) { + TypeDeClassementHashCodeAFaire[LignePivot] = ELEMENT_HASCODE_A_DECLASSER; + } +} + +NbNonuLignePivot = NbTermesLignePivot - 1; + +/* S'il n'y a qu'un seul terme dans la colonne pivot, il n'y a rien a faire */ +if ( NbTermesColonnePivot <= 1 ) goto FinDuScanningDesLignes; + +StockageLignesRedimensionne = NON_LU; +StockageColonnesRedimensionne = NON_LU; + +ic = icDebColonnePivot; +for ( i = 0 ; i < NbTermesColonnePivot ; i++ , ic++ ) { + Ligne = CIndiceLigne[ic]; + if ( Ligne != LignePivot ) { + + if ( UtiliserLesSuperLignes == OUI_LU ) { + /* Si la Ligne est dans une SuperLigne on ne fait rien */ + if ( NombreDePassagesDansSuperLignes > 0 ) { + if ( SuperLigneDeLaLigne[Ligne] != NULL ) { + if ( SuperLigneDeLaLigne[Ligne]->ScannerLaSuperLigne == NON_LU ) { + SuperLigneAScanner[NombreDeSuperLignesAScanner] = SuperLigneDeLaLigne[Ligne]; + NombreDeSuperLignesAScanner++; + SuperLigneDeLaLigne[Ligne]->ScannerLaSuperLigne = OUI_LU; + } + continue; + } + } + } + + /* Recherche de la valeur du terme de la ligne IndiceLigne qui se trouve dans la colonne pivot */ + ilDeb = Ldeb[Ligne]; + for ( il = ilDeb ; LIndiceColonne[il] != ColonnePivot ; il++ ); + ValTermeColonnePivot = Elm[il] * UnSurValeurDuPivot; + /* Triangle L */ + ElmDeL [ilL] = ValTermeColonnePivot; + IndiceLigneDeL[ilL] = Ligne; + ilL++; + /* */ + /* Il faut dechainer la ligne du chainage fonction du nombre de termes car son nombre de termes peut changer */ + LU_DeClasserUneLigne( Matrice , Ligne , LNbTerm[Ligne] ); + + if ( UtiliserLesSuperLignes == OUI_LU ) { + TypeDeClassementHashCodeAFaire[Ligne] = ELEMENT_HASCODE_A_RECLASSER; + } + + /* Suppression du terme dans le chainage par ligne */ + LNbTerm[Ligne]--; + ilDer = ilDeb + LNbTerm[Ligne]; + LIndiceColonne[il] = LIndiceColonne[ilDer]; + Elm [il] = Elm[ilDer]; + + Matrice->NombreDeTermes--; + + if ( UtiliserLesSuperLignes == OUI_LU ) { + HashCodeLigne[Ligne]-= PoidsDesColonnes[ColonnePivot]; + } + + /* Scan de la ligne */ + /* Attention il faut faire le scan ligne meme si ValTermeColonnePivot est egal a 0, car en cas de pivotage + diagonal sur matrice symetrique en topologie on perd la symetrie si on ne le fait pas */ + /* Et aussi pour avoir toujous les termes dans les refactorisations (hades) */ + if ( ContexteDeLaFactorisation != LU_SIMPLEXE ) { + if ( NbNonuLignePivot > 0 ) { + LU_ScanLigne( Matrice, Ligne, ilDebLignePivot, NbNonuLignePivot, ValTermeColonnePivot, LignePivot, + &StockageLignesRedimensionne, &StockageColonnesRedimensionne ); + T[ColonnePivot] = 0; + } + } + else { + if ( NbNonuLignePivot > 0 && ValTermeColonnePivot != 0.0 ) { + LU_ScanLigne( Matrice, Ligne, ilDebLignePivot, NbNonuLignePivot, ValTermeColonnePivot, LignePivot, + &StockageLignesRedimensionne, &StockageColonnesRedimensionne ); + T[ColonnePivot] = 0; + } + } + if ( StockageColonnesRedimensionne == OUI_LU ) { + CIndiceLigne = Matrice->CIndiceLigne; + ic = Cdeb[ColonnePivot] + i; + StockageColonnesRedimensionne = NON_LU; + } + if ( StockageLignesRedimensionne == OUI_LU ) { + LIndiceColonne = Matrice->LIndiceColonne; + Elm = Matrice->Elm; + ilDebLignePivot = Ldeb[LignePivot]; + StockageLignesRedimensionne = NON_LU; + } + /* Si l'on a choisi l'option du pivotage diagonal */ + if ( FaireDuPivotageDiagonal == OUI_LU ) { + /* Le terme diagonal est toujours range en premier */ + /* Si le terme diagonal est trop petit on ne reclasse pas la ligne */ + X = fabs( Elm[Ldeb[Ligne]] ); + if ( X > PivotMin ) { + AbsDuPlusGrandTermeDeLaLigne[Ligne] = -1.0; + /* Pas besoin de mettre une valeur negative si < a PivotMin car de toute facon c'est pas classe */ + AbsValeurDuTermeDiagonal[Ligne] = X; + LU_ClasserUneLigne( Matrice , Ligne , LNbTerm[Ligne] ); + } + } + else { + /* Preparations pour le calcul du nombre de Markowitz */ + AbsDuPlusGrandTermeDeLaLigne[Ligne] = -1.; + /* Pivotage partout */ + /* Remarque: a ce stade IndiceLigne ne peut pas etre egal a LignePivot */ + LU_ClasserUneLigne( Matrice , Ligne , LNbTerm[Ligne] ); + } + } +} + +if ( UtiliserLesSuperLignes == OUI_LU ) { + for ( j = 0 ; j < NombreDeSuperLignesAScanner ; j++ ) { + SuperLigne = SuperLigneAScanner[j]; + + ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; + NumerosDesLignesDeLaSuperLigne = SuperLigne->NumerosDesLignesDeLaSuperLigne; + NombreDeTermesDeLaSuperLigne = SuperLigne->NombreDeTermes; + IndiceColonne = SuperLigne->IndiceColonne; + + for ( il = 0 ; il < NombreDeTermesDeLaSuperLigne ; il++ ) { + if ( IndiceColonne[il] == ColonnePivot ) { + icDebColonnePivot = SuperLigne->CapaciteDesColonnes * il; + break; + } + } + + /* Modification des termes de la colonne pivot et stockage dans le triangle L */ + ic = icDebColonnePivot; + ValeurDesTermesDeColonnePivot = &(ElmDeL[ilL]); + for ( k = 0 ; k < SuperLigne->NombreDeLignesDeLaSuperLigne; k++ , ic++ ) { + ElmDeL [ilL] = ElmColonneDeSuperLigne[ic] * UnSurValeurDuPivot; + IndiceLigneDeL[ilL] = NumerosDesLignesDeLaSuperLigne[k]; + ilL++; + /* Il faut dechainer la ligne du chainage fonction du nombre de termes car son nombre de termes peut changer */ + AbsDuPlusGrandTermeDeLaLigne[NumerosDesLignesDeLaSuperLigne[k]] = -1.; + LU_DeClasserUneLigne( Matrice , NumerosDesLignesDeLaSuperLigne[k] , NombreDeTermesDeLaSuperLigne ); + } + + /* Suppression dans SuperLigne des termes de la colonne pivot */ + LU_SupprimerUnTermeDansUneSuperLigne( Matrice , SuperLigne ,icDebColonnePivot , il ); + /* Car on a supprime dans Ligne, le terme d'indice colonne LignePivot */ + Matrice->NombreDeTermes-= SuperLigne->NombreDeLignesDeLaSuperLigne; + + NombreDeTermesDeLaSuperLigne--; + + /* Scan de la SuperLigne */ + + LU_ScanSuperLigne( Matrice, SuperLigne, ilDebLignePivot, NbNonuLignePivot, ValeurDesTermesDeColonnePivot, + &Matrice->HashCodeSuperLigne[SuperLigne->NumeroDeLaSuperLigne] ); + + /* Au cas ou il y aurait eu un redimensionnement */ + ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; + NumerosDesLignesDeLaSuperLigne = SuperLigne->NumerosDesLignesDeLaSuperLigne; + NombreDeTermesDeLaSuperLigne = SuperLigne->NombreDeTermes; + + Element = SuperLigne->NumeroDeLaSuperLigne + Matrice->Rang; + if ( TypeDeClassementHashCodeAFaire[Element] != ELEMENT_HASCODE_A_CLASSER ) { + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_A_RECLASSER; + } + + T[ColonnePivot] = 0; + SuperLigne->ScannerLaSuperLigne = NON_LU; + + CapaciteDesColonnes = SuperLigne->CapaciteDesColonnes; + IndiceColonne = SuperLigne->IndiceColonne; + if ( FaireDuPivotageDiagonal == OUI_LU ) { + /* Pivotage diagonal */ + for ( k = 0 ; k < SuperLigne->NombreDeLignesDeLaSuperLigne; k++ , ic++ ) { + il = SuperLigne->IndexDuTermeDiagonal[k]; + X = fabs( ElmColonneDeSuperLigne[ (il * CapaciteDesColonnes) + k ] ); + if ( X > PivotMin ) { + Ligne = NumerosDesLignesDeLaSuperLigne[k]; + AbsDuPlusGrandTermeDeLaLigne[Ligne] = -1.; + /* Pas besoin de mettre une valeur negative si < PivotMin car pas classe et donc ne sera pas + rencontre dans selection du pivot diagonal */ + AbsValeurDuTermeDiagonal[Ligne] = X; + LU_ClasserUneLigne( Matrice , Ligne , NombreDeTermesDeLaSuperLigne ); + } + } + } + else { + /* Pivotage Markowitz */ + for ( k = 0 ; k < SuperLigne->NombreDeLignesDeLaSuperLigne; k++ , ic++ ) { + Ligne = NumerosDesLignesDeLaSuperLigne[k]; + /* Preparations pour le calcul du nombre de Markowitz */ + AbsDuPlusGrandTermeDeLaLigne[Ligne] = -1.; + LU_ClasserUneLigne( Matrice , Ligne , NombreDeTermesDeLaSuperLigne ); + } + } + } +} + +FinDuScanningDesLignes: + +Matrice->IndexLibreDeL = ilL; + +/* On remet aussi W et Marqueur a 0 */ +ilDebLignePivot = Ldeb[LignePivot]; +LIndiceColonne = Matrice->LIndiceColonne; +CIndiceLigne = Matrice->CIndiceLigne; + +if ( NbTermesColonnePivot > 1 ) { + if ( FaireDuPivotageDiagonal == NON_LU ) { + for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + W[Colonne] = 0.; + T[Colonne] = 0; + /* Mise a jour des colonnes */ + /* On ne supprime pas les termes de la LignePivot mais on decremente le nombre de termes utiles */ + CNbTermMatriceActive[Colonne]--; + LU_ClasserUneColonne( Matrice, Colonne, CNbTermMatriceActive[Colonne] ); + } + } + else { + /* Dans le cas du pivotage diagonal, le terme diagonal est toujours range en premier */ + for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + W[Colonne] = 0.; + T[Colonne] = 0; + /* Mise a jour des colonnes */ + /* On ne supprime pas les termes de la LignePivot mais on decremente le nombre de termes utiles */ + CNbTermMatriceActive[Colonne]--; + } + } +} +else { + if ( FaireDuPivotageDiagonal == NON_LU ) { + for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + /* Mise a jour des colonnes */ + /* On ne supprime pas les termes de la LignePivot mais on decremente le nombre de termes utiles */ + CNbTermMatriceActive[Colonne]--; + LU_ClasserUneColonne( Matrice , Colonne , CNbTermMatriceActive[Colonne] ); + } + } + else { + /* Dans le cas du pivotage diagonal, le terme diagonal est toujours range en premier */ + for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + /* Mise a jour des colonnes */ + /* On ne supprime pas les termes de la LignePivot mais on decremente le nombre de termes utiles */ + CNbTermMatriceActive[Colonne]--; + } + } +} + +if ( UtiliserLesSuperLignes == OUI_LU ) SuperLigneDeLaLigne[LignePivot] = NULL; + +/* Remarque: +On peut recupere la place occupee par la colonne eliminee et l'allouer a la colonne precedente mais cela +necessite de reprendre le codage de LU_AugmenterLaTailleDeLaMatriceActiveParColonne et de ne recopier +que les colonnes de la matrice active. On fera ca plus tard. Ci dessous la facon de faire pour recuperer +la place */ +/* +ic = Cdeb[ColonnePivot]; +Nb = Matrice->CNbTerm[ColonnePivot]; +ix = Matrice->CDernierPossible[ColonnePivot]; + +C1 = Matrice->ColonnePrecedente[ColonnePivot]; +C2 = Matrice->ColonneSuivante[ColonnePivot]; +if ( C1 >= 0 ) { + Matrice->CDernierPossible[C1] = ix; + if ( C2 >= 0 ) { + Matrice->ColonneSuivante [C1] = C2; + Matrice->ColonnePrecedente[C2] = C1; + } +} +else { + if ( C2 >= 0 ) Matrice->ColonnePrecedente[C2] = -1; +} +Matrice->ColonnePrecedente[ColonnePivot] = -1; +Matrice->ColonneSuivante[ColonnePivot] = -1; + +CNbTermMatriceActive[ColonnePivot] = 0; +Matrice->CNbTerm[ColonnePivot] = 0; +*/ + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne_cas_symetrique.c b/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne_cas_symetrique.c new file mode 100644 index 0000000000..0ab48eedf0 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne_cas_symetrique.c @@ -0,0 +1,497 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Elimination d'une ligne dans la cas symetrique (pivotage + diagonal). + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +void LU_EliminationDUneLigneMatricePleineCasSymetrique( MATRICE * , int , int ); + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_EliminationDUneLigneCasSymetrique( MATRICE * Matrice , int LignePivot , int ColonnePivot ) +{ +int il; int ic; int ilL; double X; char Contexte; +int * IndiceColonne; int NbNonuLignePivot; double UnSurValeurDuPivot; +double ValTermeColonnePivot; char * T; double * W; char MajValeurPivotDiagonal; +int NbTermesLignePivot; int Ligne; int NbTermesColonnePivot; int Colonne; +double * ElmDeL; int * IndiceLigneDeL ; +double * AbsValeurDuTermeDiagonal; double * AbsDuPlusGrandTermeDeLaLigne ; double PivotMin; + +int * Ldeb; int * LNbTerm; int * LDernierPossible; int * LIndiceColonne; double * Elm; + +char LignePivotDansSuperLigne; int ilDebLignePivot; char StockageLignesRedimensionne; + +/* Pour les super lignes */ +SUPER_LIGNE_DE_LA_MATRICE * SuperLigne ; SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneDeLaLigne ; +SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneAScanner; double * ElmColonneDeSuperLigne ; +int * NumerosDesLignesDeLaSuperLigne ; char * TypeDeClassementHashCodeAFaire ; +int CapaciteDesColonnes;int k;int j; int i ; double * ValeurDesTermesDeColonnePivot ; +int NombreDeTermesDeLaSuperLigne ; int Element ; +int NombreDeSuperLignesAScanner ; SUPER_LIGNE_DE_LA_MATRICE * SuperLigneDeLaLignePivot; +int icDebColonnePivot ; int NombreDePassagesDansSuperLignes ; +char UtiliserLesSuperLignes ; +/* Fin super lignes */ + +UtiliserLesSuperLignes = Matrice->UtiliserLesSuperLignes; + +if ( UtiliserLesSuperLignes == OUI_LU ) { + if ( Matrice->MatricePleineDansUneSeuleSuperLigne == OUI_LU ) { + LU_EliminationDUneLigneMatricePleineCasSymetrique( Matrice , LignePivot , ColonnePivot ); + return; + } +} + +Contexte = Matrice->ContexteDeLaFactorisation; + +PivotMin = Matrice->PivotMin; +AbsValeurDuTermeDiagonal = Matrice->AbsValeurDuTermeDiagonal; +AbsDuPlusGrandTermeDeLaLigne = Matrice->AbsDuPlusGrandTermeDeLaLigne; + +LignePivotDansSuperLigne = NON_LU; + +if ( UtiliserLesSuperLignes == OUI_LU ) { + NombreDePassagesDansSuperLignes = Matrice->NombreDePassagesDansSuperLignes; + /* Utilisation des super lignes */ + NombreDeSuperLignesAScanner = 0; + SuperLigneDeLaLigne = Matrice->SuperLigneDeLaLigne; + SuperLigneAScanner = Matrice->SuperLigneAScanner; + TypeDeClassementHashCodeAFaire = Matrice->TypeDeClassementHashCodeAFaire; + /* Si la ligne pivot se trouve dans une SuperLigne, on la recopie dans un tableau particulier, + et on fait pointer IndiceColonne et Elm vers ces tableaux, puis on l'enleve de la SuperLigne */ + SuperLigneDeLaLignePivot = SuperLigneDeLaLigne[LignePivot]; + if ( SuperLigneDeLaLignePivot != NULL ) { + /* Recopie de la ligne pivot vers un tableau compact */ + LU_RecopierUneLigneDeSuperLigneDansLigne( Matrice, SuperLigneDeLaLigne[LignePivot], LignePivot ); + LignePivotDansSuperLigne = OUI_LU; + /* Suppression de la LignePivot dans la SuperLigne */ + LU_SupprimerUneLigneDansUneSuperLigne( Matrice , SuperLigneDeLaLignePivot , LignePivot , ColonnePivot ); + } +} + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LDernierPossible = Matrice->LDernierPossible; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +ilDebLignePivot = Ldeb[LignePivot]; +NbTermesLignePivot = LNbTerm[LignePivot]; + +Matrice->IndexLibreDeU += NbTermesLignePivot; /* Servira a allouer le triangle U */ + +/* On enleve deja le nombre de termes de la ligne pivot */ +Matrice->NombreDeTermes-= NbTermesLignePivot; +if ( LignePivotDansSuperLigne == OUI_LU ) { + /* Si la ligne etait dans une super ligne il faut remettre le terme diagonal en premier car il a pu changer de place */ + for ( il = ilDebLignePivot ; LIndiceColonne[il] != ColonnePivot ; il++ ); + LIndiceColonne[il] = LIndiceColonne[ilDebLignePivot]; + LIndiceColonne[ilDebLignePivot] = ColonnePivot; + X = Elm[ilDebLignePivot]; + Elm[ilDebLignePivot] = Elm[il]; + Elm[il] = X; +} + +icDebColonnePivot = ilDebLignePivot; +NbTermesColonnePivot = NbTermesLignePivot; + +ElmDeL = Matrice->ElmDeL; +IndiceLigneDeL = Matrice->IndiceLigneDeL; + +W = Matrice->W; +T = Matrice->Marqueur; + +/* Transfert de la ligne dans un tableau de travail */ +/* Le terme diagonal est range en premier */ +UnSurValeurDuPivot = 1. / Elm[ilDebLignePivot]; + +/* On inverse tout de suite le terme pivot */ +Elm[ilDebLignePivot] = UnSurValeurDuPivot; + +for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + W[Colonne] = Elm[il]; + T[Colonne] = 1; +} + +/* Il faut dechainer la ligne pivot du chainage fonction du nombre de termes (la colonne pivot a ete dechainee + ci-dessus dans la foulee) */ +LU_DeClasserUneLigne( Matrice , LignePivot , NbTermesLignePivot ); + +if ( UtiliserLesSuperLignes == OUI_LU ) { + /* Si la ligne pivot est dans une super ligne on ne met pas a jour son type de classement au cas ou + elle aurait deja ete declassee */ + if ( SuperLigneDeLaLignePivot == NULL ) { + TypeDeClassementHashCodeAFaire[LignePivot] = ELEMENT_HASCODE_A_DECLASSER; + } +} + +NbNonuLignePivot = NbTermesLignePivot - 1; + +/* Transfert de la colonne pivot dans la triangulaire inferieure L et modification de la matrice active */ +/* Le terme diagonal vaut 1 et est stocke pour beneficier de l'indice ligne */ +if ( Matrice->IndexLibreDeL + NbTermesColonnePivot > Matrice->DernierIndexLibreDeL ) { + LU_AugmenterLaTailleDuTriangleL( Matrice , NbTermesColonnePivot ); + ElmDeL = Matrice->ElmDeL; + IndiceLigneDeL = Matrice->IndiceLigneDeL; +} + +Matrice->NbTermesParColonneDeL[Matrice->Kp] = NbTermesColonnePivot; + +ilL = Matrice->IndexLibreDeL; +Matrice->CdebParColonneDeL[Matrice->Kp] = ilL; + +/* Initialisaton de ElmDeL */ +Matrice->ElmDeL[ilL] = 1.; +Matrice->IndiceLigneDeL[ilL] = LignePivot; +ilL++; + +/* Maintenant on balaye toutes les lignes de la matrice active qui ont un terme non nul dans la colonne + pivot et on les compare a la ligne pivot (ce qui revient a balayer les termes de la ligne pivot) */ +StockageLignesRedimensionne = NON_LU; +ic = ilDebLignePivot + 1; +for ( i = 1 ; i < NbTermesLignePivot ; i++ , ic++ ) { + /* Le terme diagonal est toujours range en premier */ + /* En fait, il y a aussi un terme d'indice ligne egal a cette "Colonne" dans la colonne pivot */ + Ligne = LIndiceColonne[ic]; + + if ( UtiliserLesSuperLignes == OUI_LU ) { + /* Si la Ligne est dans une SuperLigne on ne fait rien */ + if ( NombreDePassagesDansSuperLignes > 0 ) { + if ( SuperLigneDeLaLigne[Ligne] != NULL ) { + if ( SuperLigneDeLaLigne[Ligne]->ScannerLaSuperLigne == NON_LU ) { + SuperLigneAScanner[NombreDeSuperLignesAScanner] = SuperLigneDeLaLigne[Ligne]; + NombreDeSuperLignesAScanner++; + SuperLigneDeLaLigne[Ligne]->ScannerLaSuperLigne = OUI_LU; + } + continue; + } + } + } + + LU_DeClasserUneLigne( Matrice , Ligne , LNbTerm[Ligne] ); + + if ( UtiliserLesSuperLignes == OUI_LU ) { + TypeDeClassementHashCodeAFaire[Ligne] = ELEMENT_HASCODE_A_RECLASSER; + } + + ValTermeColonnePivot = Elm[ic] * UnSurValeurDuPivot; + ElmDeL [ilL] = ValTermeColonnePivot; + IndiceLigneDeL[ilL] = Ligne; + ilL++; + + /* La suppression du terme de la colonne pivot dans Ligne est fait dans ScanLigneCasSymetrique */ + LU_ScanLigneCasSymetrique( Matrice , Ligne, ilDebLignePivot, NbNonuLignePivot, ValTermeColonnePivot, + LignePivot, &StockageLignesRedimensionne ); + if ( StockageLignesRedimensionne == OUI_LU ) { + LIndiceColonne = Matrice->LIndiceColonne; + Elm = Matrice->Elm; + ilDebLignePivot = Ldeb[LignePivot]; + ic = ilDebLignePivot + i; + StockageLignesRedimensionne = NON_LU; + } + + MajValeurPivotDiagonal = OUI_LU; + + /* Dans le cas symetrique le terme diagonal est forcement modifie. Balayer la ligne plutot que de gerer cela dans + "ScanLigne" et dans une eventuelle extension du stockage de la matrice n'est pas penalisant. */ + if ( MajValeurPivotDiagonal == OUI_LU ) { + /* Car on a supprime dans Ligne, le terme d'indice colonne LignePivot */ + Matrice->NombreDeTermes--; + /* */ + /* Le terme diagonal est toujours range en premier */ + /* Si le terme diagonal est trop petit on ne reclasse pas la ligne */ + X = fabs( Elm[Ldeb[Ligne]] ); + if ( X > PivotMin || Contexte == LU_POINT_INTERIEUR ) { + AbsDuPlusGrandTermeDeLaLigne[Ligne] = -1; /* Il a pu etre modifie */ + /* Pas besoin de mettre une valeur negative si < PivotMin car pas classe et donc ne sera pas + rencontre dans selection du pivot diagonal */ + AbsValeurDuTermeDiagonal[Ligne] = X; + LU_ClasserUneLigne( Matrice, Ligne, LNbTerm[Ligne] ); + } + } +} + +if ( UtiliserLesSuperLignes == OUI_LU ) { + + for ( j = 0 ; j < NombreDeSuperLignesAScanner ; j++ ) { + SuperLigne = SuperLigneAScanner[j]; + + ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; + NumerosDesLignesDeLaSuperLigne = SuperLigne->NumerosDesLignesDeLaSuperLigne; + NombreDeTermesDeLaSuperLigne = SuperLigne->NombreDeTermes; + IndiceColonne = SuperLigne->IndiceColonne; + + for ( il = 0 ; il < NombreDeTermesDeLaSuperLigne ; il++ ) { + if ( IndiceColonne[il] == ColonnePivot ) { + icDebColonnePivot = SuperLigne->CapaciteDesColonnes * il; + break; + } + } + + /* Modification des termes de la colonne pivot et stockage dans le triangle L */ + ic = icDebColonnePivot; + ValeurDesTermesDeColonnePivot = &(ElmDeL[ilL]); + for ( k = 0 ; k < SuperLigne->NombreDeLignesDeLaSuperLigne; k++ , ic++ ) { + ElmDeL [ilL] = ElmColonneDeSuperLigne[ic] * UnSurValeurDuPivot; + IndiceLigneDeL[ilL] = NumerosDesLignesDeLaSuperLigne[k]; + ilL++; + /* Il faut dechainer la ligne du chainage fonction du nombre de termes car son nombre de termes peut changer */ + LU_DeClasserUneLigne( Matrice , NumerosDesLignesDeLaSuperLigne[k] , NombreDeTermesDeLaSuperLigne ); + } + + /* Suppression dans SuperLigne des termes de la colonne pivot */ + LU_SupprimerUnTermeDansUneSuperLigne( Matrice , SuperLigne ,icDebColonnePivot , il ); + /* Car on a supprime dans Ligne, le terme d'indice colonne LignePivot */ + Matrice->NombreDeTermes-= SuperLigne->NombreDeLignesDeLaSuperLigne; + + NombreDeTermesDeLaSuperLigne--; + + /* Scan de la SuperLigne */ + /* On a deja scanne la super ligne de la ligne pivot */ + if ( SuperLigne != SuperLigneDeLaLignePivot || 1 ) { + LU_ScanSuperLigneCasSymetrique( Matrice, SuperLigne, ilDebLignePivot, NbNonuLignePivot, ValeurDesTermesDeColonnePivot, + &Matrice->HashCodeSuperLigne[SuperLigne->NumeroDeLaSuperLigne] ); + /* Au cas ou il y aurait eu un redimensionnement */ + ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; + NumerosDesLignesDeLaSuperLigne = SuperLigne->NumerosDesLignesDeLaSuperLigne; /* Normalement ca change pas */ + NombreDeTermesDeLaSuperLigne = SuperLigne->NombreDeTermes; + IndiceColonne = SuperLigne->IndiceColonne; + } + + Element = SuperLigne->NumeroDeLaSuperLigne + Matrice->Rang; + if ( TypeDeClassementHashCodeAFaire[Element] != ELEMENT_HASCODE_A_CLASSER ) { + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_A_RECLASSER; + } + + T[ColonnePivot] = 0; + SuperLigne->ScannerLaSuperLigne = NON_LU; + + CapaciteDesColonnes = SuperLigne->CapaciteDesColonnes; + for ( k = 0 ; k < SuperLigne->NombreDeLignesDeLaSuperLigne; k++ , ic++ ) { + il = SuperLigne->IndexDuTermeDiagonal[k]; + X = fabs( ElmColonneDeSuperLigne[ (il * CapaciteDesColonnes) + k ] ); + if ( X > PivotMin || Contexte == LU_POINT_INTERIEUR ) { + Ligne = NumerosDesLignesDeLaSuperLigne[k]; + /* Pas besoin de mettre une valeur negative si < PivotMin car pas classe et donc ne sera pas + rencontre dans selection du pivot diagonal */ + AbsDuPlusGrandTermeDeLaLigne[Ligne] = -1.0; + AbsValeurDuTermeDiagonal[Ligne] = X; + LU_ClasserUneLigne( Matrice , Ligne , NombreDeTermesDeLaSuperLigne ); + } + } + } +} + +Matrice->IndexLibreDeL = ilL; + +ilDebLignePivot = Ldeb[LignePivot]; +LIndiceColonne = Matrice->LIndiceColonne; + +/* Dans le cas du pivotage diagonal, le terme diagonal est toujours range en premier */ +for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + /* On remet W et Marqueur a 0 */ + W[Colonne] = 0.; + T[Colonne] = 0; +} + +if ( UtiliserLesSuperLignes == OUI_LU ) SuperLigneDeLaLigne[LignePivot] = NULL; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* La matrice est symetrique pleine et tout est dans une seule super ligne */ + +void LU_EliminationDUneLigneMatricePleineCasSymetrique( MATRICE * Matrice , int LignePivot , int ColonnePivot ) +{ +int il; int ic; int ilL; double X; int ilDebLignePivot; int ilColonnePivot; int ilElm; +int * IndiceColonne; double UnSurValeurDuPivot; int NbTermesLignePivot; int Ligne; int NbTermesColonnePivot; +double * ElmDeL; int * IndiceLigneDeL; int CapaciteDesColonnes; int i; int NombreDeLignesDeLaSuperLigne; +int NumeroDeColonne; char Contexte; int icDebColonnePivot; double * ElmColonneDeSuperLigne; +int * NumerosDesLignesDeLaSuperLigne; int NombreDeTermesDeLaSuperLigne; +double * ValeurDesTermesDeColonnePivot; int k; int NombreDeLignesRestantes; +SUPER_LIGNE_DE_LA_MATRICE * SuperLigneDeLaLignePivot; double PivotMin; +int * Ldeb; int * LNbTerm; int * LIndiceColonne; double * Elm; + +/*printf("Matrice->Kp = %d LignePivot %d \n", Matrice->Kp, LignePivot);*/ + +Contexte = Matrice->ContexteDeLaFactorisation; +PivotMin = Matrice->PivotMin; + +SuperLigneDeLaLignePivot = Matrice->SuperLigneDeLaLigne[LignePivot]; + +Matrice->NombreDeTermes-= SuperLigneDeLaLignePivot->NombreDeTermes; +NombreDeLignesRestantes = SuperLigneDeLaLignePivot->NombreDeLignesDeLaSuperLigne - 1; +Matrice->NombreDeTermes-= NombreDeLignesRestantes; + +/* Recopie de la ligne pivot vers un tableau compact */ +LU_RecopierUneLigneDeSuperLigneDansLigne( Matrice, SuperLigneDeLaLignePivot, LignePivot ); +/* Suppression de la LignePivot dans la SuperLigne */ +LU_SupprimerUneLigneDansUneSuperLigne( Matrice , SuperLigneDeLaLignePivot , LignePivot , ColonnePivot ); + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +ilDebLignePivot = Ldeb[LignePivot]; +NbTermesLignePivot = LNbTerm[LignePivot]; +NbTermesColonnePivot = NbTermesLignePivot; + +Matrice->IndexLibreDeU += NbTermesLignePivot; /* Servira a allouer le triangle U */ + +/* On repere le terme diagonal mais on ne le place pas tout de suite en premiere position */ +for ( il = ilDebLignePivot ; LIndiceColonne[il] != ColonnePivot ; il++ ); +ilColonnePivot = il; +UnSurValeurDuPivot = 1. / Elm[ilColonnePivot]; +NumeroDeColonne = ilColonnePivot - ilDebLignePivot; + +ElmDeL = Matrice->ElmDeL; +IndiceLigneDeL = Matrice->IndiceLigneDeL; + +/* Recopies dans les triangles */ +/* Triangle L */ +/* Le terme diagonal vaut 1 et est stocke pour beneficier de l'indice ligne */ +if ( Matrice->IndexLibreDeL + NbTermesColonnePivot > Matrice->DernierIndexLibreDeL ) { + LU_AugmenterLaTailleDuTriangleL( Matrice , NbTermesColonnePivot ); + ElmDeL = Matrice->ElmDeL; + IndiceLigneDeL = Matrice->IndiceLigneDeL; +} + +Matrice->NbTermesParColonneDeL[Matrice->Kp] = NbTermesColonnePivot; + +ilL = Matrice->IndexLibreDeL; +Matrice->CdebParColonneDeL[Matrice->Kp] = ilL; + +/* Initialisaton de ElmDeL */ +Matrice->ElmDeL[ilL] = 1.; +Matrice->IndiceLigneDeL[ilL] = LignePivot; +ilL++; + +/* Il faut dechainer la ligne pivot du chainage fonction du nombre de termes (la colonne pivot a ete dechainee + ci-dessus dans la foulee) */ +LU_DeClasserUneLigne( Matrice , LignePivot , NbTermesLignePivot ); + +if ( NombreDeLignesRestantes <= 0 ) { + Matrice->IndexLibreDeL = ilL; + goto FinScanSuperLigne; +} + +ElmColonneDeSuperLigne = SuperLigneDeLaLignePivot->ElmColonneDeSuperLigne; +NumerosDesLignesDeLaSuperLigne = SuperLigneDeLaLignePivot->NumerosDesLignesDeLaSuperLigne; +NombreDeTermesDeLaSuperLigne = SuperLigneDeLaLignePivot->NombreDeTermes; +IndiceColonne = SuperLigneDeLaLignePivot->IndiceColonne; +CapaciteDesColonnes = SuperLigneDeLaLignePivot->CapaciteDesColonnes; +NombreDeLignesDeLaSuperLigne = SuperLigneDeLaLignePivot->NombreDeLignesDeLaSuperLigne; + +icDebColonnePivot = CapaciteDesColonnes * NumeroDeColonne; + +/* On scanne la super ligne. Il n'y a pas de creation de terme et il n'y a pas a s'occuper du hashcode */ +ValeurDesTermesDeColonnePivot = &(ElmColonneDeSuperLigne[icDebColonnePivot]); + +ilElm = ilDebLignePivot; +for ( il = 0 ; il < NbTermesLignePivot ; il++ , ilElm++ ) { + + if ( il == NumeroDeColonne ) continue; + + X = Elm[ilElm] * UnSurValeurDuPivot; + + ElmDeL [ilL] = X; + IndiceLigneDeL[ilL] = LIndiceColonne[ilElm]; + ilL++; + + /* Calcul du terme modifie: on balaye la colonne de la SuperLigne */ + ic = CapaciteDesColonnes * il; + for ( i = 0 ; i < NombreDeLignesDeLaSuperLigne ; i++ , ic++ ) { + ElmColonneDeSuperLigne[ic]-= X * ValeurDesTermesDeColonnePivot[i]; + } +} + +Matrice->IndexLibreDeL = ilL; + +/* Dans ce cas, ce n'est qu'apres que l'on enleve le terme de la colonne pivot */ +/* Suppression dans SuperLigne des termes de la colonne pivot */ +LU_SupprimerUnTermeDansUneSuperLigne( Matrice , SuperLigneDeLaLignePivot , icDebColonnePivot , NumeroDeColonne ); +NombreDeTermesDeLaSuperLigne--; + +goto UtilisationIndexDuTermeDiagonalMatricePleine; + +for ( k = 0 ; k < NombreDeLignesDeLaSuperLigne; k++ , ic++ ) { + Ligne = NumerosDesLignesDeLaSuperLigne[k]; + LU_DeClasserUneLigne( Matrice , Ligne , NbTermesLignePivot ); + for ( il = 0 ; il < NombreDeTermesDeLaSuperLigne ; il++ ) { + if ( IndiceColonne[il] == Ligne) { + X = fabs( ElmColonneDeSuperLigne[ (il * CapaciteDesColonnes) + k ] ); + /* Si le terme diagonal est trop petit on ne reclasse pas la ligne */ + if ( X > PivotMin || Contexte == LU_POINT_INTERIEUR ) { + Matrice->AbsDuPlusGrandTermeDeLaLigne[Ligne] = -1.0; + Matrice->AbsValeurDuTermeDiagonal[Ligne] = X; + LU_ClasserUneLigne( Matrice , Ligne , NombreDeTermesDeLaSuperLigne ); + } + break; + } + } +} +goto FinScanSuperLigne; + +UtilisationIndexDuTermeDiagonalMatricePleine: +for ( k = 0 ; k < NombreDeLignesDeLaSuperLigne; k++ , ic++ ) { + Ligne = NumerosDesLignesDeLaSuperLigne[k]; + LU_DeClasserUneLigne( Matrice , Ligne , NbTermesLignePivot ); + il = SuperLigneDeLaLignePivot->IndexDuTermeDiagonal[k]; + X = fabs( ElmColonneDeSuperLigne[ (il * CapaciteDesColonnes) + k ] ); + if ( X > PivotMin || Contexte == LU_POINT_INTERIEUR ) { + Matrice->AbsDuPlusGrandTermeDeLaLigne[Ligne] = -1.0; + Matrice->AbsValeurDuTermeDiagonal[Ligne] = X; + LU_ClasserUneLigne( Matrice , Ligne , NombreDeTermesDeLaSuperLigne ); + } +} + +FinScanSuperLigne: + +/* La ligne etait dans une super ligne il faut remettre le terme diagonal en premier car il a pu changer de place */ + +if ( ilColonnePivot == ilDebLignePivot ) { + Elm[ilDebLignePivot] = UnSurValeurDuPivot; +} +else { + LIndiceColonne[ilColonnePivot] = LIndiceColonne[ilDebLignePivot]; + LIndiceColonne[ilDebLignePivot] = ColonnePivot; + X = Elm[ilDebLignePivot]; + /* On inverse le terme pivot */ + Elm[ilDebLignePivot] = UnSurValeurDuPivot; + Elm[ilColonnePivot] = X; +} + +if ( Matrice->UtiliserLesSuperLignes == OUI_LU ) Matrice->SuperLigneDeLaLigne[LignePivot] = NULL; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne_matrice_pleine.c b/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne_matrice_pleine.c new file mode 100644 index 0000000000..97f732f36d --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne_matrice_pleine.c @@ -0,0 +1,242 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU de la base. + Elimination d'une ligne, cas d'une matrice pleine. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_EliminationDUneLigneMatricePleine( MATRICE * Matrice , int LignePivot , int ColonnePivot ) +{ + +# ifndef ON_COMPILE +/* Pour eviter les warning de compil */ +MATRICE * Mat; int Ligne; int Colonne; +Mat = Matrice; +Ligne = LignePivot; +Colonne = ColonnePivot; +# endif + +# ifdef ON_COMPILE + +int il; int ic; int ilU; int ilL ; +int * IndiceColonne; int * IndiceLigne ; double UnSurValeurDuPivot; +double ValTermeColonnePivot; int Ligne; int Colonne; int itC; +int NbTermesLignePivot; int NbTermesColonnePivot; double * Elm; + +int * Ldeb; int * LNbTerm; int * LDernierPossible; int * LIndiceColonne; double * Elm; +int * Cdeb; int * CNbTerm; int * CDernierPossible; int * CIndiceLigne; int * CNbTermMatriceActive; + +printf("Attention LU_EliminationDUneLigneMatricePleine ne met pas a jour AbsDuPlusGrandTermeDeLaLigne \n"); + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LDernierPossible = Matrice->LDernierPossible; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +Cdeb = Matrice->Cdeb; +CNbTerm = Matrice->CNbTerm; +CNbTermMatriceActive = Matrice->CNbTermMatriceActive; +CDernierPossible = Matrice->CDernierPossible; +CIndiceLigne = Matrice->CIndiceLigne; + +ilDebLignePivot = Ldeb[LignePivot]; +NbTermesLignePivot = LNbTerm[LignePivot]; + +icDebColonnePivot = Cdeb[ColonnePivot]; +NbTermesColonnePivot = CNbTerm[ColonnePivot]; /* Pour la colonne pivot c'est egal a CNbTermMatriceActive */ + +/* Transfert de la ligne dans un tableau de travail */ +for ( il = ilDebLignePivot ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) Matrice->W[IndiceColonne[il]] = Elm[il]; + +UnSurValeurDuPivot = 1. / Matrice->W[ColonnePivot]; +Matrice->W[ColonnePivot] = 0.0; + +/* Maintenant on balaye toutes les lignes de la matrice active qui ont un terme non nul dans la colonne + pivot et on les compare a la ligne pivot */ + +itC = 0; +for ( ic = icDebColonnePivot ; ic < icDebColonnePivot + NbTermesColonnePivot ; ic++ ) { + Ligne = CIndiceLigne[ic]; + if ( Ligne != LignePivot ) { + /* Recherche de la valeur du terme de la ligne IndiceLigne qui se trouve dans la colonne pivot */ + for ( il = Ldeb[Ligne] ; LIndiceColonne[il] != ColonnePivot ; il++ ); + ValTermeColonnePivot = Elm[il] * UnSurValeurDuPivot; + + Matrice->ValeurDesTermesDeLaColonnePivot[itC] = ValTermeColonnePivot; + Matrice->LigneDesTermesDeLaColonnePivot [itC] = Ligne; + itC++; + + /* Il faut enlever du stockage par ligne, le terme de la ColonnePivot d'indice ligne "IndiceLigne" */ + ptLigne->NombreDeTermes--; + Elm [il] = Elm[ptLigne->NombreDeTermes]; + IndiceColonne[il] = IndiceColonne[ptLigne->NombreDeTermes]; + if ( ValTermeColonnePivot != 0.0 ) { + LU_ScanLigneMatricePleine ( Matrice, Ligne, ColonnePivot, ValTermeColonnePivot ); + } + + } +} + +/* Transfert de la ligne pivot dans la triangulaire superieure U */ +if ( Matrice->IndexLibreDeU + NbTermesLignePivot > Matrice->DernierIndexLibreDeU ) { + LU_AugmenterLaTailleDuTriangleU( Matrice , NbTermesLignePivot ); +} + +ilU = Matrice->IndexLibreDeU; +Matrice->LdebParLigneDeU[Matrice->Kp] = ilU; + +/* Le terme diagonal est egal au pivot et est range en premier */ +Matrice->ElmDeU[ilU] = UnSurValeurDuPivot; +Matrice->IndiceColonneDeU[ilU] = ColonnePivot; +ilU++; + +Matrice->NbTermesParLigneDeU[Matrice->Kp] = NbTermesLignePivot; + +IndiceColonne = ptLignePivot->IndiceColonne; +Elm = ptLignePivot->Elm; +for ( il = 0 ; il < NbTermesLignePivot ; il++ ) { + Colonne = IndiceColonne[il]; + /* Inutile de remettre W a 0 car matrice pleine */ + if ( Colonne != ColonnePivot ) { + Matrice->ElmDeU[ilU] = Elm[il]; + Matrice->IndiceColonneDeU[ilU] = Colonne; + ilU++; + /* Mise a jour de la colonne la matrice active: on dechaine le terme de la + ligne pivot */ + /* Suppression du terme d'indice ligne "LignePivot" dans la colonne "IndiceColonne" */ + + printf("Attention EliminationDUneLigneMatricePleine est obsolete\n"); + printf("a cause du changement des structures decrivant la matrice active\n"); + printf("et a cause de l'introduction de Matrice->CNbTermMatriceActive\n"); + + ptColonne = Matrice->ColonneDeLaMatrice[Colonne]; + IndiceLigne = ptColonne->IndiceLigne; + for ( ic = 0 ; IndiceLigne[ic] != LignePivot ; ic++ ); + ptColonne->NombreDeTermes--; + IndiceLigne[ic] = IndiceLigne[ptColonne->NombreDeTermes]; + + + } +} +Matrice->IndexLibreDeU = ilU; + +/* Transfert de la colonne pivot dans la triangulaire inferieure L */ +/* Le terme diagonal vaut 1 et est stocke pour beneficier de l'indice ligne */ +if ( Matrice->IndexLibreDeL + NbTermesColonnePivot > Matrice->DernierIndexLibreDeL ) { + LU_AugmenterLaTailleDuTriangleL( Matrice , NbTermesColonnePivot ); +} + +Matrice->NbTermesParColonneDeL[Matrice->Kp] = NbTermesColonnePivot; + +ilL = Matrice->IndexLibreDeL; +Matrice->CdebParColonneDeL[Matrice->Kp] = ilL; + +/* Initialisaton de ElmDeL */ +Matrice->ElmDeL[ilL] = 1.; +Matrice->IndiceLigneDeL[ilL] = LignePivot; +ilL++; + +for ( ic = 0 ; ic < itC ; ic++ ){ + Matrice->ElmDeL [ilL] = Matrice->ValeurDesTermesDeLaColonnePivot[ic]; + Matrice->IndiceLigneDeL[ilL] = Matrice->LigneDesTermesDeLaColonnePivot[ic]; + /* Remarque: a ce stade IndiceLigne ne peut pas etre egal a LignePivot */ + ilL++; +} + +Matrice->IndexLibreDeL = ilL; + +# endif + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne_turbo.c b/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne_turbo.c new file mode 100644 index 0000000000..bbc6947558 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_elimination_une_ligne_turbo.c @@ -0,0 +1,289 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Elimination de la ligne pivot version turbo. + Attention il y a des conditions: + 1- La matrice doit etre symetrique en topologie + 2- Il faut faire du pivotage diagonal + Ce sous programme ne prend pas en charge les super lignes. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_EliminationDUneLigneVersionTurbo( MATRICE * Matrice , int LignePivot , int ColonnePivot ) +{ +int il; int ill; int illDeb; double X; int NbNonuLignePivot; int Demande; double UnSurValeurDuPivot; +int NbTermesLignePivot; int NbTermesColonnePivot; int NbTermesLigne; int Ligne; int Colonne; +int ilDebLignePivot; char * T; double * W; double ValTermeColonnePivot; int f; int i; double PivotMin; +double * AbsValeurDuTermeDiagonal; double * AbsDuPlusGrandTermeDeLaLigne; int illLigne; +int * Ldeb; int * LNbTerm; int * LDernierPossible; int * LIndiceColonne; double * Elm; +int * IndiceLigneDeL; double * ElmDeL; int ilL; + +/*printf("Kp %d Rang %d LignePivot %d\n",Matrice->Kp,Matrice->Rang,LignePivot);*/ + +PivotMin = Matrice->PivotMin; +AbsValeurDuTermeDiagonal = Matrice->AbsValeurDuTermeDiagonal; +AbsDuPlusGrandTermeDeLaLigne = Matrice->AbsDuPlusGrandTermeDeLaLigne; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LDernierPossible = Matrice->LDernierPossible; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +ilDebLignePivot = Ldeb[LignePivot]; +NbTermesLignePivot = LNbTerm[LignePivot]; + +NbTermesColonnePivot = NbTermesLignePivot; + +Matrice->IndexLibreDeU += NbTermesLignePivot; /* Servira a allouer le triangle U */ + +Matrice->NombreDeTermes -= NbTermesLignePivot + (NbTermesLignePivot-1); + +/* printf("Matrice->Kp = %d LignePivot %d NbTermesLignePivot %d\n",Matrice->Kp,LignePivot,NbTermesLignePivot); */ + +W = Matrice->W; +T = Matrice->Marqueur; + +/* Transfert de la ligne dans un tableau de travail */ +/* Le terme diagonal est range en premier */ +UnSurValeurDuPivot = 1. / Elm[ilDebLignePivot]; + +/* On inverse tout de suite le terme pivot */ +Elm[ilDebLignePivot] = UnSurValeurDuPivot; + +for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + W[LIndiceColonne[il]] = Elm[il]; + T[LIndiceColonne[il]] = 1; +} + +/* Il faut dechainer la ligne pivot du chainage fonction du nombre de termes (la colonne pivot a ete dechainee ci-dessus + dans la foulee) */ +LU_DeClasserUneLigne( Matrice , LignePivot , NbTermesLignePivot ); + +NbNonuLignePivot = NbTermesLignePivot - 1; + +ElmDeL = Matrice->ElmDeL; +IndiceLigneDeL = Matrice->IndiceLigneDeL; +/* Transfert de la colonne pivot dans la triangulaire inferieure L et modification de la matrice active */ +/* Le terme diagonal vaut 1 et est stocke pour beneficier de l'indice ligne */ +if ( Matrice->IndexLibreDeL + NbTermesColonnePivot > Matrice->DernierIndexLibreDeL ) { + LU_AugmenterLaTailleDuTriangleL( Matrice , NbTermesColonnePivot ); + ElmDeL = Matrice->ElmDeL; + IndiceLigneDeL = Matrice->IndiceLigneDeL; +} + +Matrice->NbTermesParColonneDeL[Matrice->Kp] = NbTermesColonnePivot; + +ilL = Matrice->IndexLibreDeL; +Matrice->CdebParColonneDeL[Matrice->Kp] = ilL; + +/* Initialisaton de ElmDeL */ +ElmDeL [ilL] = 1.; +IndiceLigneDeL[ilL] = LignePivot; +ilL++; + +il = ilDebLignePivot + 1; +for ( i = 1 ; i < NbTermesLignePivot ; i++ , il++ ) { + /* Le terme diagonal est toujours range en premier */ + /* En fait, il y a aussi un terme d'indice ligne egal a cette "Colonne" dans la colonne pivot */ + Ligne = LIndiceColonne[il]; + /* Recherche de la valeur du terme de la ligne Ligne qui se trouve dans la colonne pivot */ + illDeb = Ldeb[Ligne]; + for ( ill = illDeb ; LIndiceColonne[ill] != ColonnePivot ; ill++ ); + ValTermeColonnePivot = Elm[ill] * UnSurValeurDuPivot; + /* Triangle L */ + ElmDeL [ilL] = ValTermeColonnePivot; + IndiceLigneDeL[ilL] = Ligne; + ilL++; + /* */ + /* Il faut dechainer la ligne du chainage fonction du nombre de termes car son nombre de termes peut changer */ + NbTermesLigne = LNbTerm[Ligne]; + LU_DeClasserUneLigne( Matrice , Ligne , NbTermesLigne ); + /* Suppression du terme dans le chainage par ligne */ + NbTermesLigne--; + LNbTerm[Ligne] = NbTermesLigne; + Elm [ill] = Elm[illDeb + NbTermesLigne]; + LIndiceColonne[ill] = LIndiceColonne[illDeb + NbTermesLigne]; + /* Scan de la ligne */ + /* Attention il faut faire le scan ligne meme si ValTermeColonnePivot est egal a 0, car en cas de pivotage + diagonal sur matrice symetrique en topologie on perd la symetrie si on ne le fait pas */ + /* Et egalement pour ne pas perdre de termes dans les refactorisations (hades) */ + if ( NbNonuLignePivot <= 0 ) goto FinDuScan; + + /* f sert a mesurer le "fill-in" */ + f = NbNonuLignePivot; + /* Transformation des termes de la ligne scannee */ + for ( ill = illDeb ; ill < illDeb + NbTermesLigne ; ill++ ) { + Colonne = LIndiceColonne[ill]; + if ( T[Colonne] == 1 ) { + T[Colonne] = 0; + Elm[ill]-= W[Colonne] * ValTermeColonnePivot; + f--; + if ( f == 0 ) break; + } + } + if ( f > 0 ) { + Matrice->CompteurExclusionMarkowitz+= f; + Matrice->NombreDeTermes+= f; + Matrice->NbFillIn+= f; + /* Il y a un "fill-in" de f termes => on scanne la ligne pivot pour pouvoir calculer et + stocker les termes crees . Les termes crees sont chaines en fin de ligne */ + if ( illDeb + NbTermesLigne + f - 1 > LDernierPossible[Ligne] ) { + Demande = NbTermesLigne + f; + LU_AugmenterLaTailleDeLaMatriceActive( Matrice , Ligne , Demande ); + LIndiceColonne = Matrice->LIndiceColonne; + Elm = Matrice->Elm; + ilDebLignePivot = Ldeb[LignePivot]; + il = ilDebLignePivot + i; + illDeb = Ldeb[Ligne]; + } + + illLigne = illDeb + NbTermesLigne; + + /* On commence a 1 car terme diagonal range en premier */ + for ( ill = ilDebLignePivot + 1 ; ill < ilDebLignePivot + NbTermesLignePivot ; ill++ ) { + Colonne = LIndiceColonne[ill]; + if ( T[Colonne] == 1 ) { + LIndiceColonne[illLigne] = Colonne; + Elm [illLigne] = -W[Colonne] * ValTermeColonnePivot; + illLigne++; + NbTermesLigne++; + f--; + if ( f == 0 ) { ill++; break;} + } + else T[Colonne] = 1; + } + while ( ill < ilDebLignePivot + NbTermesLignePivot ) { + T[LIndiceColonne[ill]] = 1; + ill++; + } + /* Mise a jour du nombre de termes de la ligne scannee */ + LNbTerm[Ligne] = NbTermesLigne; + } + else { + /* Pas de "fill-in" : on remet Matrice.Marqueur aux bonnes valeurs */ + /* Terme diagonal range en premier */ + for ( ill = ilDebLignePivot + 1 ; ill < ilDebLignePivot + NbTermesLignePivot ; ill++ ) { + T[LIndiceColonne[ill]] = 1; + } + } + + FinDuScan: + /* Le terme diagonal est toujours range en premier */ + /* Si le terme diagonal est trop petit on ne reclasse pas la ligne */ + X = fabs( Elm[illDeb] ); + if ( X > PivotMin ) { + AbsDuPlusGrandTermeDeLaLigne[Ligne] = -1.0; + /* Pas besoin de mettre une valeur negative si < PivotMin car n'est pas classe et ne sera pas + rencontre dans slection du pivot diagonal */ + AbsValeurDuTermeDiagonal[Ligne] = X; + LU_ClasserUneLigne( Matrice , Ligne , NbTermesLigne ); + } +} + +Matrice->IndexLibreDeL = ilL; + +/* Dans le cas du pivotage diagonal, le terme diagonal est toujours range en premier */ +for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + W[LIndiceColonne[il]] = 0.; + T[LIndiceColonne[il]] = 0; +} + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_factorisation.c b/src/ext/Sirius_Solver/simplexe/lu/lu_factorisation.c new file mode 100644 index 0000000000..7b6191c01b --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_factorisation.c @@ -0,0 +1,214 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Factorisation LU. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_constantes_externes.h" +# include "lu_definition_arguments.h" +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ + +MATRICE * LU_Factorisation( MATRICE_A_FACTORISER * Mat ) +{ +int FaireScalingDeLaMatrice; MATRICE * Matrice; void * Tas ; +double SeuilDePivotage ; int NombreDeChangementsDeSeuilDePivotage; + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + Tas = MEM_Init(); + Matrice = (MATRICE *) MEM_Malloc ( Tas, sizeof( MATRICE ) ); + if ( Matrice == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet MATRICE\n"); + Mat->ProblemeDeFactorisation = SATURATION_MEMOIRE; + return( NULL ); + } + Matrice->Tas = Tas; +# else + Matrice = (MATRICE *) malloc ( sizeof( MATRICE ) ); + if ( Matrice == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet MATRICE\n"); + Mat->ProblemeDeFactorisation = SATURATION_MEMOIRE; + return( NULL ); + } + Matrice->Tas = NULL; +# endif + +LU_InitTableauxANull( Matrice ); + +Matrice->MatriceEntree = Mat; + +Matrice->AnomalieDetectee = NON_LU; +Matrice->NombreDeChangementsDeSeuilDePivotage = 0; + +if ( (Matrice->MatriceEntree)->SeuilPivotMarkowitzParDefaut == OUI_LU ) Matrice->SeuilDePivotage = PREMIER_SEUIL_DE_PIVOTAGE; +else Matrice->SeuilDePivotage = (Matrice->MatriceEntree)->ValeurDuPivotMarkowitz; + +/* Precaution pour les etourdis */ +if ( Matrice->SeuilDePivotage > 1.0 ) Matrice->SeuilDePivotage = 1.0; +else if ( Matrice->SeuilDePivotage == 0.0 ) Matrice->SeuilDePivotage = PREMIER_SEUIL_DE_PIVOTAGE; + +FaireScalingDeLaMatrice = (Matrice->MatriceEntree)->FaireScalingDeLaMatrice; +if ( FaireScalingDeLaMatrice != OUI_LU && FaireScalingDeLaMatrice != NON_LU ) { + printf("Vous avez mal initialise l'indicateur FaireScalingDeLaMatrice. Vous devez choisir entre OUI_LU et NON_LU\n"); + (Matrice->MatriceEntree)->ProblemeDeFactorisation = OUI_LU; + return( Matrice ); +} + +Factorisation: +setjmp( Matrice->Env ); +if ( Matrice->AnomalieDetectee != NON_LU ) { + + #if VERBOSE_LU + printf(" Probleme dans la factorisation LU\n");fflush(stdout); + #endif + + /*LU_LibererLesTableauxTemporaires( Matrice );*/ /* Fait ci-dessous */ + + if ( Matrice->AnomalieDetectee == MATRICE_SINGULIERE ) { + + LU_LibererLesTableauxTemporaires( Matrice ); + + if ( Matrice->NombreDeChangementsDeSeuilDePivotage < Matrice->NombreMaxDeChangementsDeSeuilDePivotage ) { + if ( Matrice->SeuilDePivotage + INCREMENT_DE_SEUIL_DE_PIVOTAGE < 1.0 ) { + + #if VERBOSE_LU + printf(" modification de SeuilDePivotage avant %lf apres %lf\n", + Matrice->SeuilDePivotage,Matrice->SeuilDePivotage+INCREMENT_DE_SEUIL_DE_PIVOTAGE ); + fflush(stdout); + #endif + + SeuilDePivotage = Matrice->SeuilDePivotage; + NombreDeChangementsDeSeuilDePivotage = Matrice->NombreDeChangementsDeSeuilDePivotage; + + Mat = Matrice->MatriceEntree; + + LU_LibererMemoireLU( Matrice ); + + # ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + Tas = MEM_Init(); + Matrice = (MATRICE *) MEM_Malloc ( Tas, sizeof( MATRICE ) ); + if ( Matrice == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet MATRICE\n"); + Mat->ProblemeDeFactorisation = SATURATION_MEMOIRE; + return( NULL ); + } + Matrice->Tas = Tas; + # else + Matrice = (MATRICE *) malloc ( sizeof( MATRICE ) ); + if ( Matrice == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet MATRICE\n"); + Mat->ProblemeDeFactorisation = SATURATION_MEMOIRE; + return( NULL ); + } + Matrice->Tas = NULL; + # endif + + LU_InitTableauxANull( Matrice ); + + Matrice->MatriceEntree = Mat; + + Matrice->AnomalieDetectee = NON_LU; + Matrice->NombreDeChangementsDeSeuilDePivotage = 0; + + Matrice->SeuilDePivotage = SeuilDePivotage + INCREMENT_DE_SEUIL_DE_PIVOTAGE; + Matrice->NombreDeChangementsDeSeuilDePivotage = NombreDeChangementsDeSeuilDePivotage + 1; + + goto Factorisation; + } + } + + } + + (Matrice->MatriceEntree)->ProblemeDeFactorisation = Matrice->AnomalieDetectee; + #if VERBOSE_LU + printf(" Matrice non inversible malgre les changements de seuils\n");fflush(stdout); + #endif + + return( Matrice ); +} +else { + LU_FactorisationCalculs( Matrice , Matrice->MatriceEntree ); +} + +return( Matrice ); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_factorisation_calculs.c b/src/ext/Sirius_Solver/simplexe/lu/lu_factorisation_calculs.c new file mode 100644 index 0000000000..941f01fde6 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_factorisation_calculs.c @@ -0,0 +1,563 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU de la base. Methode de pivot total. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------------------------------------------*/ +void LU_FactorisationCalculs( MATRICE * Matrice , MATRICE_A_FACTORISER * MatriceEntree ) +{ +/* La matrice d'entree */ +double * ValeurDesTermesDeLaMatrice; int * IndicesDeLigne; int * Ideb; int * NbTermesDesColonnes; int NbColonnes; +int * CodeRetour; +/* */ +int Kp ; int OrdreKp ; int LignePivot; int ColonnePivot; int OrdreLignePivot; int OrdreColonnePivot; +int SeuilDeChangementDePivotMin; int Ki; int Ligne; int Colonne ; char RetourAuDebut ; +int SeuilPourReintegration ; char UtiliserLesSuperLignes ; + +int Rang; int NbT; int * OrdreLigne ; int * OrdreColonne;int * InverseOrdreLigne; + +int * InverseOrdreColonne ; double * AbsValeurDuTermeDiagonal ; +char * LigneRejeteeTemporairementPourPivotage ; double * AbsDuPlusGrandTermeDeLaLigne ; +char * ColonneRejeteeTemporairementPourPivotage; SUPER_LIGNE_DE_LA_MATRICE * SuperLigne; +double X; int k; char ContexteDeLaFactorisation; char WarningMatricePleine; + +int * LNbTerm; int * CNbTermMatriceActive; + +/*----------------------------------------------------------------------------------------------------*/ +ValeurDesTermesDeLaMatrice = MatriceEntree->ValeurDesTermesDeLaMatrice; +IndicesDeLigne = MatriceEntree->IndicesDeLigne; +Ideb = MatriceEntree->IndexDebutDesColonnes; +NbTermesDesColonnes = MatriceEntree->NbTermesDesColonnes; +NbColonnes = MatriceEntree->NombreDeColonnes; +Matrice->FaireScaling = (char)(MatriceEntree->FaireScalingDeLaMatrice); +CodeRetour = &MatriceEntree->ProblemeDeFactorisation; +/*----------------------------------------------------------------------------------------------------*/ +Matrice->ContexteDeLaFactorisation = MatriceEntree->ContexteDeLaFactorisation; +if ( Matrice->ContexteDeLaFactorisation != LU_SIMPLEXE && Matrice->ContexteDeLaFactorisation != LU_POINT_INTERIEUR && + Matrice->ContexteDeLaFactorisation != LU_GENERAL ) { + printf("Attention, il faut preciser le contexte de la factorisation parmi les choix LU_SIMPLEXE/LU_POINT_INTERIEUR/LU_GENERAL\n"); + printf("=> on initialise de contexte a LU_GENERAL\n"); + Matrice->ContexteDeLaFactorisation = LU_GENERAL; +} +/*----------------------------------------------------------------------------------------------------*/ +if ( Matrice->ContexteDeLaFactorisation == LU_SIMPLEXE ) { + Matrice->NombreMaxDeChangementsDeSeuilDePivotage = NOMBRE_MAX_DE_CHANGEMENTS_DE_SEUIL_DE_PIVOTAGE_SIMPLEXE; +} +else { + Matrice->NombreMaxDeChangementsDeSeuilDePivotage = NOMBRE_MAX_DE_CHANGEMENTS_DE_SEUIL_DE_PIVOTAGE_AUTRES_CONTEXTES; + if ( Matrice->ContexteDeLaFactorisation == LU_POINT_INTERIEUR ) { + Matrice->ValeurDeRegularisation = MatriceEntree->ValeurDeRegularisation; + MatriceEntree->OnARegularise = NON_LU; + Matrice->TermeDeRegularisation = MatriceEntree->TermeDeRegularisation; + Matrice->OnARegularise = NON_LU; + } +} +Matrice->OnPeutRegulariser = NON_LU; +/*----------------------------------------------------------------------------------------------------*/ +Matrice->UtiliserLesSuperLignes = MatriceEntree->UtiliserLesSuperLignes; +/* Precaution pour les etourdis */ +if ( Matrice->UtiliserLesSuperLignes != OUI_LU && Matrice->UtiliserLesSuperLignes != NON_LU ) { + Matrice->UtiliserLesSuperLignes = NON_LU; +} +Matrice->LaMatriceEstSymetriqueEnStructure= MatriceEntree->LaMatriceEstSymetriqueEnStructure; +/* Precaution pour les etourdis */ +if ( Matrice->LaMatriceEstSymetriqueEnStructure != OUI_LU && Matrice->LaMatriceEstSymetriqueEnStructure != NON_LU ) { + Matrice->LaMatriceEstSymetriqueEnStructure = NON_LU; +} +/*----------------------------------------------------------------------------------------------------*/ +Matrice->UtiliserLesValeursDePivotNulParDefaut = MatriceEntree->UtiliserLesValeursDePivotNulParDefaut; +if ( Matrice->UtiliserLesValeursDePivotNulParDefaut == OUI_LU ) { + if ( Matrice->ContexteDeLaFactorisation == LU_SIMPLEXE ) { + Matrice->ValeurDuPivotMin = PIVOT_MIN_SIMPLEXE; + Matrice->ValeurDuPivotMinExtreme = PIVOT_MIN_EXTREME_SIMPLEXE; + } + else { + Matrice->ValeurDuPivotMin = PIVOT_MIN_AUTRES_CONTEXTES; + Matrice->ValeurDuPivotMinExtreme = PIVOT_MIN_EXTREME_AUTRES_CONTEXTES; + } +} +else { + Matrice->ValeurDuPivotMin = MatriceEntree->ValeurDuPivotMin; + Matrice->ValeurDuPivotMinExtreme = MatriceEntree->ValeurDuPivotMinExtreme; +} +/*----------------------------------------------------------------------------------------------------*/ +Matrice->FaireDuPivotageDiagonal = MatriceEntree->FaireDuPivotageDiagonal; +Matrice->LaMatriceEstSymetrique = MatriceEntree->LaMatriceEstSymetrique; +if ( Matrice->FaireDuPivotageDiagonal != OUI_LU ) Matrice->LaMatriceEstSymetrique = NON_LU; +/* La symetrie de structure est analyses dans la construction de la matrice. On ne met cet indicateur + a OUI_LU que si: + 1- on demande le pivotage diagonal, + 2- et si la matrice n'est pas symetrique + 3- et si le controle montre tout de meme une symetrie de structure */ + +if ( Matrice->FaireDuPivotageDiagonal != OUI_LU ) Matrice->LaMatriceEstSymetriqueEnStructure = NON_LU; +if ( Matrice->LaMatriceEstSymetrique == OUI_LU ) Matrice->LaMatriceEstSymetriqueEnStructure = NON_LU; + +/* Donc une matrice pour laquelle on ne veut pas de pivotage diagonal sera toujours vue comme + non symetrique ni en valeur ni en structure. + A l'inverse une matrice peut ne peut pas etre symetrique tout en ayant demande le pivotage diagonal */ + +/*----------------------------------------------------------------------------------------------------*/ + +Matrice->NbFillIn = 0; +Matrice->Kp = -1; +Matrice->ExclureLesEchecsMarkowitz = OUI_LU; +Matrice->CompteurExclusionMarkowitz = 0; +/* +printf(" LU_Factorisation ##############\n"); fflush(stdout); +*/ +*CodeRetour = (int) NON_LU; + +if ( NbColonnes == 0 ) return; + +LU_AllouerLU( Matrice, ValeurDesTermesDeLaMatrice, IndicesDeLigne, Ideb, /*Isui*/ NbTermesDesColonnes, &NbColonnes ); +/* Tester le code retour */ + +UtiliserLesSuperLignes = Matrice->UtiliserLesSuperLignes; + +SeuilPourReintegration = (int) (SEUIL_DE_REINTRODUCTION * Matrice->NombreDeTermesDeLaMatriceAFactoriser); + +/* Classement de toutes les lignes et de toutes les colonnes */ +LU_ClasserToutesLesLignesEtToutesLesColonnes( Matrice ); + +if ( UtiliserLesSuperLignes == OUI_LU ) LU_InitPourSuperLignes( Matrice ); + +/* Debut de la factorisation */ +SeuilDeChangementDePivotMin = (int) (0.9 * Matrice->Rang); + +Rang = Matrice->Rang; +OrdreLigne = Matrice->OrdreLigne; +OrdreColonne = Matrice->OrdreColonne; +InverseOrdreLigne = Matrice->InverseOrdreLigne; +InverseOrdreColonne = Matrice->InverseOrdreColonne; +AbsValeurDuTermeDiagonal = Matrice->AbsValeurDuTermeDiagonal; +AbsDuPlusGrandTermeDeLaLigne = Matrice->AbsDuPlusGrandTermeDeLaLigne; +LigneRejeteeTemporairementPourPivotage = Matrice->LigneRejeteeTemporairementPourPivotage; +ColonneRejeteeTemporairementPourPivotage = Matrice->ColonneRejeteeTemporairementPourPivotage; +ContexteDeLaFactorisation = Matrice->ContexteDeLaFactorisation; +WarningMatricePleine = OUI_LU; + +LNbTerm = Matrice->LNbTerm; +CNbTermMatriceActive = Matrice->CNbTermMatriceActive; + +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + + Matrice->Kp = Kp; + + if ( UtiliserLesSuperLignes == OUI_LU ) { + /* Si on utilise la version turbo de l'elimination des lignes, on ne fait rien sur les super lignes */ + if ( Matrice->LaMatriceEstSymetriqueEnStructure != OUI_LU ) { + LU_DeclenchementEventuelRechercheSuperLignes( Matrice ); + } + } + + EtapeDebut: + + if ( Kp > SeuilDeChangementDePivotMin ) { + Matrice->PivotMin = Matrice->ValeurDuPivotMinExtreme; + if ( Matrice->ContexteDeLaFactorisation == LU_POINT_INTERIEUR ) Matrice->OnPeutRegulariser = OUI_LU; + } + + /* A la derniere etape il ne reste plus qu'un terme a inverser => les question de dimensionnement + importent moins et on peut se permettre d'avoir un seuil de pivotage tres proche de 0 */ + if ( Kp == Rang - 1 /*&& ContexteDeLaFactorisation != LU_SIMPLEXE on le fait aussi pour le simplexe*/ ) { + Matrice->PivotMin = PIVOT_MIN_FINAL; + /* Il faut reclasse la derniere ligne au cas ou elle aurait ete declassee */ + Ligne = OrdreLigne[Kp]; + Colonne = OrdreColonne[Kp]; + if ( Matrice->FaireDuPivotageDiagonal == OUI_LU ) { + AbsDuPlusGrandTermeDeLaLigne[Ligne] = -1.; + if ( UtiliserLesSuperLignes == NON_LU ) { + /* Il faut utiliser "Matrice->" a cause des redimensionnements */ + AbsValeurDuTermeDiagonal[Ligne] = fabs( Matrice->Elm[Matrice->Ldeb[Ligne]] ); + } + else { + SuperLigne = Matrice->SuperLigneDeLaLigne[Ligne]; + if ( SuperLigne != NULL ) { + for ( k = 0 ; k < SuperLigne->NombreDeLignesDeLaSuperLigne; k++ ) { + if ( SuperLigne->NumerosDesLignesDeLaSuperLigne[k] != Ligne ) continue; + X = fabs( SuperLigne->ElmColonneDeSuperLigne[ ( SuperLigne->IndexDuTermeDiagonal[k] * + SuperLigne->CapaciteDesColonnes) + k ] ); + AbsValeurDuTermeDiagonal[Ligne] = X; + break; + } + } + else { + /* Il faut utiliser "Matrice->" a cause des redimensionnements */ + AbsValeurDuTermeDiagonal[Ligne] = fabs( Matrice->Elm[Matrice->Ldeb[Ligne]] ); + } + } + } + + if ( UtiliserLesSuperLignes == NON_LU ) NbT = LNbTerm[Ligne]; + else { + SuperLigne = Matrice->SuperLigneDeLaLigne[Ligne]; + if ( SuperLigne != NULL ) NbT = SuperLigne->NombreDeTermes; + else NbT = LNbTerm[Ligne]; + } + LU_DeClasserUneLigne( Matrice, Ligne, NbT ); /* A quoi ça sert de declasser pour reclasser tout de suite apres ? */ + LU_ClasserUneLigne( Matrice, Ligne, NbT ); + + if ( Matrice->FaireDuPivotageDiagonal != OUI_LU ) { + NbT = CNbTermMatriceActive[Colonne]; + LU_DeClasserUneColonne( Matrice, Colonne, NbT ); /* A quoi ça sert de declasser pour reclasser tout de suite apres ? */ + LU_ClasserUneColonne( Matrice, Colonne, NbT ); + } + } + + /* Reintegration des lignes et colonnes exclues */ + if ( Matrice->CompteurExclusionMarkowitz >= SeuilPourReintegration && Matrice->ExclureLesEchecsMarkowitz == OUI_LU ) { + #if VERBOSE_LU + printf("Reintegration des lignes et colonnes exclues etape %d NbFillIn %d\n",Kp,Matrice->NbFillIn); + #endif + Matrice->CompteurExclusionMarkowitz = 0; + for ( Ki = Kp ; Ki < Matrice->Rang ; Ki++ ) { + /* Inutile de reintegrer les ligne a un seul terme */ + Ligne = OrdreLigne[Ki]; + if ( LNbTerm[Ligne] > 1 ) { + LigneRejeteeTemporairementPourPivotage[Ligne] = NON_LU; + } + /* Inutile de reintegrer les colonnes a un seul terme */ + if ( ( Matrice->LaMatriceEstSymetriqueEnStructure == OUI_LU && Matrice->FaireDuPivotageDiagonal == OUI_LU ) || + ( Matrice->LaMatriceEstSymetrique == OUI_LU && Matrice->FaireDuPivotageDiagonal == OUI_LU ) ) { + /* Si la matrice est symetrique en valeur ou en structure et qu'on fait du pivotage diagonal + alors on n'utilise pas les colonnes */ + } + else { + Colonne = Matrice->OrdreColonne[Ki]; + if ( CNbTermMatriceActive[Colonne] > 1 ) { + ColonneRejeteeTemporairementPourPivotage[Colonne] = NON_LU; + } + } + } + } + + if ( Matrice->FaireDuPivotageDiagonal == OUI_LU && Matrice->FactoriserEnMatricePleine == NON_LU ) { + LU_SelectionDuPivotDiagonal( Matrice, &LignePivot, &ColonnePivot ); + goto FinChoixPivot; + } + + if ( Matrice->FactoriserEnMatricePleine == NON_LU ) { + LU_SelectionDuPivot( Matrice, &LignePivot, &ColonnePivot ); + } + else { + /* On est dans le cas de la factorisation en matrice pleine */ + LU_SelectionDuPivotMatricePleine( Matrice, &LignePivot, &ColonnePivot ); + } + /* */ + FinChoixPivot: + if ( LignePivot >= 0 && ColonnePivot >= 0 ) { + + OrdreLignePivot = InverseOrdreLigne[LignePivot]; + InverseOrdreLigne[LignePivot] = Kp; + OrdreColonnePivot = InverseOrdreColonne[ColonnePivot]; + InverseOrdreColonne[ColonnePivot] = Kp; + + OrdreKp = OrdreLigne[Kp]; + OrdreLigne [Kp] = LignePivot; + OrdreLigne [OrdreLignePivot] = OrdreKp; + InverseOrdreLigne[OrdreKp] = OrdreLignePivot; + + OrdreKp = OrdreColonne[Kp]; + OrdreColonne [Kp] = ColonnePivot; + OrdreColonne [OrdreColonnePivot] = OrdreKp; + InverseOrdreColonne[OrdreKp] = OrdreColonnePivot; + + if ( Matrice->FactoriserEnMatricePleine == NON_LU ) { + /* Si la ligne pivot est pleine et la colonne pivot est pleine alors on est certain + qu'a la prochaine etape on sera en matrice pleine */ + /* + printf("Ligne pivot= %d Colonne pivot= %d\n",LignePivot,ColonnePivot); + */ + if ( Matrice->NombreDeTermes == (Rang - Kp) * (Rang - Kp) ) { + if ( UtiliserLesSuperLignes == OUI_LU ) { + /* La matrice sera pleine le coup d'apres */ + Matrice->LaMatriceEstPleine = OUI_LU; + } + if ( Matrice->LaMatriceEstSymetrique == NON_LU ) { + #if VERBOSE_LU + if ( Matrice->Rang - Matrice->Kp > 100 && WarningMatricePleine == OUI_LU ) { + printf(" --> Matrice pleine a l'etape %d rang %d NbFillIn %d taille du carre plein %d\n", + Matrice->Kp+1, Matrice->Rang, Matrice->NbFillIn,Matrice->Rang - Matrice->Kp); + WarningMatricePleine = NON_LU; + } + #endif + /* En fait il semblerait que ça ne sert pas ŕ grand chose */ + /* Matrice->FactoriserEnMatricePleine = OUI_LU;*/ + /* printf("Sous-matrice active pleine a Kp = %d Rang = %d\n",Matrice->Kp,Matrice->Rang); exit(0);*/ + } + } + if ( Matrice->FaireDuPivotageDiagonal == OUI_LU && Matrice->LaMatriceEstSymetrique == OUI_LU ) { + LU_EliminationDUneLigneCasSymetrique( Matrice, LignePivot , ColonnePivot ); + } + else { + if ( Matrice->LaMatriceEstSymetriqueEnStructure == OUI_LU ) { + /* Symetrie en structure (possible que si on fait aussi du pivotage diagonal + et que la matrice n'est pas symetrique */ + LU_EliminationDUneLigneVersionTurbo( Matrice , LignePivot , ColonnePivot ); + } + else { + LU_EliminationDUneLigne( Matrice, LignePivot , ColonnePivot ); + } + } + if ( Matrice->FactoriserEnMatricePleine == OUI_LU ) { + /* Comme le prochain coup on va passer en mode matrice pleine, on cherche le plus grand + terme de la matrice active */ + LU_RechercherLePlusGrandTermeDeLaMatriceActive( Matrice ); + } + } + else { + Matrice->ValeurDuPlusGrandTerme = -1.; + LU_EliminationDUneLigneMatricePleine( Matrice, LignePivot , ColonnePivot ); + } + } + else { + + RetourAuDebut = NON_LU; + + if ( Matrice->ContexteDeLaFactorisation == LU_POINT_INTERIEUR ) { + if ( Matrice->OnPeutRegulariser == NON_LU ) { + Matrice->PivotMin = Matrice->ValeurDuPivotMinExtreme; + Matrice->OnPeutRegulariser = OUI_LU; + RetourAuDebut = OUI_LU; + } + } + + if ( Matrice->ExclureLesEchecsMarkowitz == OUI_LU ) { + Matrice->ExclureLesEchecsMarkowitz = NON_LU; + Matrice->CompteurExclusionMarkowitz = 0; + for ( Ki = Kp ; Ki < Matrice->Rang ; Ki++ ) { + Ligne = OrdreLigne[Ki]; + Colonne = OrdreColonne[Ki]; + LigneRejeteeTemporairementPourPivotage[Ligne] = NON_LU; + ColonneRejeteeTemporairementPourPivotage[Colonne] = NON_LU; + if ( ContexteDeLaFactorisation == LU_SIMPLEXE ) continue; + + /* Il est necessaire de remettre dans le classement les lignes qui en avaient ete exclues + car le pivot a change. C'est indispensable pour le pivotage diagonal. */ + if ( Matrice->FaireDuPivotageDiagonal == OUI_LU ) { + AbsDuPlusGrandTermeDeLaLigne[Ligne] = -1.; + if ( UtiliserLesSuperLignes == NON_LU ) { + /* Il faut utiliser "Matrice->" a cause des redimensionnements */ + AbsValeurDuTermeDiagonal[Ligne] = fabs( Matrice->Elm[Matrice->Ldeb[Ligne]] ); + } + else { + SuperLigne = Matrice->SuperLigneDeLaLigne[Ligne]; + if ( SuperLigne != NULL ) { + for ( k = 0 ; k < SuperLigne->NombreDeLignesDeLaSuperLigne; k++ ) { + if ( SuperLigne->NumerosDesLignesDeLaSuperLigne[k] != Ligne ) continue; + X = fabs( SuperLigne->ElmColonneDeSuperLigne[ ( SuperLigne->IndexDuTermeDiagonal[k] * + SuperLigne->CapaciteDesColonnes) + k ] ); + AbsValeurDuTermeDiagonal[Ligne] = X; + break; + } + } + else { + /* Il faut utiliser "Matrice->" a cause des redimensionnements */ + AbsValeurDuTermeDiagonal[Ligne] = fabs( Matrice->Elm[Matrice->Ldeb[Ligne]] ); + } + } + } + + if ( UtiliserLesSuperLignes == NON_LU ) NbT = LNbTerm[Ligne]; + else { + SuperLigne = Matrice->SuperLigneDeLaLigne[Ligne]; + if ( SuperLigne != NULL ) NbT = SuperLigne->NombreDeTermes; + else NbT = LNbTerm[Ligne]; + } + + LU_DeClasserUneLigne( Matrice, Ligne, NbT ); + LU_ClasserUneLigne( Matrice, Ligne, NbT ); + if ( Matrice->FaireDuPivotageDiagonal != OUI_LU ) { + NbT = CNbTermMatriceActive[Colonne]; + LU_DeClasserUneColonne( Matrice, Colonne, NbT ); + LU_ClasserUneColonne( Matrice, Colonne, NbT ); + } + } + RetourAuDebut = OUI_LU; + } + if ( RetourAuDebut == NON_LU ) { + /* Switch eventuel de la methode */ + if ( Matrice->FaireDuPivotageDiagonal == OUI_LU && 0 /* desactive pour l'instant car utilite pas demontree */ ) { + /* PB: pour l'instant je ne gere pas le fait de ne pas avoir cree de colonnes si la matrice est symetrique + ou symetrique en structure */ + if ( Matrice->LaMatriceEstSymetrique != OUI_LU && Matrice->LaMatriceEstSymetriqueEnStructure != OUI_LU ) { + LU_SwitchVersMarkowitz( Matrice ); + RetourAuDebut = OUI_LU; + } + } + } + + if ( RetourAuDebut == OUI_LU ) goto EtapeDebut; + + #if VERBOSE_LU + printf("Factorisation LU: la matrice est singuliere, etape %d etape max %d\n",Kp,Matrice->Rang-1); + #endif + Matrice->EtapeSinguliere = Kp; + Matrice->AnomalieDetectee = MATRICE_SINGULIERE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); + } +} + +/* RAZ de SolutionIntermediaire avant toute resolution de systeme */ +memset( (char *) Matrice->SolutionIntermediaire, 0, Rang * sizeof( double ) ); + +/* Attention, dans les cas hors Simplexe on a initialise le PivotMin a PIVOT_MIN_FINAL. Il faut + donc remettre ValeurDuPivotMinExtreme dans le cas ContexteDeLaFactorisation = LU_POINT_INTERIEUR */ +if ( Matrice->ContexteDeLaFactorisation == LU_POINT_INTERIEUR ) { + Matrice->PivotMin = Matrice->ValeurDuPivotMinExtreme; + MatriceEntree->OnARegularise = Matrice->OnARegularise ; +} + +if ( UtiliserLesSuperLignes == OUI_LU ) { + if ( Matrice->NbScanSuperLignes > 0 ) { + printf("Nombre moyen de lignes dans une SuperLigne scannee %d\n",Matrice->NbLignesSuperLignes/Matrice->NbScanSuperLignes); + printf("Nombre superlignes a moins de 2 lignes scannees %d\n",Matrice->NbScanMin); + } +} + +Matrice->MxTermesCreesLuUpdate = 0; +if ( Matrice->ContexteDeLaFactorisation == LU_GENERAL ) { + /* On conserve le stockage par ligne de U dont on dispose grace a la factorisation */ + LU_ChainageParLigneDeULUGeneral( Matrice ); + /* On construit le chainage par colonne de U pour les resolutions */ + LU_ChainageParColonneDeUHorsSimplexe( Matrice ); +} +else if ( Matrice->ContexteDeLaFactorisation == LU_SIMPLEXE ) { + /* On se reconstruit un chainage par ligne de U pour recuperer la place vide qu'on peut + avoir construite pendant la factorisation */ + LU_ChainageParLigneDeU( Matrice ); + /* On construit un chainage par colonne de U adapte a la LU update */ + LU_ChainageParColonneDeU( Matrice ); + /* Pour la LU_Update, on stocke le nombre max de termes crees a partir duquel il faudra refaire une + factorisation: un certain pourcentage du nombre de terme du triangle U */ + Matrice->MxTermesCreesLuUpdate = (int) ( POURCENTAGE_MAX_DE_TERMES_CREES_PAR_LU_UPDATE * Matrice->IndexLibreDeU ); + /* Attention, en faisant ca on peut avoir un nombre tres grand et ne jamais demander de refactorisation + dans la lu update si Rang est grand donc on teste le resultat par rapport a Matrice->IndexLibreDeU */ + k = Matrice->NombreDeVecteursHAlloues * (int) ( 0.1 * Matrice->Rang ); + if ( k > Matrice->IndexLibreDeU ) k = Matrice->IndexLibreDeU; + if ( k < 100 ) k = 100; + if ( Matrice->MxTermesCreesLuUpdate < k ) Matrice->MxTermesCreesLuUpdate = k; + +} +else { /* Contexte LU_POINT_INTERIEUR */ + /* On se recontruit un chainage par ligne de U pour recuperer la place vide qu'on peut + avoir construite pendant la factorisation */ + LU_ChainageParLigneDeU( Matrice ); + /* On classe le stockage par ligne de U dans l'ordre croissant de l'ordre d'elimination */ + LU_StockageDeUDansLOrdreCroissantDesIndices( Matrice ); +} + +#if VERBOSE_LU + printf("Fin de factorisation NbFillIn %d\n", Matrice->NbFillIn); fflush(stdout); +#endif + +/* Liberation des tableaux de travail */ +LU_LibererLesTableauxTemporaires( Matrice ); + +/* En retour, les triangles de la factorisee */ +MatriceEntree->IndexDebutDesColonnesDeL = Matrice->CdebParColonneDeL; +MatriceEntree->NbTermesDesColonnesDeL = Matrice->NbTermesParColonneDeL; +MatriceEntree->ValeurDesTermesDeL = Matrice->ElmDeL; +MatriceEntree->IndicesDeLigneDeL = Matrice->IndiceLigneDeL; + +MatriceEntree->IndexDebutDesLignesDeU = Matrice->LdebParLigneDeU; +MatriceEntree->NbTermesDesLignesDeU = Matrice->NbTermesParLigneDeU; +MatriceEntree->ValeurDesTermesDeU = Matrice->ElmDeU; +MatriceEntree->IndicesDeColonneDeU = Matrice->IndiceColonneDeU; + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_fonctions.h b/src/ext/Sirius_Solver/simplexe/lu/lu_fonctions.h new file mode 100644 index 0000000000..8aa2e6a06d --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_fonctions.h @@ -0,0 +1,230 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef LU_FONCTIONS_DEJA_DEFINI +/*****************************************************************************/ + +# include "lu_define.h" +# include "lu_definition_arguments.h" + +/*****************************************************************************/ +/*----------------------------- Factorisation LU ------------------------------*/ + +MATRICE * LU_Factorisation( MATRICE_A_FACTORISER * ); + +void LU_FactorisationCalculs( MATRICE * Matrice , MATRICE_A_FACTORISER * ); + +void LU_Refactorisation( MATRICE * , double * , int , double * , double , char * , char * ); + +void LU_InitTableauxANull( MATRICE * ); + +void LU_AllouerLU( MATRICE * , double * , int * , int * , int * , int * ); + +void LU_ConstruireProbleme( MATRICE * Matrice , double * , int * , int * , int * , int , int , int ); + +void LU_AugmenterLaTailleDeLaMatriceActive( MATRICE * , int , int ); + +void LU_AugmenterLaTailleDeLaMatriceActiveParColonne( MATRICE * , int , int ); + +void LU_AugmenterLaTailleDuTriangleL( MATRICE * , int ); + +void LU_AugmenterLaTailleDuTriangleU( MATRICE * , int ); + +void LU_AugmenterLaTailleDuTriangleUParColonne( MATRICE * , int ); + +void LU_SelectionDuPivot( MATRICE * , int * , int * ); + +void LU_SelectionDuPivotDiagonal( MATRICE * , int * , int * ); + +double LU_TrouverPlusGrandTermeDeLigne( MATRICE * , int ); + +void LU_EliminationDUneLigne( MATRICE * , int , int ); + +void LU_EliminationDUneLigneVersionTurbo( MATRICE * , int , int ); + +void LU_ScanLigne( MATRICE * , int , int , int , double , int , char * , char * ); + +void LU_ClasserToutesLesLignesEtToutesLesColonnes( MATRICE * ); + +void LU_ClasserUneLigne( MATRICE * , int , int ); + +void LU_DeClasserUneLigne( MATRICE * , int , int ); + +void LU_ClasserUneColonne( MATRICE * , int , int ); + +void LU_DeClasserUneColonne( MATRICE * , int , int ); + +void LU_SupprimerTermesInutilesDansColonne( MATRICE * , int , int ); + +void LU_InitMinMarkowitzDeColonne( MATRICE * , int , int * , double * ); + +void LU_PlusGrandTermeDeLaLigne( MATRICE * , int , int , int * ); + +void LU_InitMinMarkowitzDeLigne( MATRICE * , int , int * , double * ); + +/* Gestion des super lignes */ +void LU_InitPourSuperLignes( MATRICE * ); + +void LU_DeclenchementEventuelRechercheSuperLignes( MATRICE * ); + +void LU_CreerLesHashCode( MATRICE * ); + +void LU_ClasserLesElementsEnFonctionDuHashCode( MATRICE * ); + +void LU_MajClassementDesElementsEnFonctionDuHashCode( MATRICE * ); + +void LU_ClasserEnFonctionDuHashCode( MATRICE * , int ); + +void LU_DeClasserEnFonctionDuHashCode( MATRICE * , int ); + +void LU_RechercherUnGroupeDeLignes( MATRICE * , int * , int * , int , int , int , + int * T , int * , int * ); + +void LU_DetectionSuperLignes( MATRICE * , char * ); + +void LU_ScanSuperLigne( MATRICE * , SUPER_LIGNE_DE_LA_MATRICE * , int , int , double * , unsigned int * ); + +void LU_ScanSuperLigneCasSymetrique( MATRICE * , SUPER_LIGNE_DE_LA_MATRICE * , int , int , double * , unsigned int * ); + +SUPER_LIGNE_DE_LA_MATRICE * LU_CreerUneSuperLigne( MATRICE * , int * , int , int * , int ); + +void LU_FusionnerDeuxSuperLignes( MATRICE * , int * , int , int ); + +void LU_AjouterUneLigneDansUneSuperLigne( MATRICE * , SUPER_LIGNE_DE_LA_MATRICE * , int * , int ); + +void LU_SupprimerUneLigneDansUneSuperLigne( MATRICE * , SUPER_LIGNE_DE_LA_MATRICE * , int , int ); + +void LU_SupprimerUnTermeDansUneSuperLigne( MATRICE * , SUPER_LIGNE_DE_LA_MATRICE * , int , int ); + +void LU_RecopierUneLigneDeSuperLigneDansLigne( MATRICE * , SUPER_LIGNE_DE_LA_MATRICE * , int ); + +void LU_AugmenterCapaciteDesColonnesDeSuperLigne( MATRICE * , SUPER_LIGNE_DE_LA_MATRICE * , int ); + +void LU_DiminuerCapaciteDesColonnesDeSuperLigne( MATRICE * , SUPER_LIGNE_DE_LA_MATRICE * ); + +void LU_AugmenterCapaciteDeSuperLigne( MATRICE * , SUPER_LIGNE_DE_LA_MATRICE * , int ); + +void LU_MettreTouteLaMatriceDansUneSuperLigne( MATRICE * Matrice ); + +/* */ + +/* Pour le switch vers le pivotage de Markowitz en cas de pivot nul sur une factorisation + par pivotage diagonal */ +void LU_SwitchVersMarkowitz( MATRICE * ); +void LU_ClasserLesColonnesRestantes( MATRICE * ); +/* */ + +/* Mode matrice pleine */ +void LU_ScanLigneMatricePleine ( MATRICE * , int , int , double ); +void LU_EliminationDUneLigneMatricePleine( MATRICE * , int , int ); +void LU_SelectionDuPivotMatricePleine( MATRICE * , int * , int * ); +void LU_RechercherLePlusGrandTermeDeLaMatriceActive( MATRICE * ); +/* */ + +/* Mode matrice symetrique */ +void LU_EliminationDUneLigneCasSymetrique( MATRICE * , int , int ); +void LU_ScanLigneCasSymetrique( MATRICE * , int , int , int , double , int , char * ); +/* */ + +void LU_LibererLesTableauxTemporaires( MATRICE * ); + +void LU_LibererMemoireLU( MATRICE * ); + +void LU_LuSolv( MATRICE * , double * , int * , MATRICE_A_FACTORISER * , int , double ); +void LU_LuSolvTriangleL( MATRICE * , double * ); +void LU_LuSolvTriangleU( MATRICE * , double * ); + +void LU_LuSolvTransposee( MATRICE * , double * , int * , MATRICE_A_FACTORISER * , int , double ); +void LU_LuSolvTriangleUTransposee( MATRICE * , double * ); +void LU_LuSolvTriangleLTransposee( MATRICE * , double * ); + +/* Resolution cas hyper creux */ +void LU_AllocEtInitHyperCreux( MATRICE * , char * ); +char LU_RecusionSurTriangle_1( MATRICE * , int * , int , int * , int * , int * , int * , int * ); +char LU_RecusionSurTriangle_2( MATRICE * , int * , int , int * , int * , int * , int * ); + +char LU_LuSolvTriangleLSecondMembreHyperCreux( MATRICE * , int * , int * , double * ); +void LU_LuSolveHSecondMembreHyperCreux( MATRICE * , int * , int * ); +char LU_LuSolvTriangleUSecondMembreHyperCreux( MATRICE * , double * , int * , int * , char ); + +char LU_LuSolvTriangleUTransposeeSecondMembreHyperCreux( MATRICE * , int * , int * , double * ); +void LU_LuSolveHTransposeeSecondMembreHyperCreux( MATRICE * , int * , int * ); +char LU_LuSolvTriangleLTransposeeSecondMembreHyperCreux( MATRICE * , double * , int * , int * ); + +void LU_LuSolvSecondMembreHyperCreux( MATRICE * , double * , int * , int * , char , char , char * ); +void LU_LuSolvTransposeeSecondMembreHyperCreux( MATRICE * , double * , int * , int * , char , char * ); +void LU_MettreSolutionSousFormeHyperCreux( MATRICE * , double * , int * , int * , double * , char , char ); + +/* Fin cas hyper creux */ + +void LU_LuSolvLuUpdate( MATRICE * , double * , int * , char , char , MATRICE_A_FACTORISER * , + int , double ); +void LU_LuSolvTransposeeLuUpdate( MATRICE * , double * , int * , char , MATRICE_A_FACTORISER * , + int , double ); + +void LU_UpdateLuSpikePret( MATRICE * , int , int * ); +void LU_UpdateLuEliminations( MATRICE * , int , int , int , int * , int * , char * , double * ); + +void LU_LuSolveH( MATRICE * ); +void LU_LuSolveHTransposee( MATRICE * ); + +void LU_ChainageParLigneDeULUGeneral( MATRICE * ); +void LU_ChainageParLigneDeU( MATRICE * ); +void LU_ChainageParColonneDeU( MATRICE * ); +void LU_ChainageParLigneDeL( MATRICE * , char * ); +void LU_ChainageParColonneDeUHorsSimplexe( MATRICE * ); + +/* Variables indeterminees en cas de singularite */ + +int * LU_InconnuesIndeterminees( MATRICE * , int * , int * ); + +int * LU_Indeterminees( MATRICE * , int * , char , char , char ); + +/* Pour le scaling s'il est demande */ +void LU_CalculerLeScaling( MATRICE * ); +void LU_ArrondiEnPuissanceDe2( double * ); +void LU_Scaling( MATRICE * ); +void LU_ScalingSecondMembre( MATRICE * , double * ); +void LU_ScalingSecondMembreTranspose( MATRICE * , double * ); +void LU_UnScaling( MATRICE * , double * ); +void LU_UnScalingTranspose( MATRICE * , double * ); + +/* Pour les refactorisation pour le point interieur */ +void LU_StockageDeUDansLOrdreCroissantDesIndices( MATRICE * ); +void LU_RefactorisationSimulation( MATRICE * , char * , int ); +double LU_RefactorisationControleDuPivot( MATRICE * , double , double * , int , int , char * ); +void LU_RefactorisationScanLigne( int , int , double , char * , double * , double * , int * ); +void LU_RefactorisationScanLignePlein( int , int , double , double * , double * , int * ); + +/* Pour les refactorisations non symetriques */ +void LU_EliminationDUneLigneRefactorisationNonSymetrique( MATRICE * , int * ); +void LU_InitTrianglesRefactorisationNonSymetrique( MATRICE * ,double * , int * , int * , int * , int * ); +void LU_RefactorisationNonSymetrique( MATRICE * , MATRICE_A_FACTORISER * ); +void LU_RefactorisationLL( MATRICE * , double * , int * , int * , int * , int * ); + +/* Pour les refactorisations symetriques */ +void LU_RefactorisationSymetrique( MATRICE * , MATRICE_A_FACTORISER * ); + +/*******************************************************************************************/ +# define LU_FONCTIONS_DEJA_DEFINI +# endif +# ifdef __cplusplus + } +# endif diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_inconnues_indeterminees.c b/src/ext/Sirius_Solver/simplexe/lu/lu_inconnues_indeterminees.c new file mode 100644 index 0000000000..557760704c --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_inconnues_indeterminees.c @@ -0,0 +1,165 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Ce sous-programme retourne la liste des inconnues que l'on + ne peut pas determiner lorsque la matrice est singuliere. + C'est la sous-matrice active. + La fonction retourne: + - le nombre de variables indeterminees, + - le nombre de triangles observables, + - un pointeur sur une table contenant + * la valeur "VARIABLE_INDETERMINEE" si + l'inconnue est indeterminee + * le numero du triangle si l'inconnue appartient a + un triangle qui a pu etre factorise + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +# define PREMIER_NUMERO_DE_TRIANGLE 1 +# define VARIABLE_INDETERMINEE -1 +# define VARIABLE_PAS_ENCORE_AFFECTEE -10 +# define NUMERO_DE_TRIANGLE_NON_DEFINI -10000 + +/*-------------------------------------------------------------------------------------------------------------*/ +/* Attention cette fonction n'est plus utilisee. C'est Sylvain qui reconstiutue ce dont il a besoin */ + +int * LU_InconnuesIndeterminees( MATRICE * Matrice , int * NombreDeVariablesIndeterminees , int * NombreDeTrianglesFactorises ) +{ +int Kp; int ilDeb ; int ilFin; int il; int ilMax; int Inconnue ; +int NumeroDeTriangle; int NumeroDeTriangleCourant ; int NbVariablesIndeterminees; + +/*Matrice = Mat;*/ + +printf("Attention: la fonction LU_InconnuesIndeterminees est obsolete, on ne rentre pas dedans\n"); +return( NULL ); + +*NombreDeVariablesIndeterminees = 0; +*NombreDeTrianglesFactorises = 0; + +Matrice->NumeroDeTriangleDeLaVariable = (int *) malloc( Matrice->Rang * sizeof( int ) ); +if ( Matrice->NumeroDeTriangleDeLaVariable == NULL ) { + printf("Factorisation LU, sous-programme LU_InconnuesIndeterminees: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} + + +for ( Kp = 0 ; Kp < Matrice->Rang ; Kp++ ) Matrice->NumeroDeTriangleDeLaVariable[Kp] = VARIABLE_PAS_ENCORE_AFFECTEE; + +NbVariablesIndeterminees = 0; +for ( Kp = Matrice->EtapeSinguliere ; Kp < Matrice->Rang ; Kp++ ) { + Matrice->NumeroDeTriangleDeLaVariable[Matrice->OrdreColonne[Kp]] = VARIABLE_INDETERMINEE; + NbVariablesIndeterminees++; +} + +/* Etablissement des numero de triangles factorises: parcours de la triangulaire superieure */ + +NumeroDeTriangleCourant = PREMIER_NUMERO_DE_TRIANGLE - 1; + +for ( Kp = Matrice->EtapeSinguliere - 1 ; Kp >= 0 ; Kp-- ) { + ilDeb = Matrice->LdebParLigneDeU[Kp]; + ilFin = ilDeb + Matrice->NbTermesParLigneDeU[Kp]; + /* Recherche d'un numero de triangle */ + il = ilDeb; + ilMax = ilFin; + NumeroDeTriangle = NUMERO_DE_TRIANGLE_NON_DEFINI; + while ( il != ilMax ) { + if ( Matrice->ElmDeU[il] != 0.0 ) { + Inconnue = Matrice->IndiceColonneDeU[il]; + if ( Matrice->NumeroDeTriangleDeLaVariable[Inconnue] >= PREMIER_NUMERO_DE_TRIANGLE ) { + NumeroDeTriangle = Matrice->NumeroDeTriangleDeLaVariable[Inconnue]; + break; + } + } + il++; + } + /* On n'a pas trouve de numero de zone alors on en cree un */ + if ( NumeroDeTriangle == NUMERO_DE_TRIANGLE_NON_DEFINI ) { + NumeroDeTriangleCourant++; + NumeroDeTriangle = NumeroDeTriangleCourant; + } + + il = ilDeb; + ilMax = ilFin; + while ( il != ilMax ) { + if ( Matrice->ElmDeU[il] != 0.0 ) { + Inconnue = Matrice->IndiceColonneDeU[il]; + if ( Matrice->NumeroDeTriangleDeLaVariable[Inconnue] != VARIABLE_INDETERMINEE ) { + Matrice->NumeroDeTriangleDeLaVariable[Inconnue] = NumeroDeTriangle; + } + } + il++; + } +} + +*NombreDeVariablesIndeterminees = NbVariablesIndeterminees; +if ( NumeroDeTriangleCourant < PREMIER_NUMERO_DE_TRIANGLE ) NumeroDeTriangleCourant = 0; +*NombreDeTrianglesFactorises = NumeroDeTriangleCourant; + +return( Matrice->NumeroDeTriangleDeLaVariable ); + +} + +/*----------------------------------------------------------------------*/ +/* Routine experimentale, uniquement pour les besoins du PRESOLVE */ +/* On utilise NumeroDeTriangleDeLaVariable mais en realite on met les + numeros de lignes non factorisees */ + +int * LU_Indeterminees( MATRICE * Matrice, int * NombreDIndeterminees, char Choix, char LIGNE, char COLONNE ) +{ +int Kp; int NbDIndeterminees; int * Ordre; + +/*printf("LU_Indeterminees Choix %d LIGNE %d COLONNE %d\n",Choix,LIGNE,COLONNE);*/ + +if ( Choix == LIGNE ) Ordre = Matrice->OrdreLigne; +else if ( Choix == COLONNE ) Ordre = Matrice->OrdreColonne; +else { + *NombreDIndeterminees = 0; + return( NULL ); +} + +*NombreDIndeterminees = 0; + +Matrice->NumeroDeTriangleDeLaVariable = (int *) malloc( Matrice->Rang * sizeof( int ) ); +if ( Matrice->NumeroDeTriangleDeLaVariable == NULL ) { + return( NULL ); +} + +NbDIndeterminees = 0; +for ( Kp = Matrice->EtapeSinguliere ; Kp < Matrice->Rang ; Kp++ ) { + Matrice->NumeroDeTriangleDeLaVariable[NbDIndeterminees] = Ordre[Kp]; + NbDIndeterminees++; +} + +*NombreDIndeterminees = NbDIndeterminees; + +return( Matrice->NumeroDeTriangleDeLaVariable ); + +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_init_tableaux_null.c b/src/ext/Sirius_Solver/simplexe/lu/lu_init_tableaux_null.c new file mode 100644 index 0000000000..0ae4472988 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_init_tableaux_null.c @@ -0,0 +1,164 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On met NULL dans tous les tableaux. ceci permet d'eviter + les plantages lors de free mais aussi de reconnaitre + un tableau non alloue. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void LU_InitTableauxANull( MATRICE * Matrice ) +{ + +Matrice->LigneRejeteeTemporairementPourPivotage = NULL; +Matrice->ColonneRejeteeTemporairementPourPivotage = NULL; +Matrice->AbsDuPlusGrandTermeDeLaLigne = NULL; + +Matrice->LignePrecedente = NULL; +Matrice->LigneSuivante = NULL; +Matrice->Ldeb = NULL; +Matrice->LNbTerm = NULL; +Matrice->LDernierPossible = NULL; +Matrice->LIndiceColonne = NULL; +Matrice->Elm = NULL; + +Matrice->ColonnePrecedente = NULL; +Matrice->ColonneSuivante = NULL; +Matrice->Cdeb = NULL; +Matrice->CNbTerm = NULL; +Matrice->CNbTermMatriceActive = NULL; +Matrice->CDernierPossible = NULL; +Matrice->CIndiceLigne = NULL; + +Matrice->SuperLigneDeLaLigne = NULL; +Matrice->SuperLigneAScanner = NULL; +Matrice->SuperLigne = NULL; +Matrice->PoidsDesColonnes = NULL; +Matrice->HashCodeLigne = NULL; +Matrice->HashCodeSuperLigne = NULL; +Matrice->HashModuloPrem = NULL; +Matrice->HashNbModuloIdentiques = NULL; +Matrice->TypeDeClassementHashCodeAFaire = NULL; +Matrice->HashModuloSuiv = NULL; +Matrice->HashModuloPrec = NULL; + +Matrice->PremLigne = NULL; +Matrice->SuivLigne = NULL; +Matrice->PrecLigne = NULL; + +Matrice->PremColonne = NULL; +Matrice->SuivColonne = NULL; +Matrice->PrecColonne = NULL; + +Matrice->W = NULL; +Matrice->Marqueur = NULL; + +Matrice->OrdreLigne = NULL; +Matrice->InverseOrdreLigne = NULL; +Matrice->OrdreColonne = NULL; +Matrice->InverseOrdreColonne = NULL; + +Matrice->NbTermesParColonneDeL = NULL; +Matrice->CdebParColonneDeL = NULL; +Matrice->ElmDeL = NULL; +Matrice->IndiceLigneDeL = NULL; +Matrice->IndexKpDeUouL = NULL; + +Matrice->NbTermesParLigneDeU = NULL; +Matrice->LdebParLigneDeU = NULL; +Matrice->ElmDeU = NULL; +Matrice->IndiceColonneDeU = NULL; +Matrice->CapaciteParLigneDeU = NULL; + +Matrice->LdebParLigneDeL = NULL; +Matrice->NbTermesParLigneDeL = NULL; +Matrice->IndiceColonneParLigneDeL = NULL; +Matrice->ElmDeLParLigne = NULL; + +Matrice->CdebParColonneDeU = NULL; +Matrice->NbTermesParColonneDeU = NULL; +Matrice->IndiceLigneParColonneDeU = NULL; +Matrice->CapaciteParColonneDeU = NULL; +Matrice->ElmDeUParColonne = NULL; + +Matrice->StockageColonneVersLigneDeU = NULL; +Matrice->StockageLigneVersColonneDeU = NULL; + +Matrice->SolutionIntermediaire = NULL; + +# ifdef HYPER_CREUX + Matrice->NoeudDansLaliste = NULL; + Matrice->ListeDesNoeuds = NULL; + Matrice->PseudoPile = NULL; +# endif + +Matrice->NumeroDeTriangleDeLaVariable = NULL; + +Matrice->OrdreUcolonne = NULL; +Matrice->InverseOrdreUcolonne = NULL; + +Matrice->HDeb = NULL; +Matrice->HLigne = NULL; +Matrice->HNbTerm = NULL; +Matrice->HIndiceColonne = NULL; +Matrice->HValeur = NULL; + +Matrice->ValeurElmSpike = NULL; +Matrice->IndicesLignesDuSpike = NULL; + +Matrice->ScaleX = NULL; +Matrice->ScaleB = NULL; + +Matrice->AbsValeurDuTermeDiagonal = NULL; + +Matrice->DebutInfosAdressesQueKpModifie = NULL; +Matrice->AdresseDeUModifie = NULL; +Matrice->AdresseUHaut = NULL; +Matrice->DebutInfosLignesQueKpModifie = NULL; +Matrice->NombreDeLignesQueKpModifie = NULL; +Matrice->AdresseUGauche = NULL; +Matrice->NombreDeTermesParLigneQueKpModifie = NULL; + +Matrice->SecondMembreSV = NULL; +Matrice->SolutionSV = NULL; + +Matrice->TermeDeRegularisation = NULL; + +return; +} + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_memoire.h b/src/ext/Sirius_Solver/simplexe/lu/lu_memoire.h new file mode 100644 index 0000000000..71c02c324f --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_memoire.h @@ -0,0 +1,34 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef LU_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# include "mem_fonctions.h" +/***************************************************************** + + + Macros pour redefinir les primitives de gestion memoire lorsqu'on + ne veut pas utiliser celles de lib de l'OS + + +*****************************************************************/ + +# define malloc(Taille) MEM_Malloc(Matrice->Tas,Taille) +# define free(Pointeur) MEM_Free(Pointeur) +# define realloc(Pointeur,Taille) MEM_Realloc(Matrice->Tas,Pointeur,Taille) + +/*****************************************************************/ +# define LU_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# endif diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_refactorisation.c b/src/ext/Sirius_Solver/simplexe/lu/lu_refactorisation.c new file mode 100644 index 0000000000..7a7c7ade13 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_refactorisation.c @@ -0,0 +1,556 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Refactorisation de la matrice (l'ordre d'elimination + a deja ete calcule). + + ATTENTION: Routines speciales pour le point interieur. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +# include "memstats.h" + +# define TAILLE_DU_MEGA_OCTET (1024 * 1024) + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_RefactorisationScanLigne( int il, int ilMax, double ValeurTermeColonnePivot, char * T , double * W, + double * ElmDeU, int * IndexKpDeUouL ) +{ + +while ( il < ilMax ) { + if ( T[IndexKpDeUouL[il]] == 1 ) ElmDeU[il]-= W[IndexKpDeUouL[il]] * ValeurTermeColonnePivot; + il++; +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_RefactorisationScanLignePlein( int il, int ilMax, double ValeurTermeColonnePivot, double * W, + double * ElmDeU , int * IndexKpDeUouL ) +{ + +while ( il < ilMax ) { + ElmDeU[il]-= W[IndexKpDeUouL[il]] * ValeurTermeColonnePivot; + il++; +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +double LU_RefactorisationControleDuPivot( MATRICE * Matrice, + double ValeurDeRegularisation, + double * TermeDeRegularisation, + int ColonnePivot, + int il, + char * OnARegularise + ) +{ +double * ElmDeU; + +ElmDeU = Matrice->ElmDeU; + +if ( fabs( ElmDeU[il] ) < Matrice->PivotMin ) { + /* + if ( TermeDeRegularisation[ColonnePivot] == 0.0 ) { + *OnARegularise = OUI_LU; + TermeDeRegularisation[ColonnePivot] = ValeurDeRegularisation; + + } + ElmDeU[il] = TermeDeRegularisation[ColonnePivot]; + */ + + if ( ElmDeU[il] > 0.0 ) { + ElmDeU[il] = ValeurDeRegularisation; + TermeDeRegularisation[ColonnePivot] = ValeurDeRegularisation; + *OnARegularise = OUI_LU; + } + else { + ElmDeU[il] = -ValeurDeRegularisation; + TermeDeRegularisation[ColonnePivot] = -ValeurDeRegularisation; + *OnARegularise = OUI_LU; + } + +} + +return( ElmDeU[il] ); +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Matrice symetrique et pivotage diagonal */ +/* ATTENTION: special Point Interieur */ + +void LU_Refactorisation( MATRICE * Matrice , + double * ValeurDesTermesDeU , int NbElementsU , + double * TermeDeRegularisation , double ValeurDeRegularisation , + char * OnARegularise , char * Erreur ) +{ +int il; int ilMax; int Kp; int Kpp; +int ic; int ilDebKp; int ilMaxKp ; char CalculPlein; int PremierKpParCalculClassique; +double ValeurTermeColonnePivot; double ValeurDuPivot; double X; +double UnSurValeurDuPivot; int IndexAdressesKp; int IndexLignesKp; int j; int k; +double * ptAdresseDeUHaut; double * ptAdresseDeUModifie; double * ptAdresseUGauche; +double * W; char * T; int Rang; int * LdebParLigneDeU; int * NbTermesParLigneDeU; +int * IndiceColonneDeU; double * ElmDeU; double * ElmDeL; +int * DebutInfosAdressesQueKpModifie; int * DebutInfosLignesQueKpModifie; +int * NombreDeLignesQueKpModifie; int * IndexKpDeUouL; +double ** AdresseUGauche; double ** AdresseUHaut; double ** AdresseDeUModifie; +int * NombreDeTermesParLigneQueKpModifie; + +/*printf(" LU_Refactorisation \n"); fflush(stdout);*/ + +*OnARegularise = NON_LU; +*Erreur = NON_LU; + +/* Recopie de la matrice a factoriser */ +/* Triangle U */ +memcpy( (char *) Matrice->ElmDeU , (char *) ValeurDesTermesDeU , NbElementsU * sizeof( double ) ); + +Rang = Matrice->Rang; +LdebParLigneDeU = Matrice->LdebParLigneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; +ElmDeU = Matrice->ElmDeU; +ElmDeL = Matrice->ElmDeL; +IndexKpDeUouL = Matrice->IndexKpDeUouL; + +DebutInfosAdressesQueKpModifie = Matrice->DebutInfosAdressesQueKpModifie; +DebutInfosLignesQueKpModifie = Matrice->DebutInfosLignesQueKpModifie; +NombreDeLignesQueKpModifie = Matrice->NombreDeLignesQueKpModifie; + +AdresseUGauche = Matrice->AdresseUGauche; +AdresseUHaut = Matrice->AdresseUHaut; +AdresseDeUModifie = Matrice->AdresseDeUModifie; + +NombreDeTermesParLigneQueKpModifie = Matrice->NombreDeTermesParLigneQueKpModifie; + +PremierKpParCalculClassique = Matrice->PremierKpParCalculClassique; + +CalculPlein = NON_LU; + +/* Factorisation */ +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + if ( Kp == PremierKpParCalculClassique ) { + /*printf("Refactorisation classique a partir de %d sur %d ecart %d\n",Kp,Rang,Rang-Kp);*/ + goto CompleterLaFactorisation; + } + /* Transfert de la ligne dans un tableau de travail */ + il = LdebParLigneDeU[Kp]; + ilMax = il + NbTermesParLigneDeU[Kp]; + ilDebKp = il; + ilMaxKp = ilMax; + ValeurDuPivot = LU_RefactorisationControleDuPivot( Matrice , ValeurDeRegularisation, TermeDeRegularisation, + IndiceColonneDeU[il], il, OnARegularise ); + UnSurValeurDuPivot = 1. / ValeurDuPivot; + /* Stockage de l'inverse du pivot */ + ElmDeU[il] = UnSurValeurDuPivot; + /* */ + /* Modification de la sous-matrice active */ + IndexAdressesKp = DebutInfosAdressesQueKpModifie[Kp]; + IndexLignesKp = DebutInfosLignesQueKpModifie[Kp]; + for ( j = 0 ; j < NombreDeLignesQueKpModifie[Kp] ; j++ ) { + ptAdresseUGauche = AdresseUGauche[IndexLignesKp]; + ValeurTermeColonnePivot = *ptAdresseUGauche * UnSurValeurDuPivot; + for ( k = 0 ; k < NombreDeTermesParLigneQueKpModifie[IndexLignesKp]; k++ ) { + ptAdresseDeUHaut = AdresseUHaut [IndexAdressesKp]; + ptAdresseDeUModifie = AdresseDeUModifie[IndexAdressesKp]; + X = *ptAdresseDeUHaut * ValeurTermeColonnePivot; + *ptAdresseDeUModifie-= X; + IndexAdressesKp++; + } + IndexLignesKp++; + } +} +goto RecopieDuTriangleU; + +CompleterLaFactorisation: +/* On complete la factorisation par la methode classique */ +W = NULL; +T = NULL; +W = (double *) malloc( Rang * sizeof( double ) ); +T = (char *) malloc( Rang * sizeof( char ) ); +if ( W == NULL || T == NULL ) { + free( W ); W = NULL; free( T ); T = NULL; + *Erreur = OUI_LU; + goto FinRefactorisation; +} +memset( T , 0 , Rang * sizeof( char ) ); + +for ( ; Kp < Rang ; Kp++ ) { + /* Transfert de la ligne dans un tableau de travail */ + il = LdebParLigneDeU[Kp]; + ilMax = il + NbTermesParLigneDeU[Kp]; + if ( NbTermesParLigneDeU[Kp] == Rang - Kp ) CalculPlein = OUI_LU; + ilDebKp = il; + ilMaxKp = ilMax; + ValeurDuPivot = LU_RefactorisationControleDuPivot( Matrice , ValeurDeRegularisation, TermeDeRegularisation, + IndiceColonneDeU[il], il, OnARegularise ); + UnSurValeurDuPivot = 1. / ValeurDuPivot; + /* Stockage de l'inverse du pivot */ + ElmDeU[il] = UnSurValeurDuPivot; + /* */ + il++; /* On ne modifie pas la colonne pivot */ + if ( CalculPlein == NON_LU ) { + while ( il < ilMax ) { + W[IndexKpDeUouL[il]] = ElmDeU[il]; + T[IndexKpDeUouL[il]] = 1; + il++; + } + } + else { + while ( il < ilMax ) { + W[IndexKpDeUouL[il]] = ElmDeU[il]; + il++; + } + } + /* Maintenant on balaye toutes les lignes de la matrice active qui ont un terme non nul dans la colonne + pivot et on les compare a la ligne pivot */ + ic = ilDebKp; + ic++; /* Terme diagonal */ + while ( ic < ilMaxKp ) { + ValeurTermeColonnePivot = ElmDeU[ic] * UnSurValeurDuPivot; + /* Scanner la ligne */ + /* Partie U en utilisant le chainage par colonne */ + Kpp = IndexKpDeUouL[ic]; + il = LdebParLigneDeU[Kpp]; + ilMax = il + NbTermesParLigneDeU[Kpp]; + /* Calcul des termes modifies */ + if ( CalculPlein == OUI_LU ) { + LU_RefactorisationScanLignePlein( il, ilMax, ValeurTermeColonnePivot, W, ElmDeU, IndexKpDeUouL ); + } + else { + LU_RefactorisationScanLigne( il, ilMax, ValeurTermeColonnePivot, T , W, ElmDeU, IndexKpDeUouL ); + } + /* On passe au terme suivant de la colonne pivot */ + ic++; + } + + if ( CalculPlein == NON_LU ) { + il = ilDebKp; + while ( il < ilMaxKp ) { + T[IndexKpDeUouL[il]] = 0; + il++; + } + } +} +free( W ); +free( T ); +W = NULL; +T = NULL; + +RecopieDuTriangleU: +/* Recopie du triangle U dans le triangle L (car matrice symetrique ) */ +for ( Kp = 0 ; Kp < Matrice->Rang ; Kp++ ) { + il = LdebParLigneDeU[Kp]; + ilMax = il + NbTermesParLigneDeU[Kp]; + ElmDeL[il] = 1.0; + X = ElmDeU[il]; + il++; + while ( il < ilMax ) { + ElmDeL[il] = ElmDeU[il] * X; + il++; + } +} + +FinRefactorisation: + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Matrice symetrique et pivotage diagonal */ + +void LU_RefactorisationSimulation( MATRICE * Matrice , char * Erreur , int NbElementsU ) +{ +int il; int ilMax; int Kp; int Kpp; int ic ; int ilDebKp; int iKp; +int ilMaxKp ; int IndexLibrePourLesAdresses; int IndexLibrePourLesNombres; +double ** Adresse; char * T; +int NbElementsAllouesPourLesAdresses; int NbElementsAllouesPourLesNombres; +int NbLignesQueKpModifie; int NbTermesParLigneQueKpModifie; +int Taille; int TailleMaxEnMegaOctets; int Disponible; +int Rang; +int * NbTermesParLigneDeU; int * DebutInfosAdressesQueKpModifie; int * DebutInfosLignesQueKpModifie; +int * LdebParLigneDeU; int * IndexKpDeUouL; int * InverseOrdreLigne; +int * NombreDeTermesParLigneQueKpModifie; int * NombreDeLignesQueKpModifie; +double * ElmDeU; double ** AdresseDeUModifie; double ** AdresseUHaut; double ** AdresseUGauche; + +/*printf(" LU_RefactorisationSimulation \n"); fflush(stdout);*/ + +Disponible = (int) (MemoireDisponible() / TAILLE_DU_MEGA_OCTET); + +TailleMaxEnMegaOctets = Disponible >> 1; +if ( TailleMaxEnMegaOctets < 10 ) TailleMaxEnMegaOctets = 10; + +*Erreur = NON_LU; + +Adresse = NULL; +T = NULL; +Adresse = (double **) malloc( Matrice->Rang * sizeof( void * ) ); +T = (char *) malloc( Matrice->Rang * sizeof( char ) ); +if ( T == NULL ) { + *Erreur = OUI_LU; + goto FinRefactorisationSimulation; +} +memset( T , 0 , Matrice->Rang * sizeof( char ) ); + +NbElementsAllouesPourLesAdresses = NbElementsU; +Matrice->DebutInfosAdressesQueKpModifie = (int *) malloc( Matrice->Rang * sizeof( int ) ); +Matrice->AdresseDeUModifie = (double **) malloc( NbElementsAllouesPourLesAdresses * sizeof( void * ) ); +Matrice->AdresseUHaut = (double **) malloc( NbElementsAllouesPourLesAdresses * sizeof( void * ) ); + +NbElementsAllouesPourLesNombres = Matrice->Rang; +Matrice->DebutInfosLignesQueKpModifie = (int *) malloc( Matrice->Rang * sizeof( int ) ); +Matrice->NombreDeLignesQueKpModifie = (int *) malloc( Matrice->Rang * sizeof( int ) ); +Matrice->AdresseUGauche = (double **) malloc( NbElementsAllouesPourLesNombres * sizeof( void * ) ); +Matrice->NombreDeTermesParLigneQueKpModifie = (int *) malloc( NbElementsAllouesPourLesNombres * sizeof( int ) ); + +if (Matrice->DebutInfosAdressesQueKpModifie == NULL || Matrice->AdresseDeUModifie == NULL || + Matrice->AdresseUHaut == NULL || Matrice->DebutInfosLignesQueKpModifie == NULL || + Matrice->NombreDeLignesQueKpModifie == NULL || Matrice->AdresseUGauche == NULL || + Matrice->NombreDeTermesParLigneQueKpModifie == NULL ) { + *Erreur = OUI_LU; + goto FinRefactorisationSimulation; +} + +/* Simulation de refactorisation */ +IndexLibrePourLesAdresses = 0; +IndexLibrePourLesNombres = 0; +Matrice->PremierKpParCalculClassique = Matrice->Rang + 1; + +/* Controle de taille */ +Taille = 3 * ( ( Matrice->Rang * sizeof( int ) / TAILLE_DU_MEGA_OCTET ) ); +Taille+= 2 * ( ( NbElementsAllouesPourLesAdresses * sizeof( void * ) / TAILLE_DU_MEGA_OCTET ) ); +Taille+= 2 * ( ( NbElementsAllouesPourLesNombres * sizeof( int ) / TAILLE_DU_MEGA_OCTET ) ); +if ( Taille > TailleMaxEnMegaOctets ) { + Matrice->PremierKpParCalculClassique = 0; + /* + printf("Fin par controle de taille a %d\n", Matrice->PremierKpParCalculClassique); + printf("Taille %d TailleMaxEnMegaOctets %d\n",Taille,TailleMaxEnMegaOctets); + */ + goto FinRefactorisationSimulation; +} + +Rang = Matrice->Rang; + +LdebParLigneDeU = Matrice->LdebParLigneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +IndexKpDeUouL = Matrice->IndexKpDeUouL; +ElmDeU = Matrice->ElmDeU; +InverseOrdreLigne = Matrice->InverseOrdreLigne; + +DebutInfosAdressesQueKpModifie = Matrice->DebutInfosAdressesQueKpModifie; +DebutInfosLignesQueKpModifie = Matrice->DebutInfosLignesQueKpModifie; +AdresseDeUModifie = Matrice->AdresseDeUModifie; +AdresseUHaut = Matrice->AdresseUHaut; +AdresseUGauche = Matrice->AdresseUGauche; +NombreDeLignesQueKpModifie = Matrice->NombreDeLignesQueKpModifie; +NombreDeTermesParLigneQueKpModifie = Matrice->NombreDeTermesParLigneQueKpModifie; + +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + + /* Si la matrice est pleine on arrete */ + if ( NbTermesParLigneDeU[Kp] >= Rang - Kp ) { + Matrice->PremierKpParCalculClassique = Kp; + /* + printf("Fin par matrice pleine a %d sur %d\n", Matrice->PremierKpParCalculClassique,Matrice->Rang); + */ + goto FinRefactorisationSimulation; + } + + DebutInfosAdressesQueKpModifie[Kp] = IndexLibrePourLesAdresses; + + DebutInfosLignesQueKpModifie[Kp] = IndexLibrePourLesNombres; + NbLignesQueKpModifie = 0; + + ilDebKp = LdebParLigneDeU[Kp]; + ilMaxKp = ilDebKp + NbTermesParLigneDeU[Kp]; + /* */ + /* Transfert de la ligne dans un tableau de travail, on ne modifie pas la colonne pivot */ + il = ilDebKp; + il++; + while ( il < ilMaxKp ) { + Adresse[IndexKpDeUouL[il]] = &(ElmDeU[il]); + T [IndexKpDeUouL[il]] = 1; + il++; + } + /* Maintenant on balaye toutes les lignes de la matrice active qui ont un terme non nul dans la colonne + pivot et on les compare a la ligne pivot */ + ic = ilDebKp; + ic++; /* Terme diagonal */ + while ( ic < ilMaxKp ) { + /* Scanner la ligne */ + /* Partie U en utilisant le chainage par colonne */ + Kpp = IndexKpDeUouL[ic]; + il = LdebParLigneDeU[Kpp]; + ilMax = il + NbTermesParLigneDeU[Kpp]; + /* Calcul des termes modifies */ + NbTermesParLigneQueKpModifie = 0; + while ( il < ilMax ) { + iKp = IndexKpDeUouL[il]; + if ( T[iKp] == 1 ) { + AdresseDeUModifie[IndexLibrePourLesAdresses] = &(ElmDeU[il]); + AdresseUHaut [IndexLibrePourLesAdresses] = Adresse[iKp]; + IndexLibrePourLesAdresses++; + NbTermesParLigneQueKpModifie++; + if ( IndexLibrePourLesAdresses >= NbElementsAllouesPourLesAdresses ) { + /* printf("realloc adresses Kp= %d\n",Kp); */ + NbElementsAllouesPourLesAdresses+= 2 * NbElementsU; + /* Controle de taille */ + Taille = 3 * ( ( Matrice->Rang * sizeof( int ) / TAILLE_DU_MEGA_OCTET ) ); + Taille+= 2 * ( ( NbElementsAllouesPourLesAdresses * sizeof( void * ) / TAILLE_DU_MEGA_OCTET ) ); + Taille+= 2 * ( ( NbElementsAllouesPourLesNombres * sizeof( int ) / TAILLE_DU_MEGA_OCTET ) ); + if ( Taille > TailleMaxEnMegaOctets ) { + Matrice->PremierKpParCalculClassique = Kp - 1; + /* + printf("Fin par controle de taille a %d sur %d TailleMaxEnMegaOctets %d\n", + Matrice->PremierKpParCalculClassique,Matrice->Rang,TailleMaxEnMegaOctets); + */ + goto FinRefactorisationSimulation; + } + Matrice->AdresseDeUModifie = (double **) realloc( AdresseDeUModifie , NbElementsAllouesPourLesAdresses * sizeof( void * ) ); + Matrice->AdresseUHaut = (double **) realloc( AdresseUHaut , NbElementsAllouesPourLesAdresses * sizeof( void * ) ); + AdresseDeUModifie = Matrice->AdresseDeUModifie; + AdresseUHaut = Matrice->AdresseUHaut; + } + } + il++; + } + AdresseUGauche [IndexLibrePourLesNombres] = &(ElmDeU[ic]); + NombreDeTermesParLigneQueKpModifie[IndexLibrePourLesNombres] = NbTermesParLigneQueKpModifie; + IndexLibrePourLesNombres++; + NbLignesQueKpModifie++; + if ( IndexLibrePourLesNombres >= NbElementsAllouesPourLesNombres ) { + /* printf("realloc nombres Kp= %d\n",Kp); */ + NbElementsAllouesPourLesNombres+= 5 * Matrice->Rang; + /* Controle de taille */ + Taille = 3 * ( ( Matrice->Rang * sizeof( int ) / TAILLE_DU_MEGA_OCTET ) ); + Taille+= 2 * ( ( NbElementsAllouesPourLesAdresses * sizeof( void * ) / TAILLE_DU_MEGA_OCTET ) ); + Taille+= 2 * ( ( NbElementsAllouesPourLesNombres * sizeof( int ) / TAILLE_DU_MEGA_OCTET ) ); + if ( Taille > TailleMaxEnMegaOctets ) { + Matrice->PremierKpParCalculClassique = Kp - 1; + /* + printf("Fin par controle de taille a %d sur %d TailleMaxEnMegaOctets %d\n", + Matrice->PremierKpParCalculClassique,Matrice->Rang,TailleMaxEnMegaOctets); + */ + goto FinRefactorisationSimulation; + } + Matrice->AdresseUGauche = + (double **) realloc( AdresseUGauche , NbElementsAllouesPourLesNombres * sizeof( void * ) ); + Matrice->NombreDeTermesParLigneQueKpModifie = + (int *) realloc( NombreDeTermesParLigneQueKpModifie , NbElementsAllouesPourLesNombres * sizeof( int ) ); + AdresseUGauche = Matrice->AdresseUGauche; + NombreDeTermesParLigneQueKpModifie = Matrice->NombreDeTermesParLigneQueKpModifie; + } + /* On passe au terme suivant de la colonne pivot */ + ic++; + } + + il = ilDebKp; + while ( il < ilMaxKp ) { + T[IndexKpDeUouL[il]] = 0; + il++; + } + + NombreDeLignesQueKpModifie[Kp] = NbLignesQueKpModifie; + +} + +FinRefactorisationSimulation: + +free( Adresse ); +free( T ); +Adresse = NULL; +T = NULL; + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_refactorisation_de_la_matrice.c b/src/ext/Sirius_Solver/simplexe/lu/lu_refactorisation_de_la_matrice.c new file mode 100644 index 0000000000..777cf37ef1 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_refactorisation_de_la_matrice.c @@ -0,0 +1,556 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Refactorisation de la matrice (l'ordre d'elimination + a deja ete calcule). Cas d'une matrice non symetrique. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_EliminationDUneLigneRefactorisationNonSymetrique_B( + int Kp, + int * LdebParLigneDeU, + int * NbTermesParLigneDeU, + int * IndiceColonneDeU, + double * ElmDeU, + int * CdebParColonneDeL, + int * NbTermesParColonneDeL, + int * IndiceLigneDeL, + double * ElmDeL, + int * InverseOrdreLigne, + int * InverseOrdreColonne, + double * W, + int Symetrie, + double PivotMin, + int * ProblemeDansLaRefactorisation + ) + +{ +int il; int il1; int il1Max; int ic; int ic1; int ic1Max; int KpU ; int KpL ; +double UnSurValeurDuPivot ; int LignePivot ; int ColonnePivot ; int ilMax; +double ValTermeColonnePivot ; int icMax; + +/* Transfert de la ligne dans un tableau de travail */ + +il1 = LdebParLigneDeU[Kp]; +/* Le terme pivot est deja range au debut de la ligne */ +ColonnePivot = IndiceColonneDeU[il1]; +il1Max = il1 + NbTermesParLigneDeU[Kp]; +il = il1; +while ( il < il1Max ) { + W[IndiceColonneDeU[il]] = ElmDeU[il]; + il++; +} + +/* Le terme pivot est deja range au debut de la ligne */ +if ( fabs( W[ColonnePivot] ) < PivotMin ) { + /* Pivot trop petit => on abandonne la refactorisation. Il vaut mieux relancer + une factorisation complete pour trouver des pivots mieux calibres */ + *ProblemeDansLaRefactorisation = OUI_LU; + return; +} + +UnSurValeurDuPivot = 1. / W[ColonnePivot]; +W[ColonnePivot] = 0.0; + +/* On met a jour les lignes du triangle U actif */ +ic = CdebParColonneDeL[Kp]; +/* Le terme pivot est deja range au debut de la colonne */ +LignePivot = IndiceLigneDeL[ic]; +ElmDeL[ic] = 1.; +icMax = ic + NbTermesParColonneDeL[Kp]; +ic++; +while ( ic < icMax ) { + /*Ligne = IndiceLigneDeL[ic];*/ + ValTermeColonnePivot = ElmDeL[ic] * UnSurValeurDuPivot; + ElmDeL[ic] = ValTermeColonnePivot; + KpU = InverseOrdreLigne[/*Ligne*/IndiceLigneDeL[ic]]; + /* On balaye la ligne du triangle U et on la met a jour */ + il = LdebParLigneDeU[KpU]; + ilMax = il + NbTermesParLigneDeU[KpU]; + while ( il < ilMax ) { + /* Calcul du terme modifie */ + ElmDeU[il]-= W[IndiceColonneDeU[il]] * ValTermeColonnePivot; + il++; + } + ic++; +} + +if ( Symetrie == NON_LU ) { + /* Si la structure est symetrique, pas besoin de remettre a 0 */ + il = il1; + while ( il < il1Max ) { + W[IndiceColonneDeU[il]] = 0.0; + il++;; + } +} + +/* On met a jour les lignes du triangle L actif */ +ic1 = CdebParColonneDeL[Kp]; +ic1Max = ic1 + NbTermesParColonneDeL[Kp]; +ic = ic1; +while ( ic < ic1Max ) { + W[IndiceLigneDeL[ic]] = ElmDeL[ic]; + ic++;; +} +W[LignePivot] = 0.0; + +/* On met a jour les colonnes du triangle L actif */ +il = LdebParLigneDeU[Kp]; +ElmDeU[il] = UnSurValeurDuPivot; +ilMax = il + NbTermesParLigneDeU[Kp]; +il++; +while ( il < ilMax ) { + /*Colonne = IndiceColonneDeU[il];*/ + ValTermeColonnePivot = ElmDeU[il]; + KpL = InverseOrdreColonne[/*Colonne*/IndiceColonneDeU[il]]; + ic = CdebParColonneDeL[KpL]; + icMax = ic + NbTermesParColonneDeL[KpL]; + while ( ic < icMax ) { + /* Calcul du terme modifie */ + ElmDeL[ic]-= W[IndiceLigneDeL[ic]] * ValTermeColonnePivot; + ic++; + } + il++; +} + +ic = ic1; +while ( ic < ic1Max ) { + W[IndiceLigneDeL[ic]] = 0.0; + ic++;; +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* On recopie la matrice d'entree dans les triangles L et U */ + +void LU_InitTrianglesRefactorisationNonSymetrique( MATRICE * Matrice, + double * ValeurDesTermesDeLaMatrice, + int * IndicesDeLigne , + int * Ideb, + int * NbTermesDesColonnes, + int * ProblemeDansLaRefactorisation + ) +{ +int Ligne; int Colonne; int Kp ; int il ; int ilMax ; int ic1 ; int ic1Max; +int ic ; int icSV ; int icMax; double * W; int NbElements; int Rang; int il1 ; + +int * Ldeb ; int * Lsui ; int * Lcol; char Symetrie; char FaireScaling; +double * ScaleX ; double * ScaleB; double ScX ; double ScB ; int k; + +int * LdebParLigneDeU ; int * NbTermesParLigneDeU ; int * IndiceColonneDeU; double * ElmDeU; +int * CdebParColonneDeL; int * NbTermesParColonneDeL; int * IndiceLigneDeL ; double * ElmDeL; + +FaireScaling = Matrice->FaireScaling; +ScaleX = Matrice->ScaleX; +ScaleB = Matrice->ScaleB; + +Symetrie = NON_LU; +if ( Matrice->LaMatriceEstSymetriqueEnStructure == OUI_LU || + Matrice->LaMatriceEstSymetrique == OUI_LU ) { + Symetrie = OUI_LU; +} + +Rang = Matrice->Rang; + +NbElements = Matrice->NombreDeTermesDeLaMatriceAFactoriser; + +/* Stockage par lignes de la matrice */ +Ldeb = (int *) malloc( Rang * sizeof( int ) ); +Lsui = (int *) malloc( NbElements * sizeof( int ) ); +Lcol = (int *) malloc( NbElements * sizeof( int ) ); +if ( Ldeb == NULL || Lsui == NULL || Lcol == NULL ) { + free( Ldeb ); free( Lsui ); free( Lcol ); + printf("Refactorisation LU: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + *ProblemeDansLaRefactorisation = (int) OUI_LU; + return; +} +for ( il = 0 ; il < Rang ; il++ ) Ldeb[il] = -1; + +for ( Colonne = 0 ; Colonne < Rang ; Colonne++ ) { + ic = Ideb[Colonne]; + icMax = ic + NbTermesDesColonnes[Colonne]; + while ( ic < icMax ) { + Ligne = IndicesDeLigne[ic]; + icSV = Ldeb[Ligne]; + Ldeb[Ligne] = ic; + Lcol[ic] = Colonne; + Lsui[ic] = icSV; + /* */ + ic++; + } +} + +W = Matrice->SolutionIntermediaire; +memset( W , 0 , Rang * sizeof( double ) ); + +LdebParLigneDeU = Matrice->LdebParLigneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; +ElmDeU = Matrice->ElmDeU; + +CdebParColonneDeL = Matrice->CdebParColonneDeL; +NbTermesParColonneDeL = Matrice->NbTermesParColonneDeL; +IndiceLigneDeL = Matrice->IndiceLigneDeL; +ElmDeL = Matrice->ElmDeL; + +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + /* 1- Triangle U */ + /* L'indice ligne du premier terme du triangle L nous donne la ligne a recopier + dans U */ + Ligne = IndiceLigneDeL[CdebParColonneDeL[Kp]]; + il1 = Ldeb[Ligne]; + il = il1; + if ( FaireScaling != OUI_LU ) { + while ( il >= 0 ) { + W[Lcol[il]] = ValeurDesTermesDeLaMatrice[il]; + il = Lsui[il]; + } + } + else { + /* Cas du scaling */ + ScB = ScaleB[Ligne]; + while ( il >= 0 ) { + k = Lcol[il]; + W[k] = ValeurDesTermesDeLaMatrice[il] * ScaleX[k] * ScB; + il = Lsui[il]; + } + } + /* Initialisation du triangle U */ + il = LdebParLigneDeU[Kp]; + ilMax = il + NbTermesParLigneDeU[Kp]; + while ( il < ilMax ) { + ElmDeU[il] = W[IndiceColonneDeU[il]]; + il++; + } + /* Raz de W pour la suite */ + + if ( Symetrie == NON_LU ) { + /* Si la structure est symetrique, pas besoin de remettre a 0 */ + il = il1; + while ( il >= 0 ) { + W[Lcol[il]] = 0.0; + il = Lsui[il]; + } + } + /* 2- Triangle L */ + /* L'indice colonne du premier terme du triangle U nous donne la colonne a recopier + dans L */ + Colonne = IndiceColonneDeU[LdebParLigneDeU[Kp]]; + ic1 = Ideb[Colonne]; + ic1Max = ic1 + NbTermesDesColonnes[Colonne]; + ic = ic1; + if ( FaireScaling != OUI_LU ) { + while ( ic ValeurDesTermesDeLaMatrice; +IndicesDeLigne = Mat->IndicesDeLigne; +Ideb = Mat->IndexDebutDesColonnes; +NbTermesDesColonnes = Mat->NbTermesDesColonnes; +/*----------------------------------------------------------------------------------------------------*/ + +ProblemeDansLaRefactorisation = NON_LU; + +X = (double) ( Matrice->IndexLibreDeL + Matrice->IndexLibreDeU ) / (double) ( Matrice->Rang * Matrice->Rang ); +/* Attention. Maintenant dans le cas LU_GENERAL, on resout le triangle U en utilisant le stockage + de U par colonne. Comme la refactorisation autre que RefactorisationLL ne met a jour que le stockage + de U par ligne, il n'est pas souhaitable de l'utiliser ou alors il faudrait tenir compte du type + de refactorisation disponible au moment de la resolution. Pour l'instant il semble preferable de + ne pas compliquer les choses. Le cas echeant on pourra prevoir un indicateur permettant de choisir + le type de stockage a untiliser lors des resolutions */ + +if ( X < 0.03 /*&& Matrice->FaireDuPivotageDiagonal == OUI_LU*/ || 1 ) { + LU_RefactorisationLL( Matrice, ValeurDesTermesDeLaMatrice, IndicesDeLigne , + Ideb, NbTermesDesColonnes, &ProblemeDansLaRefactorisation ); + Mat->ProblemeDeFactorisation = ProblemeDansLaRefactorisation; + return; +} + +LU_InitTrianglesRefactorisationNonSymetrique( Matrice, ValeurDesTermesDeLaMatrice, IndicesDeLigne , + Ideb, NbTermesDesColonnes, &ProblemeDansLaRefactorisation ); +if ( ProblemeDansLaRefactorisation == OUI_LU ) goto FinRefactorisation; + +Symetrie = NON_LU; +if ( Matrice->LaMatriceEstSymetriqueEnStructure == OUI_LU || + Matrice->LaMatriceEstSymetrique == OUI_LU ) { + Symetrie = OUI_LU; +} +PivotMin = Matrice->PivotMin; +W = Matrice->SolutionIntermediaire; +LdebParLigneDeU = Matrice->LdebParLigneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; +ElmDeU = Matrice->ElmDeU; +CdebParColonneDeL = Matrice->CdebParColonneDeL; +NbTermesParColonneDeL = Matrice->NbTermesParColonneDeL; +IndiceLigneDeL = Matrice->IndiceLigneDeL; +ElmDeL = Matrice->ElmDeL; +InverseOrdreLigne = Matrice->InverseOrdreLigne; +InverseOrdreColonne = Matrice->InverseOrdreColonne; + +for ( Kp = 0 ; Kp < Matrice->Rang ; Kp++ ) { + LU_EliminationDUneLigneRefactorisationNonSymetrique_B( Kp, LdebParLigneDeU, NbTermesParLigneDeU, IndiceColonneDeU, ElmDeU, + CdebParColonneDeL, NbTermesParColonneDeL, IndiceLigneDeL, ElmDeL, + InverseOrdreLigne, InverseOrdreColonne, W, Symetrie, PivotMin, + &ProblemeDansLaRefactorisation ); + if ( ProblemeDansLaRefactorisation == OUI_LU ) goto FinRefactorisation; +} + +FinRefactorisation: +Mat->ProblemeDeFactorisation = ProblemeDansLaRefactorisation; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* On fait pareil qu'en symetrique car ça fonctionne aussi */ + +void LU_RefactorisationSymetrique( MATRICE * Matrice , /* Pointeur sur l'objet matrice qui a deja + ete factorise (c'est le pointeur retourne + par LU_Factorisation */ + MATRICE_A_FACTORISER * Mat /* Contient les nouvelles valeurs numeriques + de la matrice a refactoriser */ + ) +{ + +LU_RefactorisationNonSymetrique( Matrice , Mat ); + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_RefactorisationLL( MATRICE * Matrice, + double * ValeurDesTermesDeLaMatrice, + int * IndicesDeLigne, + int * Ideb, + int * NbTermesDesColonnes, + int * ProblemeDansLaRefactorisation + ) +{ +int Ligne; int Colonne; int Kp; int il; int ilMax; int icDeb; int ic; int icMax; int Rang; double Pivot; +/*int Kpp;*/ double X; double PivotMin; double * SecondMembre; +int * CdebParColonneDeL; int * NbTermesParColonneDeL; int * IndiceLigneDeL ; double * ElmDeL; +int * CdebParColonneDeU; int * IndiceLigneParColonneDeU; int * NbTermesParColonneDeU; double * ElmDeUParColonne; +/*int * InverseOrdreColonne;*/ int * OrdreColonne; int * InverseOrdreLigne; int * OrdreLigne; +char FaireScaling; double * ScaleX; double * ScaleB; double ScX; + +FaireScaling = Matrice->FaireScaling; +ScaleX = Matrice->ScaleX; +ScaleB = Matrice->ScaleB; + +Rang = Matrice->Rang; +PivotMin = Matrice->PivotMin; + +CdebParColonneDeL = Matrice->CdebParColonneDeL; +NbTermesParColonneDeL = Matrice->NbTermesParColonneDeL; +IndiceLigneDeL = Matrice->IndiceLigneDeL; +ElmDeL = Matrice->ElmDeL; + +CdebParColonneDeU = Matrice->CdebParColonneDeU; +IndiceLigneParColonneDeU = Matrice->IndiceLigneParColonneDeU; +NbTermesParColonneDeU = Matrice->NbTermesParColonneDeU; +ElmDeUParColonne = Matrice->ElmDeUParColonne; + +/* On resout le triangle L avec les colonnes de la matrice d'entree */ +SecondMembre = Matrice->SolutionIntermediaire; + +/*InverseOrdreColonne = Matrice->InverseOrdreColonne;*/ +OrdreColonne = Matrice->OrdreColonne; + +InverseOrdreLigne = Matrice->InverseOrdreLigne; +OrdreLigne = Matrice->OrdreLigne; + +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + /* Colonne de la matrice d'entree a utiliser */ + Colonne = OrdreColonne[Kp]; + if ( FaireScaling != OUI_LU ) { + ic = Ideb[Colonne]; + icMax = ic + NbTermesDesColonnes[Colonne]; + while ( ic < icMax ) { + SecondMembre[IndicesDeLigne[ic]] = ValeurDesTermesDeLaMatrice[ic]; + ic++; + } + } + else { + ScX = ScaleX[Colonne]; + ic = Ideb[Colonne]; + icMax = ic + NbTermesDesColonnes[Colonne]; + while ( ic < icMax ) { + Ligne = IndicesDeLigne[ic]; + SecondMembre[Ligne] = ValeurDesTermesDeLaMatrice[ic] * ScaleB[Ligne] * ScX; + ic++; + } + } + + /* On met les colonnes du triangle U: le premier terme est le terme diagonal, les termes du triangle U sont + stockes dans l'ordre decroissant de Kp */ + icDeb = CdebParColonneDeU[Kp]; + ic = icDeb + NbTermesParColonneDeU[Kp] - 1; + while ( ic > icDeb ) { + Ligne = /*OrdreColonne*/OrdreLigne[IndiceLigneParColonneDeU[ic]]; + /* Le pivot vaut 1 */ + X = SecondMembre[Ligne]; + /* A ce stade on peut ranger X dans le triangle U */ + SecondMembre[Ligne] = 0.0; + ElmDeUParColonne[ic] = X; + if ( X != 0.0 ) { + /* + Kpp = InverseOrdreColonne[Ligne]; + il = CdebParColonneDeL[Kpp]; + ilMax = il + NbTermesParColonneDeL[Kpp]; + */ + il = CdebParColonneDeL[/*InverseOrdreColonne*/InverseOrdreLigne[Ligne]]; + ilMax = il + NbTermesParColonneDeL[/*InverseOrdreColonne*/InverseOrdreLigne[Ligne]]; + il++; + while ( il < ilMax ) { + SecondMembre[IndiceLigneDeL[il]] -= ElmDeL[il] * X; + il++; + } + } + ic--; + } + /* En ce qui concerne le triangle L on n'a rien a faire car le resultat se trouve deja dans SecondMembre */ + /* On divise la colonne par le pivot */ + ic = CdebParColonneDeL[Kp]; + Ligne = IndiceLigneDeL[ic /*CdebParColonneDeL[Kp]*/ ]; + Pivot = SecondMembre[Ligne]; + SecondMembre[Ligne] = 0.0; + if ( fabs( Pivot ) < PivotMin ) { + printf("Pivot nul dans la refactorisation: Pivot %e PivotMin %e\n",Pivot,PivotMin); + *ProblemeDansLaRefactorisation = (int) OUI_LU; + return; + } + Pivot = 1. / Pivot; + ElmDeUParColonne[icDeb] = Pivot; + + /* On met la colonne dans le triangle */ + /* ic = CdebParColonneDeL[Kp]; */ + icMax = ic + NbTermesParColonneDeL[Kp]; + /*ElmDeL[ic] = 1.;*/ + ic++; + while ( ic < icMax ) { + /* + Ligne = IndiceLigneDeL[ic]; + ElmDeL[ic] = SecondMembre[Ligne] * Pivot; + SecondMembre[Ligne] = 0.0; + */ + ElmDeL[ic] = SecondMembre[IndiceLigneDeL[ic]] * Pivot; + SecondMembre[IndiceLigneDeL[ic]] = 0.0; + ic++; + } +} + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_reorganisation_chainages.c b/src/ext/Sirius_Solver/simplexe/lu/lu_reorganisation_chainages.c new file mode 100644 index 0000000000..21126ce229 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_reorganisation_chainages.c @@ -0,0 +1,561 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Reorganisation des chainages en fin de factorisation. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ +/* Chainage par ligne du triangle U */ +/* Le triangle U se trouve stocke par ligne dans la matrice active */ +/* On se contente d'un chainage dans l'ordre d'elimination */ +/*--------------------------------------------------------------------------------------------------*/ +void LU_ChainageParLigneDeULUGeneral( MATRICE * Matrice ) +{ +int Ligne;int Kp; int * LdebParLigneDeU; int * NbTermesParLigneDeU; int * IndiceColonneDeU; double * ElmDeU; +int * Ldeb; int * LNbTerm; int * LIndiceColonne; double * Elm; int * OrdreLigne; + +Matrice->DernierIndexLibreDeU = Matrice->IndexLibreDeU; + +Matrice->NbTermesParLigneDeU = Matrice->LignePrecedente; +Matrice->LdebParLigneDeU = Matrice->LigneSuivante; + +Matrice->ElmDeU = Matrice->Elm; +Matrice->IndiceColonneDeU = Matrice->LIndiceColonne; + +LdebParLigneDeU = Matrice->LdebParLigneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +ElmDeU = Matrice->ElmDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +Elm = Matrice->Elm; +LIndiceColonne = Matrice->LIndiceColonne; + +OrdreLigne = Matrice->OrdreLigne; + +for ( Kp = 0 ; Kp < Matrice->Rang ; Kp++ ) { + Ligne = OrdreLigne[Kp]; + LdebParLigneDeU [Kp] = Ldeb[Ligne]; + NbTermesParLigneDeU[Kp] = LNbTerm[Ligne]; +} + +return; +} +/*--------------------------------------------------------------------------------------------------*/ +/* Chainage par ligne du triangle U */ +/* Le triangle U se trouve stocke par ligne dans la matrice active */ +/*--------------------------------------------------------------------------------------------------*/ + +void LU_ChainageParLigneDeU( MATRICE * Matrice ) +{ +int NbTrm_U; int Ligne; int il; int Nb; int ilNew; int Kp; +int * LdebParLigneDeU; int * NbTermesParLigneDeU; int * IndiceColonneDeU; double * ElmDeU; +int * Ldeb; int * LNbTerm; int * LIndiceColonne; double * Elm; +int * OrdreLigne; + +NbTrm_U = Matrice->IndexLibreDeU + 10; +Matrice->DernierIndexLibreDeU = NbTrm_U; + +Matrice->NbTermesParLigneDeU = Matrice->LignePrecedente; +Matrice->LdebParLigneDeU = Matrice->LigneSuivante; + +Matrice->ElmDeU = (double *) malloc( NbTrm_U * sizeof( double ) ); +Matrice->IndiceColonneDeU = (int *) malloc( NbTrm_U * sizeof( int ) ); + +if ( Matrice->ElmDeU == NULL || Matrice->IndiceColonneDeU == NULL ) { + printf("Factorisation LU, sous-programme LU_ChainageParLigneDeU: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} + +LdebParLigneDeU = Matrice->LdebParLigneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +ElmDeU = Matrice->ElmDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +Elm = Matrice->Elm; +LIndiceColonne = Matrice->LIndiceColonne; + +OrdreLigne = Matrice->OrdreLigne; + +ilNew = 0; +for ( Kp = 0 ; Kp < Matrice->Rang ; Kp++ ) { + Ligne = OrdreLigne[Kp]; + il = Ldeb[Ligne]; + Nb = LNbTerm[Ligne]; + LdebParLigneDeU [Kp] = ilNew; + NbTermesParLigneDeU[Kp] = Nb; + memcpy( (char *) &(IndiceColonneDeU[ilNew]), (char *) &(LIndiceColonne[il]), Nb * sizeof( int ) ); + memcpy( (char *) &(ElmDeU[ilNew]) , (char *) &(Elm[il]) , Nb * sizeof( double ) ); + ilNew += Nb; +} +Matrice->IndexLibreDeU = ilNew; +Matrice->DernierIndexLibreDeU = ilNew; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Classement des lignes de U et des colonnes de U dans l'ordre croissant de l'elimination */ +/* ordonnee. Le premier terme de chaque ligne ou colonne sera automatiquement le terme pivot. */ + +void LU_StockageDeUDansLOrdreCroissantDesIndices( MATRICE * Matrice ) +{ +int ilDeb; int ilMax; int il; int IndiceColonne; double X; char OnInverse; int Kp; int Rang; +int * LdebParLigneDeU; int * NbTermesParLigneDeU; int * IndiceColonneDeU ; int * IndiceLigneDeL; +double * ElmDeU ; double * ElmDeL ; int * InverseOrdreColonne; int * IndexKpDeUouL ; +int NbTermesDeU ; int iKp; + +NbTermesDeU = Matrice->IndexLibreDeU; +Matrice->IndexKpDeUouL = (int *) malloc( NbTermesDeU * sizeof( int ) ); +if ( Matrice->IndexKpDeUouL == NULL ) { + printf("Factorisation LU, sous-programme LU_StockageDeUDansLOrdreCroissantDesIndices: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} + +Rang = Matrice->Rang; + +LdebParLigneDeU = Matrice->LdebParLigneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; +ElmDeU = Matrice->ElmDeU; +IndiceLigneDeL = Matrice->IndiceLigneDeL; +ElmDeL = Matrice->ElmDeL; +IndexKpDeUouL = Matrice->IndexKpDeUouL; + +InverseOrdreColonne = Matrice->InverseOrdreColonne; + +for ( il = 0 ; il < NbTermesDeU ; il++ ) { + IndexKpDeUouL[il] = InverseOrdreColonne[IndiceColonneDeU[il]]; +} + +/* Classement des lignes de U et des colonnes de U dans l'ordre croissant de indices */ +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + /* Triangle U */ + ilDeb = LdebParLigneDeU[Kp]; + ilMax = ilDeb + NbTermesParLigneDeU[Kp]; + ilMax--; + ilDeb++; + OnInverse = OUI_LU; + while ( OnInverse == OUI_LU ) { + OnInverse = NON_LU; + il = ilDeb; + while ( il < ilMax ) { + if ( IndexKpDeUouL[il] > IndexKpDeUouL[il+1] ) { + OnInverse = OUI_LU; + IndiceColonne = IndiceColonneDeU[il+1]; + iKp = IndexKpDeUouL[il+1]; + X = ElmDeU[il+1]; + IndiceColonneDeU[il+1] = IndiceColonneDeU[il]; + IndexKpDeUouL [il+1] = IndexKpDeUouL[il]; + ElmDeU [il+1] = ElmDeU[il]; + IndiceColonneDeU[il] = IndiceColonne; + IndexKpDeUouL [il] = iKp; + ElmDeU [il] = X; + } + il++; + } + } +} +/* Recopie du triangle U dans le triangle L (car matrice symetrique ) */ +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + il = LdebParLigneDeU[Kp]; + ilMax = il + NbTermesParLigneDeU[Kp]; + ElmDeL[il] = 1.0; + X = ElmDeU[il]; + il++; + while ( il < ilMax ) { + /* Calcul du terme modifie */ + ElmDeL[il] = ElmDeU[il] * X; + IndiceLigneDeL[il] = IndiceColonneDeU[il]; + il++; + } +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Chainage par colonne du triangle U */ +/* C'est en particulier utilise par la LU update */ + +void LU_ChainageParColonneDeU( MATRICE * Matrice ) +{ +int i; int il; int ilMax; int ilC; int Rang; int Kp; int Nb; double * ElmDeU; +int * OrdreUcolonne ; int KpColonne; int * NbTermesParLigneDeU ; +int * StockageColonneVersLigneDeU; int * LdebParLigneDeU ; double * ElmDeUParColonne ; +int * StockageLigneVersColonneDeU; int * CapaciteParColonneDeU; int * IndiceColonneDeU ; +int * InverseOrdreColonne ; int * CdebParColonneDeU ; int * NbTermesParColonneDeU; +int * IndiceLigneParColonneDeU ; int * CapaciteParLigneDeU ; char ContexteDeLaFactorisation; + +/* Cette routine peut etre appelee par l'estimation d'etat (Sylvain), qui veut aussi avoir un + un chainage par colonne de U. Cependant, suite a des modifs d'architecture de la LU, ce + chainage de U par colonne est deja disponible */ +if ( Matrice->ContexteDeLaFactorisation == LU_GENERAL ) { + return; +} + +ContexteDeLaFactorisation = Matrice->ContexteDeLaFactorisation; +Rang = Matrice->Rang; + +/* Pour avoir une marge disponible pour l'update de la LU */ +i = Matrice->IndexLibreDeU + ( 2 * INCREMENT_DALLOCATION_DE_U ); +Matrice->DernierIndexLibreDeUParColonne = i - 1; + +/* Limite au nombre d'Update avant refactorisation */ +/*Matrice->LimiteUpdatePourRefactorisation = Matrice->DernierIndexLibreDeUParColonne << 2;*/ +Matrice->LimiteUpdatePourRefactorisation = Matrice->DernierIndexLibreDeUParColonne * 10; +Matrice->CdebParColonneDeU = Matrice->ColonnePrecedente; +Matrice->NbTermesParColonneDeU = Matrice->ColonneSuivante; + +i = Matrice->DernierIndexLibreDeUParColonne + 1; +Matrice->IndiceLigneParColonneDeU = (int *) malloc( i * sizeof( int ) ); +Matrice->StockageColonneVersLigneDeU = (int *) malloc( i * sizeof( int ) ); +Matrice->ElmDeUParColonne = (double *) malloc( i * sizeof( double ) ); + +i = Matrice->DernierIndexLibreDeU + 1; +Matrice->StockageLigneVersColonneDeU = (int *) malloc( i * sizeof( int ) ); + +Matrice->CapaciteParLigneDeU = (int *) malloc( Rang * sizeof( int ) ); +Matrice->CapaciteParColonneDeU = (int *) malloc( Rang * sizeof( int ) ); + +Matrice->OrdreUcolonne = (int *) malloc( Rang * sizeof( int ) ); +Matrice->InverseOrdreUcolonne = (int *) malloc( Rang * sizeof( int ) ); + +if ( Matrice->IndiceLigneParColonneDeU == NULL || + Matrice->StockageColonneVersLigneDeU == NULL || Matrice->ElmDeUParColonne == NULL || + Matrice->StockageLigneVersColonneDeU == NULL || Matrice->CapaciteParLigneDeU == NULL || + Matrice->CapaciteParColonneDeU == NULL || Matrice->OrdreUcolonne == NULL || + Matrice->InverseOrdreUcolonne == NULL ) { + + printf("Factorisation LU, sous-programme LU_ChainageParColonneDeU: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} + +OrdreUcolonne = Matrice->OrdreUcolonne; +for ( i = 0 ; i < Rang ; i++ ) OrdreUcolonne[i] = i; +memcpy( (char *) Matrice->InverseOrdreUcolonne, (char *) OrdreUcolonne, Rang * sizeof( int ) ); + +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +CapaciteParLigneDeU = Matrice->CapaciteParLigneDeU; +LdebParLigneDeU = Matrice->LdebParLigneDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; +ElmDeU = Matrice->ElmDeU; +InverseOrdreColonne = Matrice->InverseOrdreColonne; + +CdebParColonneDeU = Matrice->CdebParColonneDeU; +NbTermesParColonneDeU = Matrice->NbTermesParColonneDeU; +IndiceLigneParColonneDeU = Matrice->IndiceLigneParColonneDeU; +ElmDeUParColonne = Matrice->ElmDeUParColonne; + +StockageColonneVersLigneDeU = Matrice->StockageColonneVersLigneDeU; +StockageLigneVersColonneDeU = Matrice->StockageLigneVersColonneDeU; +CapaciteParColonneDeU = Matrice->CapaciteParColonneDeU; + +memset( (char *) NbTermesParColonneDeU, 0, Rang * sizeof( int ) ); +memset( (char *) CapaciteParColonneDeU, 0, Rang * sizeof( int ) ); + +/* On balaye les lignes de U pour compter les termes dans la colonne */ +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + Nb = NbTermesParLigneDeU[Kp]; + CapaciteParLigneDeU[Kp] = Nb; + il = LdebParLigneDeU[Kp]; + ilMax = il + Nb; + while ( il < ilMax ) { + NbTermesParColonneDeU[InverseOrdreColonne[IndiceColonneDeU[il]]]++; + il++; + } +} +/* Initialisation de l'index debut des colonnes */ +ilC = 0; +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + CdebParColonneDeU[Kp] = ilC; + ilC += NbTermesParColonneDeU[Kp]; + NbTermesParColonneDeU[Kp] = 0; +} +Matrice->IndexLibreDeUParColonne = ilC; + +/* En balayant Kp a l'envers, le terme pivot de chaque colonne se retrouve automatiquement au debut */ +for ( Kp = Rang - 1 ; Kp >= 0 ; Kp-- ) { + il = LdebParLigneDeU[Kp]; + ilMax = il + NbTermesParLigneDeU[Kp]; + while ( il < ilMax ) { + KpColonne = InverseOrdreColonne[IndiceColonneDeU[il]]; + /* Automatiquement range dans l'ordre decroissant de Kp */ + ilC = CdebParColonneDeU[KpColonne] + NbTermesParColonneDeU[KpColonne]; + IndiceLigneParColonneDeU[ilC] = Kp; + + StockageColonneVersLigneDeU[ilC] = il; + StockageLigneVersColonneDeU[il] = ilC; + + ElmDeUParColonne[ilC] = ElmDeU[il]; + + NbTermesParColonneDeU[KpColonne]++; + CapaciteParColonneDeU[KpColonne]++; + il++; + } +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Chainage par colonne du triangle U hors simplexe */ +/* (le stockage definitif de U par ligne est suppose disponible) */ + +void LU_ChainageParColonneDeUHorsSimplexe( MATRICE * Matrice ) +{ +int il; int ilMax; int ilC; int Rang; int Kp; int KpColonne; int NbTrm_U; +int * LdebParLigneDeU; int * NbTermesParLigneDeU; double * ElmDeU; int * IndiceColonneDeU; +int * CdebParColonneDeU; int * NbTermesParColonneDeU; double * ElmDeUParColonne; int * IndiceLigneParColonneDeU; +int * InverseOrdreColonne; + +/*if ( Matrice->ContexteDeLaFactorisation != LU_SIMPLEXE ) return;*/ + +Rang = Matrice->Rang; + +NbTrm_U = Matrice->IndexLibreDeU + 10; +Matrice->DernierIndexLibreDeU = NbTrm_U; + +Matrice->CdebParColonneDeU = Matrice->ColonnePrecedente; +Matrice->NbTermesParColonneDeU = Matrice->ColonneSuivante; + +Matrice->ElmDeUParColonne = (double *) malloc( NbTrm_U * sizeof( double ) ); +Matrice->IndiceLigneParColonneDeU = (int *) malloc( NbTrm_U * sizeof( int ) ); + +if ( Matrice->ElmDeUParColonne == NULL || Matrice->IndiceLigneParColonneDeU == NULL ) { + printf("Factorisation LU, sous-programme LU_ChainageParColonneDeUHorsSimplexe: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} + +CdebParColonneDeU = Matrice->CdebParColonneDeU; +NbTermesParColonneDeU = Matrice->NbTermesParColonneDeU; +ElmDeUParColonne = Matrice->ElmDeUParColonne; +IndiceLigneParColonneDeU = Matrice->IndiceLigneParColonneDeU; + +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +LdebParLigneDeU = Matrice->LdebParLigneDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; +ElmDeU = Matrice->ElmDeU; +InverseOrdreColonne = Matrice->InverseOrdreColonne; + +memset( (char *) NbTermesParColonneDeU, 0, Rang * sizeof( int ) ); + +/* On balaye les lignes de U pour compter les termes dans la colonne */ +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + il = LdebParLigneDeU[Kp]; + ilMax = il + NbTermesParLigneDeU[Kp]; + while ( il < ilMax ) { + NbTermesParColonneDeU[InverseOrdreColonne[IndiceColonneDeU[il]]]++; + il++; + } +} +/* Initialisation de l'index debut des colonnes */ +ilC = 0; +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + CdebParColonneDeU[Kp] = ilC; + ilC += NbTermesParColonneDeU[Kp]; + NbTermesParColonneDeU[Kp] = 0; +} + +/* En balayant Kp a l'envers, le terme pivot de chaque colonne se retrouve automatiquement au debut */ +for ( Kp = Rang - 1 ; Kp >= 0 ; Kp-- ) { + il = LdebParLigneDeU[Kp]; + ilMax = il + NbTermesParLigneDeU[Kp]; + while ( il < ilMax ) { + KpColonne = InverseOrdreColonne[IndiceColonneDeU[il]]; + /* Automatiquement range dans l'ordre decroissant de Kp */ + ilC = CdebParColonneDeU[KpColonne] + NbTermesParColonneDeU[KpColonne]; + IndiceLigneParColonneDeU[ilC] = Kp; + ElmDeUParColonne[ilC] = ElmDeU[il]; + NbTermesParColonneDeU[KpColonne]++; + il++; + } +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Chainage de L par ligne pour la resolution transpose */ + +void LU_ChainageParLigneDeL( MATRICE * Matrice, char * AllocOk ) +{ +int i; int il; int ilMax; int ilL; int Rang; int KpLigne; int Kp; +int * InverseOrdreLigne; int * LdebParLigneDeL ; int * NbTermesParLigneDeL; +double * ElmDeLParLigne; int * CdebParColonneDeL ; int * IndiceColonneParLigneDeL; +int * NbTermesParColonneDeL ; int * IndiceLigneDeL; double * ElmDeL; + +/*if ( Matrice->ContexteDeLaFactorisation != LU_SIMPLEXE ) return;*/ + +*AllocOk = OUI_LU; + +Rang = Matrice->Rang; + +/* Pour avoir une marge disponible pour l'update de la LU */ +i = Matrice->IndexLibreDeL + 1; + +Matrice->LdebParLigneDeL = (int *) malloc( Rang * sizeof( int ) ); +Matrice->NbTermesParLigneDeL = (int *) malloc( Rang * sizeof( int ) ); +Matrice->IndiceColonneParLigneDeL = (int *) malloc( i * sizeof( int ) ); +Matrice->ElmDeLParLigne = (double *) malloc( i * sizeof( double ) ); + +if ( Matrice->LdebParLigneDeL == NULL || Matrice->NbTermesParLigneDeL == NULL || + Matrice->IndiceColonneParLigneDeL == NULL || Matrice->ElmDeLParLigne == NULL + ) { + printf("Factorisation LU, sous-programme LU_ChainageParColonneDeU: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + if ( Matrice->LdebParLigneDeL != NULL ) free( Matrice->LdebParLigneDeL ); + if ( Matrice->NbTermesParLigneDeL != NULL ) free( Matrice->NbTermesParLigneDeL ); + if ( Matrice->IndiceColonneParLigneDeL != NULL ) free( Matrice->IndiceColonneParLigneDeL ); + if ( Matrice->ElmDeLParLigne != NULL ) free( Matrice->ElmDeLParLigne ); + *AllocOk = NON_LU; + return; + /* + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); + */ +} + +CdebParColonneDeL = Matrice->CdebParColonneDeL; +NbTermesParColonneDeL = Matrice->NbTermesParColonneDeL; +IndiceLigneDeL = Matrice->IndiceLigneDeL; + +InverseOrdreLigne = Matrice->InverseOrdreLigne; + +ElmDeLParLigne = Matrice->ElmDeLParLigne; +ElmDeL = Matrice->ElmDeL; + +LdebParLigneDeL = Matrice->LdebParLigneDeL; +NbTermesParLigneDeL = Matrice->NbTermesParLigneDeL; +IndiceColonneParLigneDeL = Matrice->IndiceColonneParLigneDeL ; +ElmDeLParLigne = Matrice->ElmDeLParLigne ; + +memset( (char *) NbTermesParLigneDeL, 0, Rang * sizeof( int ) ); + +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + il = CdebParColonneDeL[Kp]; + ilMax = il + NbTermesParColonneDeL[Kp]; + while ( il < ilMax ) { + NbTermesParLigneDeL[InverseOrdreLigne[IndiceLigneDeL[il]]]++; + il++; + } +} +/* Initialisation de l'index debut des lignes */ +ilL = 0; +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + LdebParLigneDeL[Kp] = ilL; + ilL += NbTermesParLigneDeL[Kp]; + NbTermesParLigneDeL[Kp] = 0; +} + +/* En balayant Kp a l'envers, le terme pivot de chaque colonne se retrouve automatiquement au debut */ +for ( Kp = Rang - 1 ; Kp >= 0 ; Kp-- ) { + il = CdebParColonneDeL[Kp]; + ilMax = il + NbTermesParColonneDeL[Kp]; + while ( il < ilMax ) { + KpLigne = InverseOrdreLigne[IndiceLigneDeL[il]]; + ilL = LdebParLigneDeL[KpLigne] + NbTermesParLigneDeL[KpLigne]; + IndiceColonneParLigneDeL[ilL] = Kp; + ElmDeLParLigne [ilL] = ElmDeL[il]; + NbTermesParLigneDeL[KpLigne]++; + il++; + } +} + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_resolution.c b/src/ext/Sirius_Solver/simplexe/lu/lu_resolution.c new file mode 100644 index 0000000000..12415be74d --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_resolution.c @@ -0,0 +1,692 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution du systeme + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_LuSolv( MATRICE * Matrice, + double * SecondMembreEtSolution, /* Le vecteur du second membre et la solution */ + int * CodeRetour, /* Le code retour ( 0 si tout s'est bien passe ) */ + MATRICE_A_FACTORISER * MatriceEntree, /* Peut etre NULL, dans ce cas on ne fait pas de raffinement */ + int NombreMaxIterationsDeRaffinement, + double ValeurMaxDesResidus /* En norme L infini i.e. le plus grand */ + ) +{ +double * SecondMembre; double * Solution ; double * SecondMembreSV ; double * SolutionSV ; int NbResolutions ; +int Rang; int Var ; int il; int ilMax; double X; int * IdebColEntree; int * NbElmColEntree; int * IndLigEntree; +double * ValElmEntree; + +*CodeRetour = 0; + +if ( MatriceEntree == NULL ) NombreMaxIterationsDeRaffinement = 0; +if ( NombreMaxIterationsDeRaffinement < 0 ) NombreMaxIterationsDeRaffinement = 0; + +if ( NombreMaxIterationsDeRaffinement > NOMBRE_MAX_ITER_DE_RAFFINEMENT ) { + NombreMaxIterationsDeRaffinement = NOMBRE_MAX_ITER_DE_RAFFINEMENT; +} + +Rang = Matrice->Rang; + +if ( NombreMaxIterationsDeRaffinement > 0 ) { + SecondMembreSV = Matrice->SecondMembreSV; + if ( Matrice->SolutionSV == NULL ) Matrice->SolutionSV = (double *) malloc( Rang * sizeof( double ) ); + if ( Matrice->SolutionSV != NULL ) { + SolutionSV = Matrice->SolutionSV; + memcpy( (char *) SecondMembreSV , (char *) SecondMembreEtSolution , Rang * sizeof( double ) ); + memset( (char *) SolutionSV , 0 , Rang * sizeof( double ) ); + NbResolutions = 0; + /* La matrice d'entree */ + IdebColEntree = MatriceEntree->IndexDebutDesColonnes; + NbElmColEntree = MatriceEntree->NbTermesDesColonnes; + IndLigEntree = MatriceEntree->IndicesDeLigne; + ValElmEntree = MatriceEntree->ValeurDesTermesDeLaMatrice; + } + else NombreMaxIterationsDeRaffinement = 0; +} + +ResolutionLuSolv: + +if ( Matrice->FaireScaling == OUI_LU ) LU_ScalingSecondMembre( Matrice , SecondMembreEtSolution ); + +/* Resolution de Ly = Pb avec P matrice de permutation des lignes et b + le second membre */ +SecondMembre = SecondMembreEtSolution; +LU_LuSolvTriangleL( Matrice , SecondMembre ); + +LU_LuSolveH( Matrice ); + +/* Resolution de U Q^t x = y avec Q matrice de permutation des colonnes */ +Solution = SecondMembreEtSolution; +LU_LuSolvTriangleU( Matrice , Solution ); + +if ( Matrice->FaireScaling == OUI_LU ) LU_UnScaling( Matrice , SecondMembreEtSolution ); + +if ( NombreMaxIterationsDeRaffinement > 0 ) { + NbResolutions++; + if ( NbResolutions <= NombreMaxIterationsDeRaffinement ) { + for ( Var = 0 ; Var < Rang ; Var++ ) SolutionSV[Var]+= SecondMembreEtSolution[Var]; + memcpy( (char *) SecondMembreEtSolution , (char *) SecondMembreSV , Rang * sizeof( double ) ); + for ( Var = 0 ; Var < Rang ; Var++ ) { + X = SolutionSV[Var]; + il = IdebColEntree[Var]; + ilMax = il + NbElmColEntree[Var]; + while ( il < ilMax ) { + SecondMembreEtSolution[IndLigEntree[il]]-= ValElmEntree[il] * X; + il++; + } + } + for ( Var = 0 ; Var < Rang ; Var++ ) { + if ( fabs( SecondMembreEtSolution[Var] ) > ValeurMaxDesResidus ) { + /* + printf("LU_LuSolv: iteration de raffinement necessaire ecart %e sur %d\n",fabs( SecondMembreEtSolution[Var]),Var); + */ + goto ResolutionLuSolv; + } + } + memcpy( SecondMembreEtSolution , SolutionSV , Rang * sizeof( double ) ); + } + else { + /* + printf("LU_LuSolv: le nombre max d'iterations de raffinement ne suffit pas pour atteindre la precision demandee \n"); + */ + *CodeRetour = PRECISION_DE_RESOLUTION_NON_ATTEINTE; + for ( Var = 0 ; Var < Rang ; Var++ ) SecondMembreEtSolution[Var]+= SolutionSV[Var]; + } +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_LuSolvTriangleL( MATRICE * Matrice, double * SecondMembre ) +{ +int Kp; int il; int ilMax; double X; int * IndiceLigneDeL; int * NbTermesParColonneDeL; +double * SolutionIntermediaire; double * ElmDeL; int * OrdreLigne; + +SolutionIntermediaire = Matrice->SolutionIntermediaire; +IndiceLigneDeL = Matrice->IndiceLigneDeL; +NbTermesParColonneDeL = Matrice->NbTermesParColonneDeL; +ElmDeL = Matrice->ElmDeL; + +/* Resolution de Ly = Pb avec P matrice de permutation des lignes et b + le second membre */ +if ( Matrice->ContexteDeLaFactorisation == LU_SIMPLEXE && 0 ) goto LPourSimplexe; +il = 0; +for ( Kp = 0 ; Kp < Matrice->Rang ; Kp++ ) { + /* Le pivot vaut 1 */ + if ( NbTermesParColonneDeL[Kp] == 1 ) { + SolutionIntermediaire[Kp] = SecondMembre[IndiceLigneDeL[il]]; + il++; + continue; + } + X = SecondMembre[IndiceLigneDeL[il]]; + if ( X != 0.0 ) { + SolutionIntermediaire[Kp] = X; + ilMax = il + NbTermesParColonneDeL[Kp]; + il++; + while ( il < ilMax ) { + SecondMembre[IndiceLigneDeL[il]]-= ElmDeL[il] * X; + il++; + } + } + else { + il+= NbTermesParColonneDeL[Kp]; + } +} +return; + +LPourSimplexe: +OrdreLigne = Matrice->OrdreLigne; +il = 0; +for ( Kp = 0 ; Kp < Matrice->Rang ; Kp++ ) { + /* Le pivot vaut 1 */ + SolutionIntermediaire[Kp] = SecondMembre[OrdreLigne[Kp]] - SolutionIntermediaire[Kp]; + if ( NbTermesParColonneDeL[Kp] == 1 ) { + il++; + continue; + } + if ( SolutionIntermediaire[Kp] != 0.0 ) { + X = SolutionIntermediaire[Kp]; + ilMax = il + NbTermesParColonneDeL[Kp]; + il++; + while ( il < ilMax ) { + SolutionIntermediaire[IndiceLigneDeL[il]]+= ElmDeL[il] * X; + il++; + } + } + else { + il+= NbTermesParColonneDeL[Kp]; + } +} +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_LuSolveH( MATRICE * Matrice ) +{ +int k ; int il; int ilMax; double S; int Kp; int Rang; int NbTermesNonNulsDuSpike; +double * HValeur; double * SolutionIntermediaire; double * ValeurElmSpike; +int * HDeb; int * HNbTerm; int * HIndiceColonne; int * HLigne; int * IndicesLignesDuSpike; + +HDeb = Matrice->HDeb; +HNbTerm = Matrice->HNbTerm; +HValeur = Matrice->HValeur; +HIndiceColonne = Matrice->HIndiceColonne; +SolutionIntermediaire = Matrice->SolutionIntermediaire; +HLigne = Matrice->HLigne; + +k = 0; +while ( k < Matrice->NombreDeLuUpdates ) { + il = HDeb[k]; + ilMax = il + HNbTerm[k]; + S = 0.; + while ( il < ilMax ) { + S+= HValeur[il] * SolutionIntermediaire[HIndiceColonne[il]]; + il++; + } + /* Colonne egal aussi contrainte pour le terme diagonal */ + SolutionIntermediaire[HLigne[k]]-= S; + k++; +} + +if ( Matrice->SauvegardeDuResultatIntermediaire == OUI_LU ) { + ValeurElmSpike = Matrice->ValeurElmSpike; + IndicesLignesDuSpike = Matrice->IndicesLignesDuSpike; + Rang = Matrice->Rang; + NbTermesNonNulsDuSpike = 0; + + for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + /*if ( SolutionIntermediaire[Kp] != 0.0 ) {*/ + if ( fabs(SolutionIntermediaire[Kp]) > ZERO_POUR_SPIKE ) { + ValeurElmSpike[NbTermesNonNulsDuSpike] = SolutionIntermediaire[Kp]; + IndicesLignesDuSpike[NbTermesNonNulsDuSpike] = Kp; + NbTermesNonNulsDuSpike++; + } + } + Matrice->NbTermesNonNulsDuSpike = NbTermesNonNulsDuSpike; + +} +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +void LU_LuSolvTriangleU( MATRICE * Matrice , double * Solution ) +{ +int Kp ; double X; double * SolutionIntermediaire; +int * OrdreUcolonne; int KpInitial; int ic; int icMax; int * CdebParColonneDeU; +int * NbTermesParColonneDeU; double * ElmDeUParColonne; int * IndiceLigneParColonneDeU; +int * OrdreColonne; +int * LdebParLigneDeU; int * NbTermesParLigneDeU; int * IndiceColonneDeU; double * ElmDeU; +int il; int ilMax; int Inconnue; double Y; + +SolutionIntermediaire = Matrice->SolutionIntermediaire; + +if ( Matrice->ContexteDeLaFactorisation == LU_SIMPLEXE ) goto UPourSimplexe; +if ( Matrice->ContexteDeLaFactorisation == LU_POINT_INTERIEUR ) goto UPourPointInterieur; + +/* Attention, cette partie de code ne fonctionne pas avec la LU Update */ +OrdreColonne = Matrice->OrdreColonne; +CdebParColonneDeU = Matrice->CdebParColonneDeU; +NbTermesParColonneDeU = Matrice->NbTermesParColonneDeU; +ElmDeUParColonne = Matrice->ElmDeUParColonne; +IndiceLigneParColonneDeU = Matrice->IndiceLigneParColonneDeU; + +for ( Kp = Matrice->Rang - 1 ; Kp >= 0 ; Kp-- ) { + ic = CdebParColonneDeU[Kp]; + icMax = ic + NbTermesParColonneDeU[Kp]; + /* Par convention le premier terme est le pivot et il est deja inverse */ + if ( SolutionIntermediaire[Kp] != 0.0 ) { + X = ElmDeUParColonne[ic] * SolutionIntermediaire[Kp]; + /* Pendant que la donnee est dans le cache: Raz pour une prochaine utilisation */ + SolutionIntermediaire[Kp] = 0.0; + /* */ + ic++; + while ( ic < icMax ) { + SolutionIntermediaire[IndiceLigneParColonneDeU[ic]]-= ElmDeUParColonne[ic] * X; + ic++; + } + Solution[OrdreColonne[Kp]] = X; + } + else { + Solution[OrdreColonne[Kp]] = 0.0; + } +} +return; + +UPourPointInterieur: +LdebParLigneDeU = Matrice->LdebParLigneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; +ElmDeU = Matrice->ElmDeU; +for ( Kp = Matrice->Rang - 1 ; Kp >= 0 ; Kp-- ) { + il = LdebParLigneDeU[Kp]; + ilMax = il + NbTermesParLigneDeU[Kp]; + /* Par convention le premier terme est le pivot et il est deja inverse */ + X = SolutionIntermediaire[Kp]; + /* Pendant que la donnee est dans le cache: Raz pour une prochaine utilisation */ + SolutionIntermediaire[Kp] = 0.0; + /* */ + Y = ElmDeU[il]; + Inconnue = IndiceColonneDeU[il]; + il++; + while ( il < ilMax ) { + X-= ElmDeU[il] * Solution[IndiceColonneDeU[il]]; + il++; + } + /* Par convention le pivot est deja inverse */ + Solution[Inconnue] = X * Y; +} +return; + +UPourSimplexe: +/* On utilise des matrices de permutations */ +OrdreColonne = Matrice->OrdreColonne; +OrdreUcolonne = Matrice->OrdreUcolonne; +CdebParColonneDeU = Matrice->CdebParColonneDeU; +NbTermesParColonneDeU = Matrice->NbTermesParColonneDeU; +ElmDeUParColonne = Matrice->ElmDeUParColonne; +IndiceLigneParColonneDeU = Matrice->IndiceLigneParColonneDeU; + +for ( Kp = Matrice->Rang - 1 ; Kp >= 0 ; Kp-- ) { + KpInitial = OrdreUcolonne[Kp]; + if ( SolutionIntermediaire[KpInitial] == 0.0 ) { + Solution[OrdreColonne[KpInitial]] = 0.0; + continue; + } + if ( NbTermesParColonneDeU[KpInitial] == 1 ) { + X = ElmDeUParColonne[CdebParColonneDeU[KpInitial]] * SolutionIntermediaire[KpInitial]; + if ( fabs( X ) > ZERO_POUR_LE_RESULTAT_DE_LA_RESOLUTION ) Solution[OrdreColonne[KpInitial]] = X; + else Solution[OrdreColonne[KpInitial]] = 0.0; + /* Pendant que la donnee a toutes les chances d'etre dans le cache: Raz pour une prochaine utilisation */ + SolutionIntermediaire[KpInitial] = 0.0; + /* */ + continue; + } + ic = CdebParColonneDeU[KpInitial]; + icMax = ic + NbTermesParColonneDeU[KpInitial]; + /* Par convention le premier terme est le pivot et il est deja inverse */ + if ( SolutionIntermediaire[KpInitial] != 0.0 ) { + X = ElmDeUParColonne[ic] * SolutionIntermediaire[KpInitial]; + /* Pendant que la donnee est dans le cache: Raz pour une prochaine utilisation */ + SolutionIntermediaire[KpInitial] = 0.0; + /* */ + ic++; + while ( ic < icMax ) { + SolutionIntermediaire[IndiceLigneParColonneDeU[ic]]-= ElmDeUParColonne[ic] * X; + ic++; + } + if ( fabs( X ) < ZERO_POUR_LE_RESULTAT_DE_LA_RESOLUTION ) Solution[OrdreColonne[KpInitial]] = 0.0; + else Solution[OrdreColonne[KpInitial]] = X; + } + else { + Solution[OrdreColonne[KpInitial]] = 0.0; + } +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_LuSolvTransposee( + MATRICE * Matrice, + double * SecondMembreEtSolution, /* Le vecteur du second membre et la solution */ + int * CodeRetour, /* Le code retour ( 0 si tout s'est bien passe ) */ + MATRICE_A_FACTORISER * MatriceEntree, /* Peut etre NULL, dans ce cas on ne fait pas de raffinement */ + int NombreMaxIterationsDeRaffinement, + double ValeurMaxDesResidus /* En norme L infini i.e. le plus grand */ + ) +{ +double * SecondMembre; double * Solution ; double * SecondMembreSV ; double * SolutionSV ; int NbResolutions ; +int Rang; int Var ; int il; int ilMax; double X; int * IdebColEntree; int * NbElmColEntree; int * IndLigEntree; +double * ValElmEntree; int i ; + +*CodeRetour = 0; + +if ( MatriceEntree == NULL ) NombreMaxIterationsDeRaffinement = 0; +if ( NombreMaxIterationsDeRaffinement < 0 ) NombreMaxIterationsDeRaffinement = 0; +if ( NombreMaxIterationsDeRaffinement > NOMBRE_MAX_ITER_DE_RAFFINEMENT ) { + NombreMaxIterationsDeRaffinement = NOMBRE_MAX_ITER_DE_RAFFINEMENT; +} + +Rang = Matrice->Rang; + +if ( NombreMaxIterationsDeRaffinement > 0 ) { + SecondMembreSV = Matrice->SecondMembreSV; + if ( Matrice->SolutionSV == NULL ) Matrice->SolutionSV = (double *) malloc( Rang * sizeof( double ) ); + if ( Matrice->SolutionSV != NULL ) { + SolutionSV = Matrice->SolutionSV; + memcpy( (char *) SecondMembreSV , (char *) SecondMembreEtSolution , Rang * sizeof( double ) ); + memset( (char *) SolutionSV , 0 , Rang * sizeof( double ) ); + NbResolutions = 0; + /* La matrice d'entree */ + IdebColEntree = MatriceEntree->IndexDebutDesColonnes; + NbElmColEntree = MatriceEntree->NbTermesDesColonnes; + IndLigEntree = MatriceEntree->IndicesDeLigne; + ValElmEntree = MatriceEntree->ValeurDesTermesDeLaMatrice; + } + else NombreMaxIterationsDeRaffinement = 0; +} + +ResolutionLuSolvTransposee: + +if ( Matrice->FaireScaling == OUI_LU ) LU_ScalingSecondMembreTranspose( Matrice , SecondMembreEtSolution ); + +/* Resolution de U^t y = Q^t b avec Q matrice de permutation des colonnes */ +SecondMembre = SecondMembreEtSolution; +LU_LuSolvTriangleUTransposee( Matrice , SecondMembre ); + +LU_LuSolveHTransposee( Matrice ); + +/* Resolution de L^t x = y */ +Solution = SecondMembreEtSolution; +LU_LuSolvTriangleLTransposee( Matrice , Solution ); + +if ( Matrice->FaireScaling == OUI_LU ) LU_UnScalingTranspose( Matrice , SecondMembreEtSolution ); + +if ( NombreMaxIterationsDeRaffinement > 0 ) { + NbResolutions++; + if ( NbResolutions <= NombreMaxIterationsDeRaffinement ) { + for ( Var = 0 ; Var < Rang ; Var++ ) SolutionSV[Var]+= SecondMembreEtSolution[Var]; + memcpy( (char *) SecondMembreEtSolution , (char *) SecondMembreSV , Rang * sizeof( double ) ); + for ( i = 0 ; i < Rang ; i++ ) { + X = SecondMembreEtSolution[i]; + il = IdebColEntree[i]; + ilMax = il + NbElmColEntree[i]; + while ( il < ilMax ) { + /* Dans ce cas, IndLigEntree[il] va nous donner le numero de la variable */ + X-= ValElmEntree[il] * SolutionSV[IndLigEntree[il]]; + il++; + } + SecondMembreEtSolution[i] = X; + } + for ( i = 0 ; i < Rang ; i++ ) { + if ( fabs( SecondMembreEtSolution[i] ) > ValeurMaxDesResidus ) { + /* + printf("LU_LuSolvTransposee: iteration de raffinement necessaire ecart %e sur %d\n",fabs( SecondMembreEtSolution[i]),i); + */ + goto ResolutionLuSolvTransposee; + } + } + memcpy( SecondMembreEtSolution , SolutionSV , Rang * sizeof( double ) ); + } + else { + /* + printf("LU_LuSolvTransposee: le nombre max d'iterations de raffinement ne suffit pas pour atteindre la precision demandee \n"); + */ + *CodeRetour = PRECISION_DE_RESOLUTION_NON_ATTEINTE; + for ( Var = 0 ; Var < Rang ; Var++ ) SecondMembreEtSolution[Var]+= SolutionSV[Var]; + } +} + +return; +} +/*--------------------------------------------------------------------------------------------------*/ +void LU_LuSolvTriangleUTransposee( MATRICE * Matrice , double * SecondMembre ) +{ +int Kp; int il; int ilMax; double X; double Y; int Rang; int KpInitial; int * LdebParLigneDeU; +int * IndiceColonneDeU; int * NbTermesParLigneDeU; double * SolutionIntermediaire; +double * ElmDeU; int * OrdreUcolonne; +int * CdebParColonneDeU; int * NbTermesParColonneDeU; int * IndiceLigneParColonneDeU; double * ElmDeUParColonne; +int * OrdreColonne; + +SolutionIntermediaire = Matrice->SolutionIntermediaire; +Rang = Matrice->Rang; + +/* Resolution de U^t y = Q^t b avec Q matrice de permutation des colonnes */ +if ( Matrice->ContexteDeLaFactorisation == LU_SIMPLEXE ) goto UTPourSimplexe; +if ( Matrice->ContexteDeLaFactorisation == LU_POINT_INTERIEUR ) goto UTPourPointInterieur; + +/* Hors simplexe on utilise encore le chainage par colonne car c'est le seul + qui est maintenu dans le cas de la refactorisation */ +CdebParColonneDeU = Matrice->CdebParColonneDeU; +NbTermesParColonneDeU = Matrice->NbTermesParColonneDeU; +ElmDeUParColonne = Matrice->ElmDeUParColonne; +IndiceLigneParColonneDeU = Matrice->IndiceLigneParColonneDeU; +OrdreColonne = Matrice->OrdreColonne; + +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + il = CdebParColonneDeU[Kp]; + ilMax = il + NbTermesParColonneDeU[Kp]; + /* Par convention le premier terme est le pivot et il est deja inverse */ + X = SecondMembre[OrdreColonne[Kp]]; + /* */ + Y = ElmDeUParColonne[il]; + il++; + while ( il < ilMax ) { + /* IndiceLigneParColonneDeU est donne dans la numerotation Kp */ + X-= ElmDeUParColonne[il] * SolutionIntermediaire[IndiceLigneParColonneDeU[il]]; + il++; + } + /* Par convention le pivot est deja inverse */ + SolutionIntermediaire[Kp] = X * Y; +} +return; + +UTPourPointInterieur: +LdebParLigneDeU = Matrice->LdebParLigneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +ElmDeU = Matrice->ElmDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; + +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + il = LdebParLigneDeU[Kp]; + /* Par convention le premier terme est le pivot et est deja inverse */ + X = SecondMembre[IndiceColonneDeU[il]]; + /* On fait le test sur SecondMembre car si SecondMembre est nul alors X est nul */ + if ( X != 0.0 ) { + X = X * ElmDeU[il]; + SolutionIntermediaire[Kp] = X; + ilMax = il + NbTermesParLigneDeU[Kp]; + il++; + while ( il < ilMax ) { + SecondMembre[IndiceColonneDeU[il]]-= ElmDeU[il] * X; + il++; + } + } +} +return; + +UTPourSimplexe: + +LdebParLigneDeU = Matrice->LdebParLigneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +ElmDeU = Matrice->ElmDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; +OrdreUcolonne = Matrice->OrdreUcolonne; + +for ( Kp = 0 ; Kp < Rang ; Kp++ ) { + KpInitial = OrdreUcolonne[Kp]; + il = LdebParLigneDeU[KpInitial]; + /* Par convention le premier terme est le pivot et est deja inverse */ + X = SecondMembre[IndiceColonneDeU[il]]; + /* On fait le test sur SecondMembre car si SecondMembre est nul alors X est nul */ + if ( X != 0.0 ) { + X = X * ElmDeU[il]; + SolutionIntermediaire[KpInitial] = X; + ilMax = il + NbTermesParLigneDeU[KpInitial]; + il++; + while ( il < ilMax ) { + SecondMembre[IndiceColonneDeU[il]]-= ElmDeU[il] * X; + il++; + } + } +} +return; + +} +/*--------------------------------------------------------------------------------------------------*/ +void LU_LuSolveHTransposee( MATRICE * Matrice ) +{ +int k; int il; int ilMax; double S; int * HDeb; int * HNbTerm; int * HLigne; +int * HIndiceColonne; double * SolutionIntermediaire; double * HValeur; + +HDeb = Matrice->HDeb; +HNbTerm = Matrice->HNbTerm; +SolutionIntermediaire = Matrice->SolutionIntermediaire; +HLigne = Matrice->HLigne; +HIndiceColonne = Matrice->HIndiceColonne; +HValeur = Matrice->HValeur; + +k = Matrice->NombreDeLuUpdates - 1; +while ( k >= 0 ) { + il = HDeb[k]; + ilMax = il + HNbTerm[k]; + S = SolutionIntermediaire[HLigne[k]]; + if ( S != 0.0 ) { + while ( il < ilMax ) { + SolutionIntermediaire[HIndiceColonne[il]]-= HValeur[il] * S; + il++; + } + } + k--; +} +return; +} +/*--------------------------------------------------------------------------------------------------*/ +void LU_LuSolvTriangleLTransposee( MATRICE * Matrice , double * Solution ) +{ +int Kp; int il; int ilMax; double X; int Inconnue; int * CdebParColonneDeL; int * NbTermesParColonneDeL; +double * ElmDeL; int * IndiceLigneDeL; double * SolutionIntermediaire; int * LdebParLigneDeL; +int * NbTermesParLigneDeL; int * IndiceColonneParLigneDeL; double * ElmDeLParLigne; int * OrdreLigne; +char AllocOk; + +SolutionIntermediaire = Matrice->SolutionIntermediaire; + +CdebParColonneDeL = Matrice->CdebParColonneDeL; +NbTermesParColonneDeL = Matrice->NbTermesParColonneDeL; +ElmDeL = Matrice->ElmDeL; +IndiceLigneDeL = Matrice->IndiceLigneDeL; + +/* Resolution de L^t x = y */ +if ( Matrice->ContexteDeLaFactorisation == LU_SIMPLEXE ) goto LTPourSimplexe; + +LTAutresContextes: +for ( Kp = Matrice->Rang - 1 ; Kp >= 0 ; Kp-- ) { + X = SolutionIntermediaire[Kp]; + /* RAZ pendant que la donnee est dans le cache */ + SolutionIntermediaire[Kp] = 0.0; + /* */ + il = CdebParColonneDeL[Kp]; + ilMax = il + NbTermesParColonneDeL[Kp]; + Inconnue = IndiceLigneDeL[il]; + il++; + while ( il < ilMax ) { + X-= ElmDeL[il] * Solution[IndiceLigneDeL[il]]; + il++; + } + Solution[Inconnue] = X; +} +return; + +LTPourSimplexe: + +if ( Matrice->LdebParLigneDeL == NULL ) { + /* Si le stockage par ligne de L n'existe pas on le cree */ + LU_ChainageParLigneDeL( Matrice, &AllocOk ); + if ( AllocOk != OUI_LU ) goto LTAutresContextes; +} + +OrdreLigne = Matrice->OrdreLigne; +LdebParLigneDeL = Matrice->LdebParLigneDeL; +NbTermesParLigneDeL = Matrice->NbTermesParLigneDeL; +IndiceColonneParLigneDeL = Matrice->IndiceColonneParLigneDeL; +ElmDeLParLigne = Matrice->ElmDeLParLigne; + +for ( Kp = Matrice->Rang - 1 ; Kp >= 0 ; Kp-- ) { + X = SolutionIntermediaire[Kp]; + if ( X != 0 ) { + /* RAZ pendant que la donnee est dans le cache */ + SolutionIntermediaire[Kp] = 0.0; + /* */ + if ( NbTermesParLigneDeL[Kp] == 1 ) { + if ( fabs( X ) < ZERO_POUR_LE_RESULTAT_DE_LA_RESOLUTION_TRANSPOSEE ) Solution[OrdreLigne[Kp]] = 0.0; + else Solution[OrdreLigne[Kp]] = X; + continue; + } + /* */ + il = LdebParLigneDeL[Kp]; + ilMax = il + NbTermesParLigneDeL[Kp]; + il++; + while ( il < ilMax ) { + SolutionIntermediaire[IndiceColonneParLigneDeL[il]]-= ElmDeLParLigne[il] * X; + il++; + } + if ( fabs( X ) < ZERO_POUR_LE_RESULTAT_DE_LA_RESOLUTION_TRANSPOSEE ) Solution[OrdreLigne[Kp]] = 0.0; + else Solution[OrdreLigne[Kp]] = X; + } + else Solution[OrdreLigne[Kp]] = 0.0; +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_LuSolvLuUpdate( MATRICE * Matrice, double * SecondMembreEtSolution, int * CodeRetour, + char Save, char SecondMembreCreux, MATRICE_A_FACTORISER * MatriceEntree, + int NombreMaxIterationsDeRaffinement, double ValeurMaxDesResidus + ) +{ + +Matrice->SauvegardeDuResultatIntermediaire = Save; +Matrice->SecondMembreCreux = SecondMembreCreux; + +LU_LuSolv( Matrice, SecondMembreEtSolution, CodeRetour, MatriceEntree, NombreMaxIterationsDeRaffinement, + ValeurMaxDesResidus ); + +Matrice->SauvegardeDuResultatIntermediaire = NON_LU; +Matrice->SecondMembreCreux = NON_LU; +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_LuSolvTransposeeLuUpdate( MATRICE * Matrice, double * SecondMembreEtSolution, int * CodeRetour , + char SecondMembreCreux, MATRICE_A_FACTORISER * MatriceEntree, + int NombreMaxIterationsDeRaffinement, double ValeurMaxDesResidus + ) +{ + +Matrice->SecondMembreCreux = SecondMembreCreux; + +LU_LuSolvTransposee( Matrice, SecondMembreEtSolution, CodeRetour, MatriceEntree, NombreMaxIterationsDeRaffinement, + ValeurMaxDesResidus ); + +Matrice->SecondMembreCreux = NON_LU; +return; +} + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_resolution_hyper_creux.c b/src/ext/Sirius_Solver/simplexe/lu/lu_resolution_hyper_creux.c new file mode 100644 index 0000000000..02d1f7c8d5 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_resolution_hyper_creux.c @@ -0,0 +1,884 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution du systeme. Cas hyper creux. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# define SEUIL_RECURSION 0.75/*0.8*/ +# define SEUIL_RECURSION_T 0.75/*0.8*/ + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_AllocEtInitHyperCreux( MATRICE * Matrice, char * AllocOk ) +{ +int i; int Rang; char * NoeudDansLaliste; +*AllocOk = OUI_LU; +Rang = Matrice->Rang; +Matrice->RatioMoyen = 0.0; +Matrice->NombreDeRatios = 0; +Matrice->RatioMoyenTransposee = 0.0; +Matrice->NombreDeRatiosTransposee = 0; +Matrice->TailleAlloueeDePseudoPile = Rang; +Matrice->PseudoPile = Matrice->Ldeb; +Matrice->ListeDesNoeuds = Matrice->LNbTerm; +Matrice->NoeudDansLaliste = (char *) Matrice->LDernierPossible; +/* +Matrice->NoeudDansLaliste = (char *) malloc( Rang * sizeof( char ) ); +if ( Matrice->NoeudDansLaliste == NULL ) { + *AllocOk = NON_LU; + return; +} +*/ +NoeudDansLaliste = Matrice->NoeudDansLaliste; +for ( i = 0 ; i < Rang ; i++ ) NoeudDansLaliste[i] = NOEUD_HORS_LISTE; +return; +} +/*--------------------------------------------------------------------------------------------------*/ + +char LU_RecusionSurTriangle_1( MATRICE * Matrice, int * IndexTermesNonNuls, int NbTermesNonNuls, + int * InverseOrdre, int * CdebParColonne, int * IndiceLigne, + int * NbTermesParColonne, int * NombreDeNoeudsDansLaListe ) +{ +int i; int Kp; int IndexDePile; int NbNoeudsDansLaListe; int il; int ilMax; int Col; +char * NoeudDansLaliste; int * ListeDesNoeuds; int * PseudoPile; int IndexMaxDePile; + +NbNoeudsDansLaListe = 0; +NoeudDansLaliste = Matrice->NoeudDansLaliste; +ListeDesNoeuds = Matrice->ListeDesNoeuds; +PseudoPile = Matrice->PseudoPile; + +IndexMaxDePile = Matrice->TailleAlloueeDePseudoPile - 3; + +for ( i = 0 ; i < NbTermesNonNuls ; i++ ) { + Col = IndexTermesNonNuls[i]; + if ( NoeudDansLaliste[Col] != NOEUD_HORS_LISTE ) continue; + + /* Recursion avec simulation de pile */ + IndexDePile = 0; + Kp = InverseOrdre[Col]; + NouveauNoeud: + if ( NbTermesParColonne[Kp] == 1 ) goto InclureLeNoeudDansLaListe; + il = CdebParColonne[Kp] + 1; + ilMax = il + NbTermesParColonne[Kp] - 1; + ParcoursNoeud: + while ( il < ilMax ) { + if ( NoeudDansLaliste[IndiceLigne[il]] == NOEUD_HORS_LISTE ) { + + if ( IndexDePile > IndexMaxDePile ) { + # if VERBOSE_LU + printf("Taille de la pseudo pile depasse\n"); + # endif + *NombreDeNoeudsDansLaListe = NbNoeudsDansLaListe; + return( RECURSION_NOT_OK ); + } + + if ( il+1 < ilMax ) { + PseudoPile[IndexDePile] = ilMax; + IndexDePile++; + PseudoPile[IndexDePile] = il+1; + IndexDePile++; + } + else { + IndexDePile++; + PseudoPile[IndexDePile] = -1; + IndexDePile++; + } + PseudoPile[IndexDePile] = Col; + IndexDePile++; + Col = IndiceLigne[il]; + Kp = InverseOrdre[Col]; + goto NouveauNoeud; + } + il++; + } + /* On a explore tous les fils de Kp => On remonte */ + /* Au lieu de placer le noeud au sommet de la liste, on le place a la fin. + Il faudra donc lire la liste a l'envers */ + InclureLeNoeudDansLaListe: + ListeDesNoeuds[NbNoeudsDansLaListe] = Col; + NoeudDansLaliste[Col] = NOEUD_DANS_LISTE; + NbNoeudsDansLaListe++; + + /* On remonte dans la pile */ + IndexDePile--; + if ( IndexDePile >= 2 ) { + Col = PseudoPile[IndexDePile]; + IndexDePile--; + il = PseudoPile[IndexDePile]; + IndexDePile--; + if ( il < 0 ) goto InclureLeNoeudDansLaListe; + ilMax = PseudoPile[IndexDePile]; + goto ParcoursNoeud; + } +} + +*NombreDeNoeudsDansLaListe = NbNoeudsDansLaListe; + +return( RECURSION_OK ); +} + +/*--------------------------------------------------------------------------------------------------*/ + +char LU_RecusionSurTriangle_2( MATRICE * Matrice, int * IndexTermesNonNuls, int NbTermesNonNuls, + int * CdebParColonne, int * IndiceLigne, int * NbTermesParColonne, + int * NombreDeNoeudsDansLaListe ) +{ +int i; int Kp; int IndexDePile; int NbNoeudsDansLaListe; int il; int ilMax; char * NoeudDansLaliste; +int * ListeDesNoeuds; int * PseudoPile; int IndexMaxDePile; + +NbNoeudsDansLaListe = 0; +NoeudDansLaliste = Matrice->NoeudDansLaliste; +ListeDesNoeuds = Matrice->ListeDesNoeuds; +PseudoPile = Matrice->PseudoPile; + +IndexMaxDePile = Matrice->TailleAlloueeDePseudoPile - 3; + +for ( i = 0 ; i < NbTermesNonNuls ; i++ ) { + if ( NoeudDansLaliste[IndexTermesNonNuls[i]] != NOEUD_HORS_LISTE ) continue; + Kp = IndexTermesNonNuls[i]; + + /* Recursion avec simulation de pile */ + IndexDePile = 0; + NouveauNoeud: + if ( NbTermesParColonne[Kp] == 1 ) goto InclureLeNoeudDansLaListe; + il = CdebParColonne[Kp] + 1; + ilMax = il + NbTermesParColonne[Kp] - 1; + ParcoursNoeud: + while ( il < ilMax ) { + if ( NoeudDansLaliste[IndiceLigne[il]] == NOEUD_HORS_LISTE ) { + + if ( IndexDePile > IndexMaxDePile ) { + # if VERBOSE_LU + printf("Taille de la pseudo pile depasse\n"); + # endif + *NombreDeNoeudsDansLaListe = NbNoeudsDansLaListe; + return( RECURSION_NOT_OK ); + } + + if ( il+1 < ilMax ) { + PseudoPile[IndexDePile] = ilMax; + IndexDePile++; + PseudoPile[IndexDePile] = il+1; + IndexDePile++; + } + else { + IndexDePile++; + PseudoPile[IndexDePile] = -1; + IndexDePile++; + } + PseudoPile[IndexDePile] = Kp; + IndexDePile++; + Kp = IndiceLigne[il]; + goto NouveauNoeud; + } + il++; + } + /* On a explore tous les fils de Kp => On remonte */ + /* Au lieu de placer le noeud au sommet de la liste, on le place a la fin. + Il faudra donc lire la liste a l'envers */ + InclureLeNoeudDansLaListe: + ListeDesNoeuds[NbNoeudsDansLaListe] = Kp; + NoeudDansLaliste[Kp] = NOEUD_DANS_LISTE; + NbNoeudsDansLaListe++; + + /* On remonte dans la pile */ + IndexDePile--; + if ( IndexDePile >= 2 ) { + Kp = PseudoPile[IndexDePile]; + IndexDePile--; + il = PseudoPile[IndexDePile]; + IndexDePile--; + if ( il < 0 ) goto InclureLeNoeudDansLaListe; + ilMax = PseudoPile[IndexDePile]; + goto ParcoursNoeud; + } +} + +*NombreDeNoeudsDansLaListe = NbNoeudsDansLaListe; + +return( RECURSION_OK ); +} + +/*--------------------------------------------------------------------------------------------------*/ + +char LU_LuSolvTriangleLSecondMembreHyperCreux( MATRICE * Matrice, int * NbTermesNonNuls, + int * IndexTermesNonNuls, double * SecondMembre ) +{ +int Kp; int il ; int ilMax; double X ; int j; int i; int NombreDeNoeudsDansLaListe; +int Ligne; double * SolutionIntermediaire; double * ElmDeL; int * OrdreLigne; +char * NoeudDansLaliste; int * InverseOrdreLigne; int * CdebParColonneDeL; char CodeRet; +int * NbTermesParColonneDeL; int * IndiceLigneDeL; int * ListeDesNoeuds; + +NombreDeNoeudsDansLaListe = 0; + +InverseOrdreLigne = Matrice->InverseOrdreLigne; +CdebParColonneDeL = Matrice->CdebParColonneDeL; +IndiceLigneDeL = Matrice->IndiceLigneDeL; +NbTermesParColonneDeL = Matrice->NbTermesParColonneDeL; + +/* Recusion sur le graphe */ +CodeRet = LU_RecusionSurTriangle_1 ( Matrice, IndexTermesNonNuls, *NbTermesNonNuls, InverseOrdreLigne, + CdebParColonneDeL, IndiceLigneDeL, NbTermesParColonneDeL, + &NombreDeNoeudsDansLaListe ); + +ListeDesNoeuds = Matrice->ListeDesNoeuds; +NoeudDansLaliste = Matrice->NoeudDansLaliste; + +if ( CodeRet == RECURSION_NOT_OK ) { + for ( i = 0 ; i < NombreDeNoeudsDansLaListe; i++ ) NoeudDansLaliste[ListeDesNoeuds[i]] = NOEUD_HORS_LISTE; + return( CodeRet ); +} + +SolutionIntermediaire = Matrice->SolutionIntermediaire; +ElmDeL = Matrice->ElmDeL; +OrdreLigne = Matrice->OrdreLigne; + +/* Resolution */ +j = 0; +for ( i = NombreDeNoeudsDansLaListe - 1 ; i >= 0 ; i-- ) { + Ligne = ListeDesNoeuds[i]; + NoeudDansLaliste[Ligne] = NOEUD_HORS_LISTE; + + /* Le pivot vaut 1 */ + X = SecondMembre[Ligne]; + if ( X == 0.0 ) continue; + SecondMembre[Ligne] = 0.0; + + Kp = InverseOrdreLigne[Ligne]; + SolutionIntermediaire[Kp] = X; + IndexTermesNonNuls[j] = Kp; + j++; + + il = CdebParColonneDeL[Kp]; + ilMax = il + NbTermesParColonneDeL[Kp]; + il++; + while ( il < ilMax ) { + SecondMembre[IndiceLigneDeL[il]] -= ElmDeL[il] * X; + il++; + } +} + +/* Prediction du nombre de termes */ +if ( j * Matrice->RatioMoyen > ceil( SEUIL_RECURSION * Matrice->Rang ) ) { + for ( i = 0 ; i < NombreDeNoeudsDansLaListe; i++ ) NoeudDansLaliste[ListeDesNoeuds[i]] = NOEUD_HORS_LISTE; + return( ARRET_RESOLUTION_HYPER_CREUX ); +} + +Matrice->NbTermesAuDepart = NombreDeNoeudsDansLaListe; + +/* En sortie on recupere SolutionIntermediaire sous forme creux et IndexTermesNonNuls qui donne + les index de SolutionIntermediaire non nulles */ +for ( i = 0 ; i < j ; i++ ) NoeudDansLaliste[IndexTermesNonNuls[i]] = NOEUD_DANS_LISTE; +*NbTermesNonNuls = j; + +return( POURSUITE_RESOLUTION_HYPER_CREUX ); +} +/*--------------------------------------------------------------------------------------------------*/ +void LU_LuSolveHSecondMembreHyperCreux( MATRICE * Matrice, int * NbTermesNonNuls, + int * IndexTermesNonNuls ) +{ +int k ; int il; int ilMax; double S; int Kp; int Rang; int NbTermesNonNulsDuSpike; +double * HValeur; double * SolutionIntermediaire; double * ValeurElmSpike; +int * HDeb; int * HNbTerm; int * HIndiceColonne; int * HLigne; int * IndicesLignesDuSpike; +int i; char Flag; char * NoeudDansLaliste; + +SolutionIntermediaire = Matrice->SolutionIntermediaire; + +if ( Matrice->NombreDeLuUpdates <= 0 ) goto SVspike; + +NoeudDansLaliste = Matrice->NoeudDansLaliste; + +HDeb = Matrice->HDeb; +HNbTerm = Matrice->HNbTerm; +HValeur = Matrice->HValeur; +HIndiceColonne = Matrice->HIndiceColonne; +HLigne = Matrice->HLigne; + +i = *NbTermesNonNuls; +for ( k = 0 ; k < Matrice->NombreDeLuUpdates ; k++ ) { + il = HDeb[k]; + ilMax = il + HNbTerm[k]; + Flag = 0; + S = 0; + while ( il < ilMax ) { + if ( NoeudDansLaliste[HIndiceColonne[il]] != NOEUD_HORS_LISTE ) { + S+= HValeur[il] * SolutionIntermediaire[HIndiceColonne[il]]; + Flag = 1; + } + il++; + } + /* Colonne egal aussi contrainte pour le terme diagonal */ + if ( S != 0.0 ) { + if ( Flag == 1 ) { + Kp = HLigne[k]; + SolutionIntermediaire[Kp] -= S; + if ( NoeudDansLaliste[Kp] == NOEUD_HORS_LISTE ) { + NoeudDansLaliste[Kp] = NOEUD_DANS_LISTE; + IndexTermesNonNuls[i] = Kp; + i++; + } + } + } +} + +*NbTermesNonNuls = i; + +SVspike: + +if ( Matrice->SauvegardeDuResultatIntermediaire == OUI_LU ) { + + ValeurElmSpike = Matrice->ValeurElmSpike; + IndicesLignesDuSpike = Matrice->IndicesLignesDuSpike; + Rang = Matrice->Rang; + NbTermesNonNulsDuSpike = 0; + + for ( i = 0 ; i < *NbTermesNonNuls ; i++ ) { + Kp = IndexTermesNonNuls[i]; + if ( fabs(SolutionIntermediaire[Kp]) > ZERO_POUR_SPIKE ) { + ValeurElmSpike[NbTermesNonNulsDuSpike] = SolutionIntermediaire[Kp]; + IndicesLignesDuSpike[NbTermesNonNulsDuSpike] = Kp; + NbTermesNonNulsDuSpike++; + } + } + Matrice->NbTermesNonNulsDuSpike = NbTermesNonNulsDuSpike; + +} + +return; +} +/*--------------------------------------------------------------------------------------------------*/ +char LU_LuSolvTriangleUSecondMembreHyperCreux( MATRICE * Matrice, double * Solution, + int * NbTermesNonNuls, int * IndexTermesNonNuls, + char TypeDeSortie ) +{ +double X; double * SolutionIntermediaire; int KpInitial; int ic; int icMax; +int * CdebParColonneDeU; int * NbTermesParColonneDeU; double * ElmDeUParColonne; +int * IndiceLigneParColonneDeU; int * OrdreColonne; int i; int j; int NombreDeNoeudsDansLaListe; +char * NoeudDansLaliste; int * ListeDesNoeuds; char CodeRet; + +/* Recusion sur le graphe */ +NombreDeNoeudsDansLaListe = 0; +NoeudDansLaliste = Matrice->NoeudDansLaliste; +for ( i = 0 ; i < *NbTermesNonNuls ; i++ ) NoeudDansLaliste[IndexTermesNonNuls[i]] = NOEUD_HORS_LISTE; + +CdebParColonneDeU = Matrice->CdebParColonneDeU; +IndiceLigneParColonneDeU = Matrice->IndiceLigneParColonneDeU; +NbTermesParColonneDeU = Matrice->NbTermesParColonneDeU; + +CodeRet = LU_RecusionSurTriangle_2( Matrice, IndexTermesNonNuls, *NbTermesNonNuls, CdebParColonneDeU, + IndiceLigneParColonneDeU, NbTermesParColonneDeU, &NombreDeNoeudsDansLaListe ); + +ListeDesNoeuds = Matrice->ListeDesNoeuds; +SolutionIntermediaire = Matrice->SolutionIntermediaire; + +if ( CodeRet == RECURSION_NOT_OK ) { + for ( i = 0 ; i < NombreDeNoeudsDansLaListe ; i++ ) NoeudDansLaliste[ListeDesNoeuds[i]] = NOEUD_HORS_LISTE; + return( RECURSION_NOT_OK ); +} + +OrdreColonne = Matrice->OrdreColonne; +ElmDeUParColonne = Matrice->ElmDeUParColonne; + +X = Matrice->NombreDeRatios * Matrice->RatioMoyen; +X+= (double) NombreDeNoeudsDansLaListe / (double) Matrice->NbTermesAuDepart; +Matrice->NombreDeRatios++; +Matrice->RatioMoyen = X / Matrice->NombreDeRatios; + +j = 0; +for ( i = NombreDeNoeudsDansLaListe - 1 ; i >= 0 ; i-- ) { + + KpInitial = ListeDesNoeuds[i]; + NoeudDansLaliste[KpInitial] = NOEUD_HORS_LISTE; + if ( SolutionIntermediaire[KpInitial] == 0.0 ) continue; + ic = CdebParColonneDeU[KpInitial]; + + /* Par convention le premier terme est le pivot et il est deja inverse */ + X = ElmDeUParColonne[ic] * SolutionIntermediaire[KpInitial]; + SolutionIntermediaire[KpInitial] = 0.0; + + /*if ( X == 0.0 ) continue;*/ + + /* */ + icMax = ic + NbTermesParColonneDeU[KpInitial]; + ic++; + while ( ic < icMax ) { + SolutionIntermediaire[IndiceLigneParColonneDeU[ic]]-= ElmDeUParColonne[ic] * X; + ic++; + } + + if ( fabs( X ) < ZERO_POUR_LE_RESULTAT_DE_LA_RESOLUTION ) continue; + + if ( TypeDeSortie == COMPACT_LU ) Solution[j] = X; + else Solution[OrdreColonne[KpInitial]] = X; + IndexTermesNonNuls[j] = OrdreColonne[KpInitial]; + j++; +} +*NbTermesNonNuls = j; + +/*printf("Solution : NbTermesNonNuls %d\n",j);*/ + +X = Matrice->NombreDeRatios * Matrice->RatioMoyen; +X+= (double) j / (double) Matrice->NbTermesAuDepart; +Matrice->NombreDeRatios++; +Matrice->RatioMoyen = X / Matrice->NombreDeRatios; + +return( RECURSION_OK ); +} + +/*--------------------------------------------------------------------------------------------------*/ +/* SecondMembre est toujours sous forme expand */ + +char LU_LuSolvTriangleUTransposeeSecondMembreHyperCreux( MATRICE * Matrice, int * NbTermesNonNuls, + int * IndexTermesNonNuls, double * SecondMembre ) +{ +int NombreDeNoeudsDansLaListe; int i; int il; int ilMax; double X; int Col; int j; int KpInitial; +int * ListeDesNoeuds; int * NbTermesParLigneDeU; double * ElmDeU; int * LdebParLigneDeU; +int * IndiceColonneDeU; double * SolutionIntermediaire; char * NoeudDansLaliste; int * InverseOrdreColonne; +int * OrdreColonne; char CodeRet; + +/* Recusion sur le graphe */ +NombreDeNoeudsDansLaListe = 0; + +InverseOrdreColonne = Matrice->InverseOrdreColonne; +LdebParLigneDeU = Matrice->LdebParLigneDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; + +CodeRet = LU_RecusionSurTriangle_1( Matrice, IndexTermesNonNuls, *NbTermesNonNuls, InverseOrdreColonne, LdebParLigneDeU, + IndiceColonneDeU, NbTermesParLigneDeU, &NombreDeNoeudsDansLaListe ); + +ListeDesNoeuds = Matrice->ListeDesNoeuds; +NoeudDansLaliste = Matrice->NoeudDansLaliste; + +if ( CodeRet == RECURSION_NOT_OK ) { + for ( i = 0 ; i < NombreDeNoeudsDansLaListe; i++ ) NoeudDansLaliste[ListeDesNoeuds[i]] = NOEUD_HORS_LISTE; + return( CodeRet ); +} + +SolutionIntermediaire = Matrice->SolutionIntermediaire; +ElmDeU = Matrice->ElmDeU; +OrdreColonne = Matrice->OrdreColonne; + +j = 0; +for ( i = NombreDeNoeudsDansLaListe - 1 ; i >= 0 ; i-- ) { + Col = ListeDesNoeuds[i]; + NoeudDansLaliste[Col] = NOEUD_HORS_LISTE; + + KpInitial = InverseOrdreColonne[Col]; + il = LdebParLigneDeU[KpInitial]; + + /* Par convention le premier terme est le pivot et est deja inverse */ + + X = SecondMembre[Col] * ElmDeU[il]; + + if ( X == 0.0 ) continue; + + SecondMembre[Col] = 0.0; + + SolutionIntermediaire[KpInitial] = X; + IndexTermesNonNuls [j] = KpInitial; + j++; + + ilMax = il + NbTermesParLigneDeU[KpInitial]; + il++; + while ( il < ilMax ) { + SecondMembre[IndiceColonneDeU[il]] -= ElmDeU[il] * X; + il++; + } +} + +/* Prediction du nombre de termes */ +if ( /*NombreDeNoeudsDansLaListe*/ j * Matrice->RatioMoyenTransposee > ceil( SEUIL_RECURSION_T * Matrice->Rang ) ) { + for ( i = 0 ; i < NombreDeNoeudsDansLaListe; i++ ) NoeudDansLaliste[ListeDesNoeuds[i]] = NOEUD_HORS_LISTE; + return( ARRET_RESOLUTION_HYPER_CREUX ); +} + +Matrice->NbTermesAuDepartTransposee = NombreDeNoeudsDansLaListe; + +for ( i = 0 ; i < j ; i++ ) NoeudDansLaliste[IndexTermesNonNuls[i]] = NOEUD_DANS_LISTE; +*NbTermesNonNuls = j; + +return( POURSUITE_RESOLUTION_HYPER_CREUX ); +} +/*--------------------------------------------------------------------------------------------------*/ +void LU_LuSolveHTransposeeSecondMembreHyperCreux( MATRICE * Matrice, int * NbTermesNonNuls, + int * IndexTermesNonNuls ) + +{ +int k; int il; int ilMax; double S; int * HDeb; int * HNbTerm; int * HLigne; int * HIndiceColonne; +double * SolutionIntermediaire; double * HValeur; int i; int Kp; char * NoeudDansLaliste; + +if ( Matrice->NombreDeLuUpdates == 0 ) return; + +NoeudDansLaliste = Matrice->NoeudDansLaliste; + +HDeb = Matrice->HDeb; +HNbTerm = Matrice->HNbTerm; +SolutionIntermediaire = Matrice->SolutionIntermediaire; +HLigne = Matrice->HLigne; +HIndiceColonne = Matrice->HIndiceColonne; +HValeur = Matrice->HValeur; + +i = *NbTermesNonNuls; +k = Matrice->NombreDeLuUpdates - 1; +while ( k >= 0 ) { + il = HDeb[k]; + ilMax = il + HNbTerm[k]; + if ( NoeudDansLaliste[HLigne[k]] != NOEUD_HORS_LISTE ) { + S = SolutionIntermediaire[HLigne[k]]; + if ( S != 0.0 ) { + while ( il < ilMax ) { + Kp = HIndiceColonne[il]; + SolutionIntermediaire[Kp]-= HValeur[il] * S; + if ( NoeudDansLaliste[Kp] == NOEUD_HORS_LISTE ) { + NoeudDansLaliste[Kp] = NOEUD_DANS_LISTE; + IndexTermesNonNuls[i] = Kp; + i++; + } + il++; + } + } + } + k--; +} +*NbTermesNonNuls = i; + +return; +} +/*--------------------------------------------------------------------------------------------------*/ +char LU_LuSolvTriangleLTransposeeSecondMembreHyperCreux( MATRICE * Matrice, double * Solution, + int * NbTermesNonNuls, int * IndexTermesNonNuls ) +{ +int Kp ;int il; int ilMax; double X; int i; int NombreDeNoeudsDansLaListe; double * SolutionIntermediaire; +int * LdebParLigneDeL; double * ElmDeLParLigne; int * ListeDesNoeuds; int * OrdreLigne; int j; +int * IndiceColonneParLigneDeL; int * NbTermesParLigneDeL; char * NoeudDansLaliste; char CodeRet; +char AllocOk; + +/* Recusion sur le graphe */ +NombreDeNoeudsDansLaListe = 0; +NoeudDansLaliste = Matrice->NoeudDansLaliste; +for ( i = 0 ; i < *NbTermesNonNuls ; i++ ) NoeudDansLaliste[IndexTermesNonNuls[i]] = NOEUD_HORS_LISTE; + +if ( Matrice->LdebParLigneDeL == NULL ) { + /* Si le stockage par ligne de L n'existe pas on le cree */ + LU_ChainageParLigneDeL( Matrice, &AllocOk ); + /* En cas de probleme on repart sur la methode traditionnelles. Dans le methode traditionnelle on va + alors reessayer d'allouer et si ca passe pas, on utilisera uniquement le chainage pas colonne de L*/ + if ( AllocOk != OUI_LU ) return( RECURSION_NOT_OK ); +} + +LdebParLigneDeL = Matrice->LdebParLigneDeL; +IndiceColonneParLigneDeL = Matrice->IndiceColonneParLigneDeL; +NbTermesParLigneDeL = Matrice->NbTermesParLigneDeL; + +CodeRet = LU_RecusionSurTriangle_2( Matrice, IndexTermesNonNuls, *NbTermesNonNuls, LdebParLigneDeL, + IndiceColonneParLigneDeL, NbTermesParLigneDeL, &NombreDeNoeudsDansLaListe ); + +ListeDesNoeuds = Matrice->ListeDesNoeuds; +SolutionIntermediaire = Matrice->SolutionIntermediaire; + +if ( CodeRet == RECURSION_NOT_OK ) { + for ( i = 0 ; i < NombreDeNoeudsDansLaListe ; i++ ) NoeudDansLaliste[ListeDesNoeuds[i]] = NOEUD_HORS_LISTE; + return( RECURSION_NOT_OK ); +} + +OrdreLigne = Matrice->OrdreLigne; +ElmDeLParLigne = Matrice->ElmDeLParLigne; + +j = 0; +for ( i = NombreDeNoeudsDansLaListe - 1 ; i >= 0 ; i-- ) { + Kp = ListeDesNoeuds[i]; + NoeudDansLaliste[Kp] = NOEUD_HORS_LISTE; + if ( SolutionIntermediaire[Kp] == 0.0 ) continue; + X = SolutionIntermediaire[Kp]; + SolutionIntermediaire[Kp] = 0.0; + /*if ( X == 0.0 ) continue;*/ + + /* */ + il = LdebParLigneDeL[Kp]; + ilMax = il + NbTermesParLigneDeL[Kp]; + il++; + while ( il < ilMax ) { + SolutionIntermediaire[IndiceColonneParLigneDeL[il]] -= ElmDeLParLigne[il] * X; + il++; + } + + if ( fabs( X ) > ZERO_POUR_LE_RESULTAT_DE_LA_RESOLUTION_TRANSPOSEE ) { + Solution[j] = X; + IndexTermesNonNuls[j] = OrdreLigne[Kp]; + j++; + } + +} +*NbTermesNonNuls = j; + +X = Matrice->NombreDeRatiosTransposee * Matrice->RatioMoyenTransposee; +X+= (double) j / (double) Matrice->NbTermesAuDepartTransposee; +Matrice->NombreDeRatiosTransposee++; +Matrice->RatioMoyenTransposee = X / Matrice->NombreDeRatiosTransposee; + +return( RECURSION_OK ); +} + +/*--------------------------------------------------------------------------------------------------*/ +/* On a interet a ce que le type d'entree ne soit pas COMPACT_LU mais plutot ETENDUE_LU */ + +void LU_LuSolvSecondMembreHyperCreux( MATRICE * Matrice, double * SecondMembreEtSolution, + int * IndexTermesNonNuls, int * NbTermesNonNuls, + char TypeDEntree, char Save, char * TypeDeSortie ) +{ +double * SolEtSec; int i; char CodeRet; int CodeRetour; char AllocOk; + +Matrice->SauvegardeDuResultatIntermediaire = Save; + +/* Si SecondMembreEtSolution est donne sous forme comptacte, on fait un expand */ +if ( TypeDEntree == COMPACT_LU ) { + SolEtSec = Matrice->W; + for ( i = 0 ; i < *NbTermesNonNuls ; i++ ) { + SolEtSec[IndexTermesNonNuls[i]] = SecondMembreEtSolution[i]; + } +} +else SolEtSec = SecondMembreEtSolution; + +/* Si l'init n'a pas ete faite on la fait */ +if ( Matrice->PseudoPile == NULL ) { + LU_AllocEtInitHyperCreux( Matrice, &AllocOk ); + if ( AllocOk != OUI_LU ) { + /* On passe en mode normal */ + LU_LuSolvLuUpdate( Matrice, SolEtSec, &CodeRetour, Save, OUI_LU, NULL, 0, 0.0 ); + goto RestaurationSolution; + } +} + +/* Resolution de Ly = Pb avec P matrice de permutation des lignes et b + le second membre */ +CodeRet = LU_LuSolvTriangleLSecondMembreHyperCreux( Matrice, NbTermesNonNuls, IndexTermesNonNuls, SolEtSec ); +if ( CodeRet != POURSUITE_RESOLUTION_HYPER_CREUX ) { + /* On passe en mode normal car il y a trop de termes */ + if ( CodeRet == RECURSION_NOT_OK ) { + LU_LuSolvLuUpdate( Matrice, SolEtSec, &CodeRetour, Save, OUI_LU, NULL, 0, 0.0 ); + } + else { + LU_LuSolveH( Matrice ); + LU_LuSolvTriangleU( Matrice , SolEtSec ); + } + goto RestaurationSolution; + + /* Il faut mettre la solution dans SecondMembreEtSolution */ + /* + LU_MettreSolutionSousFormeHyperCreux( Matrice, SecondMembreEtSolution, IndexTermesNonNuls, NbTermesNonNuls, + SolEtSec, TypeDEntree, *TypeDeSortie ); + */ + Matrice->SauvegardeDuResultatIntermediaire = NON_LU; + return; +} + +LU_LuSolveHSecondMembreHyperCreux( Matrice , NbTermesNonNuls, IndexTermesNonNuls ); + +/* Resolution de U Q^t x = y avec Q matrice de permutation des colonnes */ +CodeRet = LU_LuSolvTriangleUSecondMembreHyperCreux( Matrice, SecondMembreEtSolution, NbTermesNonNuls, + IndexTermesNonNuls , *TypeDeSortie); + +if ( CodeRet == RECURSION_NOT_OK ) { + LU_LuSolvTriangleU( Matrice , SolEtSec ); + goto RestaurationSolution; + + /* Il faut mettre la solution dans SecondMembreEtSolution */ + /* + LU_MettreSolutionSousFormeHyperCreux( Matrice, SecondMembreEtSolution, IndexTermesNonNuls, NbTermesNonNuls, + SolEtSec, TypeDEntree, *TypeDeSortie ); + */ +} + +Matrice->SauvegardeDuResultatIntermediaire = NON_LU; + +return; + +RestaurationSolution: +*TypeDeSortie = VECTEUR_LU; +if ( TypeDEntree == COMPACT_LU ) { + memcpy( (char *) SecondMembreEtSolution, (char *) SolEtSec, Matrice->Rang * sizeof(double) ); + memset( (char *) SolEtSec, 0, Matrice->Rang * sizeof(double) ); +} + +Matrice->SauvegardeDuResultatIntermediaire = NON_LU; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +void LU_LuSolvTransposeeSecondMembreHyperCreux( MATRICE * Matrice, double * SecondMembreEtSolution, + int * IndexTermesNonNuls, int * NbTermesNonNuls, + char TypeDEntree, char * TypeDeSortie ) +{ +double * SolEtSec; int i; char CodeRet; int CodeRetour; char AllocOk; + +/* Si SecondMembreEtSolution est donne sous forme comptacte, on fait un expand */ + +if ( TypeDEntree == COMPACT_LU ) { + SolEtSec = Matrice->W; + for ( i = 0 ; i < *NbTermesNonNuls ; i++ ) { + SolEtSec[IndexTermesNonNuls[i]] = SecondMembreEtSolution[i]; + } +} +else SolEtSec = SecondMembreEtSolution; + +/* Si l'init n'a pas ete faite on la fait */ +if ( Matrice->PseudoPile == NULL ) { + LU_AllocEtInitHyperCreux( Matrice, &AllocOk ); + if ( AllocOk != OUI_LU ) { + /* On passe en mode normal */ + LU_LuSolvTransposeeLuUpdate( Matrice, SolEtSec, &CodeRetour, OUI_LU, NULL, 0, 0.0 ); + goto RestaurationSolutionTransposee; + } +} + +CodeRet = LU_LuSolvTriangleUTransposeeSecondMembreHyperCreux( Matrice, NbTermesNonNuls, IndexTermesNonNuls, SolEtSec ); +if ( CodeRet != POURSUITE_RESOLUTION_HYPER_CREUX ) { + /* On passe en mode normal car il y a trop de termes */ + if ( CodeRet == RECURSION_NOT_OK ) { + LU_LuSolvTransposeeLuUpdate( Matrice, SolEtSec, &CodeRetour, OUI_LU, NULL, 0, 0.0 ); + } + else { + /*printf("On fait le calcul normal TRANSPOSEE car trop de termes dans la recursion \n");*/ + LU_LuSolveHTransposee( Matrice ); + LU_LuSolvTriangleLTransposee( Matrice , SolEtSec ); + } + goto RestaurationSolutionTransposee; + + /* On met la solution dans SecondMembreEtSolution et en plus toujours sous forme compacte */ + /* + LU_MettreSolutionSousFormeHyperCreux( Matrice, SecondMembreEtSolution, IndexTermesNonNuls, NbTermesNonNuls, + SolEtSec, TypeDEntree, TypeDeSortie ); + */ + return; +} + +LU_LuSolveHTransposeeSecondMembreHyperCreux( Matrice , NbTermesNonNuls, IndexTermesNonNuls ); + +/* Resolution de U Q^t x = y avec Q matrice de permutation des colonnes */ +CodeRet = LU_LuSolvTriangleLTransposeeSecondMembreHyperCreux( Matrice, SecondMembreEtSolution, NbTermesNonNuls, IndexTermesNonNuls ); +if ( CodeRet == RECURSION_NOT_OK ) { + LU_LuSolvTriangleLTransposee( Matrice , SolEtSec ); + goto RestaurationSolutionTransposee; + + /* On met la solution dans SecondMembreEtSolution et en plus toujours sous forme compacte */ + /* + TypeSor = COMPACT_LU; + LU_MettreSolutionSousFormeHyperCreux( Matrice, SecondMembreEtSolution, IndexTermesNonNuls, NbTermesNonNuls, + SolEtSec, TypeDEntree, TypeSor ); + */ +} +return; +RestaurationSolutionTransposee: +*TypeDeSortie = VECTEUR_LU; +if ( TypeDEntree == COMPACT_LU ) { + memcpy( (char *) SecondMembreEtSolution, (char *) SolEtSec, Matrice->Rang * sizeof(double) ); + memset( (char *) SolEtSec, 0, Matrice->Rang * sizeof(double) ); +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_MettreSolutionSousFormeHyperCreux( MATRICE * Matrice, double * SecondMembreEtSolution, + int * IndexTermesNonNuls, int * NbTermesNonNuls, + double * SolEtSec, char TypeDEntree, char TypeDeSortie ) +{ +double * W; int i; int j; + +if ( TypeDeSortie == COMPACT_LU ) { + if ( TypeDEntree == ADRESSAGE_INDIRECT_LU ) { + /* Verification pour debogage */ + if ( SecondMembreEtSolution != SolEtSec ) { + printf("BUG dans LU_MettreSolutionSousFormeHyperCreux\n"); + exit(0); + } + W = Matrice->W; /* Car Matrice->W n'a pas ete utilise */ + for ( j = 0 , i = 0 ; i < Matrice->Rang ; i++ ) { + if ( SolEtSec[i] != 0.0 ) { + W[j] = SolEtSec[i]; + IndexTermesNonNuls[j] = i; + j++; + } + } + /* On recopie W dans SecondMembreEtSolution et on remet W a 0 */ + for ( i = 0 ; i < j ; i++ ) { + SecondMembreEtSolution[i] = W[i]; + W[i] = 0.0; + } + } + else { /* TypeDEntree = COMPACT_LU */ + /* Verification pour debogage */ + if ( SecondMembreEtSolution == SolEtSec ) { + printf("BUG dans LU_MettreSolutionSousFormeHyperCreux\n"); + exit(0); + } + for ( j = 0 , i = 0 ; i < Matrice->Rang ; i++ ) { + if ( SolEtSec[i] != 0.0 ) { + SecondMembreEtSolution[j] = SolEtSec[i]; + SolEtSec[i] = 0.0; + IndexTermesNonNuls[j] = i; + j++; + } + } + } +} +else { /* TypeDeSortie = ADRESSAGE_INDIRECT_LU */ + if ( TypeDEntree == ADRESSAGE_INDIRECT_LU ) { + if ( SecondMembreEtSolution != SolEtSec ) { + printf("BUG dans LU_MettreSolutionSousFormeHyperCreux\n"); + exit(0); + } + /* Dans ce cas on avait deja fait SolEtSec = SecondMembreEtSolution */ + for ( j = 0 , i = 0 ; i < Matrice->Rang ; i++ ) { + if ( SecondMembreEtSolution[i] != 0.0 ) { + IndexTermesNonNuls[j] = i; + j++; + } + } + } + else { /* TypeDEntree = COMPACT_LU */ + if ( SecondMembreEtSolution == SolEtSec ) { + printf("BUG dans LU_MettreSolutionSousFormeHyperCreux\n"); + exit(0); + } + for ( j = 0 , i = 0 ; i < Matrice->Rang ; i++ ) { + SecondMembreEtSolution[i] = SolEtSec[i]; + if ( SolEtSec[i] != 0.0 ) { + SolEtSec[i] = 0.0; + IndexTermesNonNuls[j] = i; + j++; + } + } + } +} + +*NbTermesNonNuls = j; + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_scaling.c b/src/ext/Sirius_Solver/simplexe/lu/lu_scaling.c new file mode 100644 index 0000000000..da3b8d5da5 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_scaling.c @@ -0,0 +1,525 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Scaling. + On tient compte du fait que parfois il peut de pas exister + de chainage par colonne (cas symetrique). + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +# define NOMBRE_MAX_DE_PASSES_DE_SCALING 10 +# define ARRONDI_EN_PUISSANCES_DE_2 OUI_LU +# define ZERO 1.e-12 +# define ZERO_TEST_RAPPORT 1.e-12 + +/*----------------------------------------------------------------------------*/ + +void LU_CalculerLeScaling( MATRICE * Matrice ) +{ +int il; int ilDeb; int ilMax; int k; double X; double UnSurX; +int Ligne; int Colonne; int LigneColonne ; +char Flag; double Rapport ; double RapportPrecedent ; +double SeuilRapport ; double * ScaleX ; char ArrondiPuissanceDe2; +double * ScaleB ; int Rang ; double Pgt; double Ppt ; + +char * FlagDeColonne ; double * PlusGrandTermeDeColonne; +double * PlusPetitTermeDeColonne; double * UnSurXDeColonne ; +char ConserverLaSymetrie ; double PlusGrandTerme; double PlusPetitTerme; + +int * Ldeb; int * LNbTerm; int * LIndiceColonne; double * Elm; + +Rang = Matrice->Rang; + +if ( Matrice->SolutionSV == NULL ) Matrice->SolutionSV = (double *) malloc( Rang * sizeof( double ) ); +if ( Matrice->SolutionSV == NULL ) { + Matrice->FaireScaling = NON_LU; + return; +} + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; + +Pgt = -1.; +Ppt = LINFINI_LU; +Rapport = 1.; + +for ( LigneColonne = 0 ; LigneColonne < Rang ; LigneColonne++ ) { + Matrice->ScaleX[LigneColonne] = 1.; + Matrice->ScaleB[LigneColonne] = 1.; +} + +Matrice->ScalingEnPuissanceDe2 = ARRONDI_EN_PUISSANCES_DE_2; + +ConserverLaSymetrie = NON_LU; +if ( Matrice->LaMatriceEstSymetrique == OUI_LU && Matrice->FaireDuPivotageDiagonal == OUI_LU ) { + ConserverLaSymetrie = OUI_LU; +} + +FlagDeColonne = Matrice->Marqueur; +PlusGrandTermeDeColonne = Matrice->W; +PlusPetitTermeDeColonne = Matrice->SolutionIntermediaire; +UnSurXDeColonne = Matrice->SolutionSV; + +ScaleX = (double *) malloc( Rang * sizeof( double ) ); +ScaleB = (double *) malloc( Rang * sizeof( double ) ); +if ( ScaleX == NULL || ScaleB == NULL ) { + printf("Factorisation LU, sous-programme LU_CalculerLeScaling: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} + +Elm = (double *) malloc( Matrice->TailleAlloueeLignes * sizeof( double) ); +if ( Elm == NULL ) { + printf("Factorisation LU, sous-programme LU_CalculerLeScaling: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} + +/* Transfert dans une zone de travail */ +for ( Ligne = 0 ; Ligne < Rang ; Ligne++ ) { + il = Ldeb[Ligne]; + ilMax = il + LNbTerm[Ligne]; + while ( il < ilMax ) { + Elm[il] = Matrice->Elm[il]; + il++; + } +} + +RapportPrecedent = 0.0; +SeuilRapport = 1.e-6; + +ArrondiPuissanceDe2 = ARRONDI_EN_PUISSANCES_DE_2; + +/* Plusieurs passes */ + +for ( k = 0 ; k < NOMBRE_MAX_DE_PASSES_DE_SCALING ; k++ ) { + + #if VERBOSE_SCALING + if ( k >= 1 ) { + printf(" Avant passe de scaling LU num %d PlusPetitTerme %e PlusGrandTerme %e rapport %e \n", + k,Ppt,Pgt,Rapport); + } + #endif + + if ( k >= 1 ) { + if ( fabs ( RapportPrecedent - Rapport ) < SeuilRapport * RapportPrecedent ) break; + if ( RapportPrecedent < Rapport ) { + /* On recupere les coeff de l'etape precedente et on arrete */ + for ( LigneColonne = 0 ; LigneColonne < Rang ; LigneColonne++ ) { + Matrice->ScaleX[LigneColonne] = ScaleX[LigneColonne]; + Matrice->ScaleB[LigneColonne] = ScaleB[LigneColonne]; + } + break; + } + } + + if ( k > 0 ) RapportPrecedent = Rapport; + else RapportPrecedent = LINFINI_LU; + + /* Stockage du scaling precedent */ + for ( LigneColonne = 0 ; LigneColonne < Rang ; LigneColonne++ ) { + ScaleX[LigneColonne] = Matrice->ScaleX[LigneColonne]; + ScaleB[LigneColonne] = Matrice->ScaleB[LigneColonne]; + } + + if ( ConserverLaSymetrie == OUI_LU ) goto ScalingDesLignes; + + /*-------------------- Scaling des colonnes ------------------------*/ + + for ( Colonne = 0 ; Colonne < Rang ; Colonne++ ) { + FlagDeColonne[Colonne] = 0; + PlusGrandTermeDeColonne[Colonne] = -1.; + PlusPetitTermeDeColonne[Colonne] = LINFINI_LU; + } + /* Recherche PlusPetitTerme PlusGrandTerme */ + for ( Ligne = 0 ; Ligne < Rang ; Ligne++ ) { + il = Ldeb[Ligne]; + ilMax = il + LNbTerm[Ligne]; + while ( il < ilMax ) { + X = Elm[il]; + if( X > ZERO ) { + Colonne = LIndiceColonne[il]; + if ( X > PlusGrandTermeDeColonne[Colonne] ) { PlusGrandTermeDeColonne[Colonne] = X; FlagDeColonne[Colonne] = 1; } + if ( X < PlusPetitTermeDeColonne[Colonne] ) { PlusPetitTermeDeColonne[Colonne] = X; FlagDeColonne[Colonne] = 1; } + } + il++; + } + } + /* Calcul de la moyenne geometrique */ + for ( Colonne = 0 ; Colonne < Rang ; Colonne++ ) { + X = 1.; + UnSurXDeColonne[Colonne] = 1.; + if ( FlagDeColonne[Colonne] == 1 ) { + X = PlusGrandTermeDeColonne[Colonne] * PlusPetitTermeDeColonne[Colonne]; + X = sqrt( X ); + UnSurXDeColonne[Colonne] = 1. / X; + } + + if ( ArrondiPuissanceDe2 == OUI_LU ) LU_ArrondiEnPuissanceDe2( &UnSurXDeColonne[Colonne] ); + Matrice->ScaleX[Colonne]*= UnSurXDeColonne[Colonne]; + } + + /* Application de la participation au scaling */ + for ( Ligne = 0 ; Ligne < Rang ; Ligne++ ) { + il = Ldeb[Ligne]; + ilMax = il + LNbTerm[Ligne]; + while ( il < ilMax ) { + Elm[il] *= UnSurXDeColonne[LIndiceColonne[il]]; + il++; + } + } + + /*-------------------- Scaling des lignes ------------------------*/ + ScalingDesLignes: + /* Lignes */ + + Pgt = -1.; + Ppt = LINFINI_LU; + + for ( Ligne = 0 ; Ligne < Rang ; Ligne++ ) { + Flag = 0; + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_LU; + /* */ + ilDeb = Ldeb[Ligne]; + ilMax = ilDeb + LNbTerm[Ligne]; + il = ilDeb; + while ( il < ilMax ) { + X = Elm[il]; + if( X > ZERO ) { + if ( X > PlusGrandTerme ) { PlusGrandTerme = X; Flag = 1; } + if ( X < PlusPetitTerme ) { PlusPetitTerme = X; Flag = 1; } + } + il++; + } + X = 1.; + UnSurX = 1.; + if ( Flag == 1 ) { + X = sqrt( PlusGrandTerme * PlusPetitTerme ); + UnSurX = 1. / X; + } + + /* Si on doit conserver la symetrie il faut prendre la racine carree afin d'appliquer la meme + valeur au scaling par colonne */ + if ( ConserverLaSymetrie == OUI_LU ) UnSurX = sqrt( UnSurX ); + + if ( ArrondiPuissanceDe2 == OUI_LU ) LU_ArrondiEnPuissanceDe2( &UnSurX ); + Matrice->ScaleB[Ligne]*= UnSurX; + + if ( ConserverLaSymetrie == OUI_LU ) UnSurXDeColonne[Ligne] = UnSurX; + + /* Scaling de A */ + if ( ConserverLaSymetrie != OUI_LU ) { + il = ilDeb; + while ( il < ilMax ) { + Elm[il]*= UnSurX; + if( Elm[il] > ZERO_TEST_RAPPORT ) { + if ( Elm[il] > Pgt ) Pgt = Elm[il]; + if ( Elm[il] < Ppt ) Ppt = Elm[il]; + } + il++; + } + } + else { + /* Le test sur Pgt et Ppt est fait apres */ + il = ilDeb; + while ( il < ilMax ) { + Elm[il]*= UnSurX; + il++; + } + } + + } + + if ( ConserverLaSymetrie == OUI_LU ) { + /* Application de la participation au scaling par colonne */ + for ( Ligne = 0 ; Ligne < Rang ; Ligne++ ) { + il = Ldeb[Ligne]; + ilMax = il + LNbTerm[Ligne]; + while ( il < ilMax ) { + Elm[il] *= UnSurXDeColonne[LIndiceColonne[il]]; + if( Elm[il] > ZERO_TEST_RAPPORT ) { + if ( Elm[il] > Pgt ) Pgt = Elm[il]; + if ( Elm[il] < Ppt ) Ppt = Elm[il]; + } + il++; + } + } + } + + Rapport = Pgt / Ppt; + + /* Fin Boucle generale de scaling */ +} + +if ( ConserverLaSymetrie == OUI_LU ) { + /* Comme dans ce cas on n'a pas mis a jour ScaleX a chaque iteration de scaling, on le fait maintenant */ + memcpy( (char *) Matrice->ScaleX, ( char *) Matrice->ScaleB, Rang * sizeof( double ) ); +} + +#if VERBOSE_SCALING + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_LU; + for ( Ligne = 0 ; Ligne < Rang ; Ligne++ ) { + il = Ldeb[Ligne]; + ilMax = il + LNbTerm[Ligne]; + while ( il < ilMax ) { + X = fabs( Elm[il] ); + if( /*X > ZERO*/ X > ZERO_TEST_RAPPORT ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + il++; + } + } + Rapport = PlusGrandTerme/PlusPetitTerme; + printf(" A la fin des calculs des coefficients de scaling: \n"); + printf(" PlusPetitTerme %e PlusGrandTerme %e rapport %e \n",PlusPetitTerme,PlusGrandTerme,Rapport); + + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_LU; + for ( Ligne = 0 ; Ligne < Rang ; Ligne++ ) { + if ( Matrice->ScaleX[Ligne] < PlusPetitTerme ) PlusPetitTerme = Matrice->ScaleX[Ligne]; + if ( Matrice->ScaleX[Ligne] > PlusGrandTerme ) PlusGrandTerme = Matrice->ScaleX[Ligne] ; + } + printf(" Plus petit ScaleX %e Plus grand ScaleX %e\n",PlusPetitTerme,PlusGrandTerme); + + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_LU; + for ( Ligne = 0 ; Ligne < Rang ; Ligne++ ) { + if ( Matrice->ScaleB[Ligne] < PlusPetitTerme ) PlusPetitTerme = Matrice->ScaleB[Ligne]; + if ( Matrice->ScaleB[Ligne] > PlusGrandTerme ) PlusGrandTerme = Matrice->ScaleB[Ligne] ; + } + printf(" Plus petit ScaleB %e Plus grand ScaleB %e\n",PlusPetitTerme,PlusGrandTerme); + +#endif + +/* Nettoyages */ +{ char * Marqueur; double * W; double * SolutionIntermediaire; + double * SolutionSV; + Marqueur = Matrice->Marqueur; + W = Matrice->W; + SolutionIntermediaire = Matrice->SolutionIntermediaire; + SolutionSV = Matrice->SolutionSV ; + for ( LigneColonne = 0 ; LigneColonne < Rang ; LigneColonne++ ) { + /* On remet a jour Marqueur car il etait utilise avec FlagDeColonne */ + Marqueur[LigneColonne] = 0; + /* On remet a jour W car il etait utilise avec PlusGrandTermeDeColonne */ + W[LigneColonne] = 0.0; + /* On remet a jour SolutionIntermediaire car il etait utilise avec PlusPetitTermeDeColonne */ + SolutionIntermediaire[LigneColonne] = 0.0; + /* On remet a jour SolutionSV car il etait utilise avec UnSurXDeColonne */ + SolutionSV[LigneColonne] = 0.0; + } +} + +free( ScaleX ); +free( ScaleB ); +free( Elm ); + +return; +} + +/*------------------------------------------------------------------------*/ + +void LU_ArrondiEnPuissanceDe2( double * ValeurRetenue ) +{ + double X; int P2; + +X = *ValeurRetenue; +frexp( X , &P2 ); +*ValeurRetenue = ldexp( 1. , P2 ); + +return; +} + +/*------------------------------------------------------------------------*/ +/* Scaling */ +/* Apres avoir calcule les matrices de scaling, on fait le scaling. */ + +void LU_Scaling( MATRICE * Matrice ) +{ + +int Ligne; int il; double X; int ilMax; double * ScaleX; double * ScaleB; +# if VERBOSE_SCALING + double PlusGrandTerme; double PlusPetitTerme; double Rapport; +# endif + +int * Ldeb; int * LNbTerm; int * LIndiceColonne; double * Elm; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; +ScaleX = Matrice->ScaleX; +ScaleB = Matrice->ScaleB; +/* Maintenant on fait le scaling effectif */ +/* 1- Scaling des colonnes */ +for ( Ligne = 0 ; Ligne < Matrice->Rang ; Ligne++ ) { + /* Scaling de la matrice des contraintes */ + il = Ldeb[Ligne]; + ilMax = il + LNbTerm[Ligne]; + while ( il < ilMax ) { + Elm[il]*= ScaleX[LIndiceColonne[il]]; + il++; + } +} +/* 2- Scaling des lignes */ +for ( Ligne = 0 ; Ligne < Matrice->Rang ; Ligne++ ) { + X = ScaleB[Ligne]; + il = Ldeb[Ligne]; + ilMax = il + LNbTerm[Ligne]; + while ( il < ilMax ) { + Elm[il]*= X; + il++; + } +} + +#if VERBOSE_SCALING + +/* Verification */ + +printf("Verification apres application effective du scaling:\n"); + +PlusGrandTerme = -1.; +PlusPetitTerme = LINFINI_LU; + +for ( Ligne = 0 ; Ligne < Matrice->Rang ; Ligne++ ) { + il = Ldeb[Ligne]; + ilMax = il + LNbTerm[Ligne]; + while ( il < ilMax ) { + X = fabs( Elm[il] ); + if( X > ZERO_TEST_RAPPORT ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + il++; + } +} + +Rapport = PlusGrandTerme/PlusPetitTerme; + +printf(" PlusPetitTerme %e PlusGrandTerme %e rapport %e \n",PlusPetitTerme,PlusGrandTerme,Rapport); + +#endif + +return; +} + +/*------------------------------------------------------------------------*/ +/* Scaling du second membre avant resolution */ + +void LU_ScalingSecondMembre( MATRICE * Matrice , double * B ) +{ +int i; double f; int Exposant; int ExposantScale; double * ScaleB; + +ScaleB = Matrice->ScaleB; +if ( Matrice->ScalingEnPuissanceDe2 != OUI_LU || 1 /* Car il est inutile de passer par les frexp */ ) { + for ( i = 0 ; i < Matrice->Rang ; i++ ) B[i] *= ScaleB[i]; +} +else { + for ( i = 0 ; i < Matrice->Rang ; i++ ) { + frexp( ScaleB[i] , &ExposantScale ); + ExposantScale--; + f = frexp( B[i] , &Exposant ); + B[i] = ldexp( f , Exposant + ExposantScale ); + } +} + +return; +} + +void LU_ScalingSecondMembreTranspose( MATRICE * Matrice , double * B ) +{ +int i; double f; int Exposant; int ExposantScale; double * ScaleX; + +ScaleX = Matrice->ScaleX; +if ( Matrice->ScalingEnPuissanceDe2 != OUI_LU || 1 /* Car il est inutile de passer par les frexp */ ) { + for ( i = 0 ; i < Matrice->Rang ; i++ ) B[i] *= ScaleX[i]; +} +else { + for ( i = 0 ; i < Matrice->Rang ; i++ ) { + frexp( ScaleX[i] , &ExposantScale ); + ExposantScale--; + f = frexp( B[i] , &Exposant ); + B[i] = ldexp( f , Exposant + ExposantScale ); + } +} + +return; +} + +/*------------------------------------------------------------------------*/ +/* UnScaling */ + +void LU_UnScaling( MATRICE * Matrice , double * Solution ) +{ +int i; double f; int Exposant; int ExposantScale; double * ScaleX; + +ScaleX = Matrice->ScaleX; +if ( Matrice->ScalingEnPuissanceDe2 != OUI_LU || 1 /* Car il est inutile de passer par les frexp */ ) { + for ( i = 0 ; i < Matrice->Rang ; i++ ) Solution[i] *= ScaleX[i]; +} +else { + for ( i = 0 ; i < Matrice->Rang ; i++ ) { + frexp( ScaleX[i] , &ExposantScale ); + ExposantScale--; + f = frexp( Solution[i] , &Exposant ); + Solution[i] = ldexp( f , Exposant + ExposantScale ); + } +} + +return; +} + +void LU_UnScalingTranspose( MATRICE * Matrice , double * Solution ) +{ +int i; double f; int Exposant; int ExposantScale; double * ScaleB; + +ScaleB = Matrice->ScaleB; +if ( Matrice->ScalingEnPuissanceDe2 != OUI_LU || 1 /* Car il est inutile de passer par les frexp */ ) { + for ( i = 0 ; i < Matrice->Rang ; i++ ) Solution[i] *= ScaleB[i]; +} +else { + for ( i = 0 ; i < Matrice->Rang ; i++ ) { + frexp( ScaleB[i] , &ExposantScale ); + ExposantScale--; + f = frexp( Solution[i] , &Exposant ); + Solution[i] = ldexp( f , Exposant + ExposantScale ); + } +} + +return; +} + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_scan_ligne.c b/src/ext/Sirius_Solver/simplexe/lu/lu_scan_ligne.c new file mode 100644 index 0000000000..721605c78d --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_scan_ligne.c @@ -0,0 +1,185 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU de la base. Modification des lignes + suite a l'elimination de la ligne pivot. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------------------------------------------*/ +/* Les termes de la ligne pivot sont compares a ceux de la ligne scannee et les nouvelle valeurs + des termes de la ligne scannee sont calculees */ + +void LU_ScanLigne( MATRICE * Matrice, + int Ligne, + int ilDebLignePivot, + int NbNonuLignePivot, + double ValTermeColonnePivot, + int LignePivot, + char * StockageLignesRedimensionne, + char * StockageColonnesRedimensionne + ) +{ +int il; int ilDeb; int ilLigne; int f; int Demande; int NbTermesLigne; int NbTermesLignePivot; +int Colonne; int NbTermesColonne; char UtiliserLesSuperLignes; int * CNbTermMatriceActive; +double * W; char * T; char Augmenter; +int * LIndiceColonne; double * Elm; +int * Cdeb; int * CNbTerm; int * CIndiceLigne; int * CDernierPossible; + +unsigned int * HashCode; int * PoidsDesColonnes; unsigned int DeltaHashCode; + +UtiliserLesSuperLignes = Matrice->UtiliserLesSuperLignes; + +ilDeb = Matrice->Ldeb[Ligne]; +NbTermesLigne = Matrice->LNbTerm[Ligne]; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +W = Matrice->W; +T = Matrice->Marqueur; + +*StockageLignesRedimensionne = NON_LU; +*StockageColonnesRedimensionne = NON_LU; + +/* f sert a mesurer le "fill-in" */ +f = NbNonuLignePivot; /* Nombre de termes de la ligne pivot moins le terme pivot */ + +/* Transformation des termes de la ligne scannee */ +for ( il = ilDeb ; il < ilDeb + NbTermesLigne ; il++ ) { + Colonne = LIndiceColonne[il]; + /* Si Colonne est egal a ColonnePivot alors on a Matrice.Marqueur[Colonne] = 0 */ + if ( T[Colonne] == 1 ) { + T[Colonne] = 0; + /* Calcul du terme modifie */ + Elm[il]-= W[Colonne] * ValTermeColonnePivot; + /* Comme il y a deja un terme dans la ligne scannee, il n'y a pas de "fill-in" a cet endroit */ + f--; + if ( f == 0 ) goto ControleFillIn; + } +} + +/* Controle du fill in */ +ControleFillIn: + +NbTermesLignePivot = NbNonuLignePivot + 1; + +if ( f > 0 ) { + if ( UtiliserLesSuperLignes == OUI_LU ) { + HashCode = &(Matrice->HashCodeLigne[Ligne]); + PoidsDesColonnes = Matrice->PoidsDesColonnes; + DeltaHashCode = 0; + } + + Matrice->NbFillIn += f; + Matrice->CompteurExclusionMarkowitz += f; + Matrice->NombreDeTermes += f; + + /* Il y a un "fill-in" de f termes => on scanne la ligne pivot pour pouvoir calculer et + stocker les termes crees . Les termes crees sont chaines en fin de ligne */ + if ( ilDeb + NbTermesLigne + f - 1 > Matrice->LDernierPossible[Ligne] ) { + Demande = NbTermesLigne + f; + LU_AugmenterLaTailleDeLaMatriceActive( Matrice , Ligne , Demande ); + *StockageLignesRedimensionne = OUI_LU; + ilDeb = Matrice->Ldeb[Ligne]; + LIndiceColonne = Matrice->LIndiceColonne; + Elm = Matrice->Elm; + ilDebLignePivot = Matrice->Ldeb[LignePivot]; + } + + ilLigne = ilDeb + NbTermesLigne; + + Cdeb = Matrice->Cdeb; + CNbTerm = Matrice->CNbTerm; + CNbTermMatriceActive = Matrice->CNbTermMatriceActive; + CIndiceLigne = Matrice->CIndiceLigne; + CDernierPossible = Matrice->CDernierPossible; + + for ( il = ilDebLignePivot ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + if ( T[Colonne] == 1 ) { + /* On ajoute un terme dans la ligne */ + Elm [ilLigne] = -W[Colonne] * ValTermeColonnePivot; + LIndiceColonne[ilLigne] = Colonne; + ilLigne++; + NbTermesLigne++; + + /* "Marqueur" est encore egal a 1 => il n'y avait pas de terme a cet IndiceColonne + dans la ligne scannee: on a trouve un "fill-in" */ + NbTermesColonne = CNbTerm[Colonne]; + if ( Cdeb[Colonne] + NbTermesColonne > CDernierPossible[Colonne] ) { + Augmenter = OUI_LU; + /* On verifie d'abord si en compactant la colonne il reste de la place */ + if ( NbTermesColonne != CNbTermMatriceActive[Colonne] ) { + LU_SupprimerTermesInutilesDansColonne( Matrice , Colonne , Cdeb[Colonne] ); + /* Il faut reinitialiser car il est possible qu'on ait compacte la colonne */ + NbTermesColonne = CNbTerm[Colonne]; + /* On refait le test afin d'augmenter la taille de la colonne si le compactage n'a pas suffit */ + if ( Cdeb[Colonne] + NbTermesColonne > CDernierPossible[Colonne] ) Augmenter = OUI_LU; + else Augmenter = NON_LU; + } + if ( Augmenter == OUI_LU ) { + LU_AugmenterLaTailleDeLaMatriceActiveParColonne( Matrice, Colonne, NbTermesColonne + 1); + *StockageColonnesRedimensionne = OUI_LU; + CIndiceLigne = Matrice->CIndiceLigne; + /* Il faut reinitialiser car il est possible qu'on ait compacte la colonne */ + NbTermesColonne = CNbTerm[Colonne]; + } + } + + if ( UtiliserLesSuperLignes == OUI_LU ) DeltaHashCode+= PoidsDesColonnes[Colonne]; + + /* Mise a jour du chainage par colonne: le nouveau terme doit etre chaine dans le + chainage par colonne */ + CIndiceLigne[ Cdeb[Colonne] + NbTermesColonne] = Ligne; + + CNbTerm[Colonne]++; + CNbTermMatriceActive[Colonne]++; + + f--; + if ( f == 0 ) { il++; break;} + } + else T[Colonne] = 1; + } + while ( il < ilDebLignePivot + NbTermesLignePivot ) { + T[LIndiceColonne[il]] = 1; + il++; + } + Matrice->LNbTerm[Ligne] = NbTermesLigne; + + if ( UtiliserLesSuperLignes == OUI_LU ) *HashCode = *HashCode + DeltaHashCode; + +} +else { + /* Pas de "fill-in" : on remet Matrice.Marqueur aux bonnes valeurs */ + for ( il = ilDebLignePivot ; il != ilDebLignePivot + NbTermesLignePivot ; il++ ) { + T[LIndiceColonne[il]] = 1; + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_scan_ligne_cas_symetrique.c b/src/ext/Sirius_Solver/simplexe/lu/lu_scan_ligne_cas_symetrique.c new file mode 100644 index 0000000000..324011a46c --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_scan_ligne_cas_symetrique.c @@ -0,0 +1,170 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU cas symetrique. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ +/* Les termes de la ligne pivot sont compares a ceux de la ligne scannee et les nouvelle valeurs + des termes de la ligne scannee sont calculees */ + +void LU_ScanLigneCasSymetrique( MATRICE * Matrice , + int Ligne, + int ilDebLignePivot, + int NbNonuLignePivot, + double ValTermeColonnePivot, + int LignePivot, + char * StockageLignesRedimensionne + ) +{ +int il; int ilDeb; double * W; char * T; int Demande; int NbTermesLigne; int NbTermesLignePivot; int Colonne; +int f; char UtiliserLesSuperLignes; unsigned int * HashCode; int * PoidsDesColonnes; unsigned int DeltaHashCode; +int * LIndiceColonne; double * Elm; int ilLigne; + +W = Matrice->W; +T = Matrice->Marqueur; + +UtiliserLesSuperLignes = Matrice->UtiliserLesSuperLignes; + +ilDeb = Matrice->Ldeb[Ligne]; +NbTermesLigne = Matrice->LNbTerm[Ligne]; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +f = NbNonuLignePivot; /* Nombre de termes de la ligne pivot moins le terme pivot */ + +if ( UtiliserLesSuperLignes == OUI_LU ) { + HashCode = &(Matrice->HashCodeLigne[Ligne]); + PoidsDesColonnes = Matrice->PoidsDesColonnes; + DeltaHashCode = 0; +} + +/* Transformation des termes de la ligne scannee */ +il = ilDeb; +Colonne = LIndiceColonne[il]; +for ( ; Colonne != LignePivot ; il++ , Colonne = LIndiceColonne[il] ) { + if ( T[Colonne] == 1 ) { + T[Colonne] = 0; + /* Calcul du terme modifie */ + Elm[il]-= W[Colonne] * ValTermeColonnePivot; + /* Comme il y a deja un terme dans la ligne scannee, il n'y a pas de "fill-in" a cet endroit */ + f--; + if ( f == 0 ) break; + } +} +if ( LIndiceColonne[il] == LignePivot ) { + /* On est sorti pour avoir rencontre le terme colonne pivot */ + NbTermesLigne--; + Elm [il] = Elm[ilDeb + NbTermesLigne]; + LIndiceColonne[il] = LIndiceColonne[ilDeb + NbTermesLigne]; + + if ( UtiliserLesSuperLignes == OUI_LU ) DeltaHashCode-= PoidsDesColonnes[LignePivot]; + + for ( ; il < ilDeb + NbTermesLigne ; il++ ) { + Colonne = LIndiceColonne[il]; + /* Si Colonne est egal a ColonnePivot alors on a T[Colonne] = 0 */ + if ( T[Colonne] == 1 ) { + /* Calcul du terme modifie */ + Elm[il]-= W[LIndiceColonne[il]] * ValTermeColonnePivot; + T[LIndiceColonne[il]] = 0; + /* Comme il y a deja un terme dans la ligne scannee, il n'y a pas de "fill-in" a cet endroit */ + f--; + if ( f == 0 ) break; + } + } +} +else { + /* On est sorti par f = 0 */ + il++; + for ( ; LIndiceColonne[il] != LignePivot ; il++ ); + NbTermesLigne--; + Elm [il] = Elm[ilDeb + NbTermesLigne]; + LIndiceColonne[il] = LIndiceColonne[ilDeb + NbTermesLigne]; + + if ( UtiliserLesSuperLignes == OUI_LU ) DeltaHashCode-= PoidsDesColonnes[LignePivot]; + +} + +NbTermesLignePivot = NbNonuLignePivot + 1; + +if ( f > 0 ) { + /* Il y a un "fill-in" => on scanne la ligne pivot pour pouvoir calculer et + stocker les termes crees . Les termes crees sont chaines en fin de ligne */ + if ( ilDeb + NbTermesLigne + f - 1 > Matrice->LDernierPossible[Ligne] ) { + Demande = NbTermesLigne + f; + LU_AugmenterLaTailleDeLaMatriceActive( Matrice , Ligne , Demande ); + *StockageLignesRedimensionne = OUI_LU; + ilDeb = Matrice->Ldeb[Ligne]; + LIndiceColonne = Matrice->LIndiceColonne; + Elm = Matrice->Elm; + ilDebLignePivot = Matrice->Ldeb[LignePivot]; + } + Matrice->NbFillIn+= f; + Matrice->CompteurExclusionMarkowitz+= f; + Matrice->NombreDeTermes+= f; + + ilLigne = ilDeb + NbTermesLigne; + + /* On commence a 1 car terme diagonal range en premier */ + for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + if ( T[Colonne] == 1 ) { + /* "Marqueur" est encore egal a 1 => il n'y avait pas de terme a cet IndiceColonne + dans la ligne scanne: on a trouve un "fill-in" */ + Elm [ilLigne] = -W[Colonne] * ValTermeColonnePivot; + LIndiceColonne[ilLigne] = Colonne; + ilLigne++; + NbTermesLigne++; + + if ( UtiliserLesSuperLignes == OUI_LU ) DeltaHashCode+= PoidsDesColonnes[Colonne]; + + f--; + if ( f == 0 ) { il++; break;} + } + else T[Colonne] = 1; + } + while ( il < ilDebLignePivot + NbTermesLignePivot ) { + T[LIndiceColonne[il]] = 1; + il++; + } +} +else { + /* Pas de "fill-in" : on remet Matrice.Marqueur aux bonnes valeurs */ + /* Terme diagonal range en premier */ + for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + T[LIndiceColonne[il]] = 1; + } +} +/* Il faut le laisser la car on a enleve le terme sur la colonne pivot */ +Matrice->LNbTerm[Ligne] = NbTermesLigne; + +if ( UtiliserLesSuperLignes == OUI_LU ) *HashCode = *HashCode + DeltaHashCode; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_scan_ligne_matrice_pleine.c b/src/ext/Sirius_Solver/simplexe/lu/lu_scan_ligne_matrice_pleine.c new file mode 100644 index 0000000000..55a78bbbc9 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_scan_ligne_matrice_pleine.c @@ -0,0 +1,155 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU de la base. + Scan ligne dans le cas ou la matrice est pleine. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------------------------------------------*/ +/* Les termes de la ligne pivot sont compares a ceux de la ligne scannee et les nouvelle valeurs + des termes de la ligne scannee sont calculees */ + +void LU_ScanLigneMatricePleine ( MATRICE * Matrice, + int Ligne, + int ColonnePivot, + double ValTermeColonnePivot + ) +{ +int il; int ilDeb; int Colonne; double X; double Y; int NbTermesLigne; +int * LIndiceColonne; double * Elm; + +/* Transformation des termes de la ligne scannee */ + +ilDeb = Matrice->Ldeb[Ligne]; +NbTermesLigne = Matrice->LNbTerm[Ligne]; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +if ( Matrice->FaireDuPivotageDiagonal == NON_LU ) { + for ( il = ilDeb ; il < ilDeb + NbTermesLigne ; il++ ) { + Colonne = LIndiceColonne[il]; + /* Calcul du terme modifie */ + /* W[ColonnePivot] a ete force a 0 pour eviter le test "IndiceColonne ? ColonnePivot" */ + X = Elm[il] - ( Matrice->W[Colonne] * ValTermeColonnePivot ); + Elm[il] = X; + Y = fabs( X ); + if ( Y > Matrice->ValeurDuPlusGrandTerme ) { + if ( Colonne != ColonnePivot ) { + Matrice->ValeurDuPlusGrandTerme = Y; + Matrice->LigneDuPlusGrandTerme = Ligne; + Matrice->ColonneDuPlusGrandTerme = Colonne; + } + } + } +} +else { + /* Cas du pivotage diagonal */ + for ( il = ilDeb ; il < ilDeb + NbTermesLigne ; il++ ) { + Colonne = LIndiceColonne[il]; + /* Calcul du terme modifie */ + /* W[ColonnePivot] a ete force a 0 pour eviter le test "IndiceColonne ? ColonnePivot" */ + X = Elm[il] - ( Matrice->W[Colonne] * ValTermeColonnePivot ); + Elm[il] = X; + if ( Colonne == Ligne ) { + Y = fabs( X ); + if ( Y > Matrice->ValeurDuPlusGrandTerme ) { + if ( Colonne != ColonnePivot ) { + Matrice->ValeurDuPlusGrandTerme = Y; + Matrice->LigneDuPlusGrandTerme = Ligne; + Matrice->ColonneDuPlusGrandTerme = Ligne; + } + } + } + } +} + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_scan_super_ligne.c b/src/ext/Sirius_Solver/simplexe/lu/lu_scan_super_ligne.c new file mode 100644 index 0000000000..23c070df2b --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_scan_super_ligne.c @@ -0,0 +1,185 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU de la base. Modification des lignes + suite a l'elimination de la ligne pivot dans le cas ou + la ligne scannee est une SuperLigne. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------------------------------------------*/ +/* Les termes de la ligne pivot sont compares a ceux de la ligne scannee et les nouvelle valeurs + des termes de la ligne scannee sont calculees */ + +void LU_ScanSuperLigne( MATRICE * Matrice, + SUPER_LIGNE_DE_LA_MATRICE * SuperLigne, + int ilDebLignePivot, + int NbNonuLignePivot, + double * ValeurDesTermesDeColonnePivot, + unsigned int * hashCode + ) +{ +int il ; int f ; int i ; int NbTermesLignePivot; int NbTCol; unsigned int DeltaHashCode; +int CapaciteMinDemandee; int Colonne; double X ; int ic; int * PoidsDesColonnes; +double * W; char * T; double * ElmColonneDeSuperLigne ; int * IndiceColonne; int CapaciteDesColonnes; +int NombreDeLignesDeLaSuperLigne; int * NumerosDesLignesDeLaSuperLigne; int * CNbTermMatriceActive; +int NombreDeTermes; int icDeb; char Augmenter; +int * LIndiceColonne; int * Cdeb; int * CNbTerm; int * CIndiceLigne; int * CDernierPossible; + +W = Matrice->W; +T = Matrice->Marqueur; + +LIndiceColonne = Matrice->LIndiceColonne; + +ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; +IndiceColonne = SuperLigne->IndiceColonne; +CapaciteDesColonnes = SuperLigne->CapaciteDesColonnes; +NombreDeLignesDeLaSuperLigne = SuperLigne->NombreDeLignesDeLaSuperLigne; +NombreDeTermes = SuperLigne->NombreDeTermes; + +/* f sert a mesurer le "fill-in" */ +f = NbNonuLignePivot; /* Nombre de termes de la ligne pivot moins le terme pivot */ + +/* Transformation des termes de la ligne scannee */ +for ( il = 0 ; il < NombreDeTermes ; il++ ) { + Colonne = IndiceColonne[il]; + /* Si Colonne est egal a ColonnePivot alors on a Matrice.Marqueur[Colonne] = 0 */ + if ( T[Colonne] == 1 ) { + T[Colonne] = 0; + /* Calcul du terme modifie: on balaye la colonne de la SuperLigne */ + ic = CapaciteDesColonnes * il; + X = W[Colonne]; + for ( i = 0 ; i < NombreDeLignesDeLaSuperLigne ; i++ , ic++ ) { + ElmColonneDeSuperLigne[ic]-= X * ValeurDesTermesDeColonnePivot[i]; + } + /* Comme il y a deja un terme dans la ligne scannee, il n'y a pas de "fill-in" a cet endroit */ + f--; + if ( f == 0 ) goto ControleFillIn; + } +} + +/* Controle du fill in */ +ControleFillIn: + +NbTermesLignePivot = NbNonuLignePivot + 1; + +if ( f > 0 ) { + + DeltaHashCode = 0; + + Matrice->CompteurExclusionMarkowitz+= f; + Matrice->NombreDeTermes+= f * NombreDeLignesDeLaSuperLigne; + Matrice->NbFillIn+= f * NombreDeLignesDeLaSuperLigne; + + Cdeb = Matrice->Cdeb; + CNbTerm = Matrice->CNbTerm; + CNbTermMatriceActive = Matrice->CNbTermMatriceActive; + CIndiceLigne = Matrice->CIndiceLigne; + CDernierPossible = Matrice->CDernierPossible; + + /* Il y a un "fill-in" => on scanne la ligne pivot pour pouvoir calculer et + stocker les termes crees . Les termes crees sont chaines en fin de ligne */ + if ( NombreDeTermes + f > SuperLigne->Capacite ) { + CapaciteMinDemandee = NombreDeTermes + f; + LU_AugmenterCapaciteDeSuperLigne( Matrice , SuperLigne , CapaciteMinDemandee ); + ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; + IndiceColonne = SuperLigne->IndiceColonne; + } + + NumerosDesLignesDeLaSuperLigne = SuperLigne->NumerosDesLignesDeLaSuperLigne; + PoidsDesColonnes = Matrice->PoidsDesColonnes; + for ( il = ilDebLignePivot ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + if ( T[Colonne] == 1 ) { + /* "Marqueur" est encore egal a 1 => il n'y avait pas de terme a cet IndiceColonne + dans la SuperLigne scannee: on a trouve un "fill-in" */ + X = W[Colonne]; + ic = CapaciteDesColonnes * NombreDeTermes; + for ( i = 0 ; i < NombreDeLignesDeLaSuperLigne ; i++ , ic++ ) { + ElmColonneDeSuperLigne[ic] = -X * ValeurDesTermesDeColonnePivot[i]; + } + IndiceColonne[NombreDeTermes] = Colonne; + NombreDeTermes++; + + DeltaHashCode+= PoidsDesColonnes[Colonne]; + + /* On met a jour le stockage par colonne pour y ajouter NombreDeLignesDeLaSuperLigne termes */ + NbTCol = CNbTerm[Colonne]; + if ( Cdeb[Colonne] + NbTCol + NombreDeLignesDeLaSuperLigne > CDernierPossible[Colonne] ) { + + Augmenter = OUI_LU; + /* On verifie d'abord si en compactant la colonne il reste de la place */ + if ( NbTCol != CNbTermMatriceActive[Colonne] ) { + LU_SupprimerTermesInutilesDansColonne( Matrice , Colonne , Cdeb[Colonne] ); + /* Il faut reinitialiser car il est possible qu'on ait compacte la colonne */ + NbTCol = CNbTerm[Colonne]; + /* On refait le test afin d'augmenter la taille de la colonne si le compactage n'a pas suffit */ + if ( Cdeb[Colonne] + NbTCol + NombreDeLignesDeLaSuperLigne > CDernierPossible[Colonne] ) Augmenter = OUI_LU; + else Augmenter = NON_LU; + } + + if ( Augmenter == OUI_LU ) { + LU_AugmenterLaTailleDeLaMatriceActiveParColonne( Matrice, Colonne, NbTCol + NombreDeLignesDeLaSuperLigne ); + CIndiceLigne = Matrice->CIndiceLigne; + /* Il faut reinitialiser car il est possible qu'on ait compacte la colonne */ + NbTCol = CNbTerm[Colonne]; + } + } + icDeb = Cdeb[Colonne]; + for ( i = 0 ; i < NombreDeLignesDeLaSuperLigne ; i++ ) { + /* On ajoute le terme dans la colonne */ + CIndiceLigne[icDeb + NbTCol] = NumerosDesLignesDeLaSuperLigne[i]; + NbTCol++; + } + CNbTerm[Colonne] = NbTCol; + CNbTermMatriceActive[Colonne] = NbTCol; + + f--; + if ( f <= 0 ) { il++; break;} + } + else T[Colonne] = 1; + } + while ( il < ilDebLignePivot + NbTermesLignePivot ) { + T[LIndiceColonne[il]] = 1; + il++; + } + + *hashCode = *hashCode + DeltaHashCode; + + SuperLigne->NombreDeTermes = NombreDeTermes; + +} +else { + /* Pas de "fill-in" : on remet Matrice.Marqueur aux bonnes valeurs */ + for ( il = ilDebLignePivot ; il != ilDebLignePivot + NbTermesLignePivot ; il++ ) { + T[LIndiceColonne[il]] = 1; + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_scan_super_ligne_cas_symetrique.c b/src/ext/Sirius_Solver/simplexe/lu/lu_scan_super_ligne_cas_symetrique.c new file mode 100644 index 0000000000..2b8e0c913c --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_scan_super_ligne_cas_symetrique.c @@ -0,0 +1,147 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU de la base. Modification des lignes + suite a l'elimination de la ligne pivot dans le cas ou + la ligne scannee est une SuperLigne. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------------------------------------------*/ +/* Les termes de la ligne pivot sont compares a ceux de la ligne scannee et les nouvelle valeurs + des termes de la ligne scannee sont calculees */ + +void LU_ScanSuperLigneCasSymetrique( MATRICE * Matrice, + SUPER_LIGNE_DE_LA_MATRICE * SuperLigne, + int ilDebLignePivot, + int NbNonuLignePivot, + double * ValeurDesTermesDeColonnePivot, + unsigned int * hashCode + ) +{ +int il; int f; int i; int NbTermesLignePivot; int CapaciteMinDemandee; int Colonne; double X; +int ic; int * PoidsDesColonnes; unsigned int DeltaHashCode; +double * W; char * T; double * ElmColonneDeSuperLigne; int * IndiceColonne; int CapaciteDesColonnes; +int NombreDeLignesDeLaSuperLigne; int NombreDeTermes; int * LIndiceColonne; + +W = Matrice->W; +T = Matrice->Marqueur; + +LIndiceColonne = Matrice->LIndiceColonne; + +ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; +IndiceColonne = SuperLigne->IndiceColonne; +CapaciteDesColonnes = SuperLigne->CapaciteDesColonnes; +NombreDeLignesDeLaSuperLigne = SuperLigne->NombreDeLignesDeLaSuperLigne; +NombreDeTermes = SuperLigne->NombreDeTermes; + +/* f sert a mesurer le "fill-in" */ +f = NbNonuLignePivot; /* Nombre de termes de la ligne pivot moins le terme pivot */ + +for ( il = 0 ; il < NombreDeTermes ; il++ ) { + Colonne = IndiceColonne[il]; + /* Si Colonne est egal a ColonnePivot alors on a Matrice.Marqueur[Colonne] = 0 */ + if ( T[Colonne] == 1 ) { + T[Colonne] = 0; + /* Calcul du terme modifie: on balaye la colonne de la SuperLigne */ + ic = CapaciteDesColonnes * il; + X = W[Colonne]; + for ( i = 0 ; i < NombreDeLignesDeLaSuperLigne ; i++ , ic++ ) { + ElmColonneDeSuperLigne[ic]-= X * ValeurDesTermesDeColonnePivot[i]; + } + /* Comme il y a deja un terme dans la ligne scannee, il n'y a pas de "fill-in" a cet endroit */ + f--; + if ( f == 0 ) goto ControleFillIn; + } +} + +/* Controle du fill in */ +ControleFillIn: + +NbTermesLignePivot = NbNonuLignePivot + 1; + +if ( f > 0 ) { + + DeltaHashCode = 0; + + Matrice->CompteurExclusionMarkowitz+= f; + Matrice->NombreDeTermes+= f * NombreDeLignesDeLaSuperLigne; + Matrice->NbFillIn+= f * NombreDeLignesDeLaSuperLigne; + + /* Il y a un "fill-in" => on scanne la ligne pivot pour pouvoir calculer et + stocker les termes crees . Les termes crees sont chaines en fin de ligne */ + if ( NombreDeTermes + f > SuperLigne->Capacite ) { + CapaciteMinDemandee = NombreDeTermes + f; + LU_AugmenterCapaciteDeSuperLigne( Matrice , SuperLigne , CapaciteMinDemandee ); + ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; + IndiceColonne = SuperLigne->IndiceColonne; + } + + PoidsDesColonnes = Matrice->PoidsDesColonnes; + + /* On commence a 1 car terme diagonal range en premier */ + for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + Colonne = LIndiceColonne[il]; + if ( T[Colonne] == 1 ) { + /* "Marqueur" est encore egal a 1 => il n'y avait pas de terme a cet IndiceColonne + dans la SuperLigne scannee: on a trouve un "fill-in" */ + X = -W[Colonne]; + ic = CapaciteDesColonnes * NombreDeTermes; + for ( i = 0 ; i < NombreDeLignesDeLaSuperLigne ; i++ , ic++ ) { + ElmColonneDeSuperLigne[ic] = X * ValeurDesTermesDeColonnePivot[i]; + } + IndiceColonne[NombreDeTermes] = Colonne; + NombreDeTermes++; + + DeltaHashCode+= PoidsDesColonnes[Colonne]; + + f--; + if ( f <= 0 ) { il++; break;} + } + else T[Colonne] = 1; + } + while ( il < ilDebLignePivot + NbTermesLignePivot ) { + T[LIndiceColonne[il]] = 1; + il++; + } + + *hashCode = *hashCode + DeltaHashCode; + + SuperLigne->NombreDeTermes = NombreDeTermes; + +} +else { + /* Pas de "fill-in" : on remet Matrice.Marqueur aux bonnes valeurs */ + /* Terme diagonal range en premier */ + for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + NbTermesLignePivot ; il++ ) { + T[LIndiceColonne[il]] = 1; + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_selection_pivot.c b/src/ext/Sirius_Solver/simplexe/lu/lu_selection_pivot.c new file mode 100644 index 0000000000..4477b67a3f --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_selection_pivot.c @@ -0,0 +1,286 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU de la base. + Choix du pivot. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------------------------------------------*/ +/* Selection du pivot en utilisant le nombre de Markowitz */ + +void LU_SelectionDuPivot( MATRICE * Matrice, + int * LignePivotChoisie, + int * ColonnePivotChoisie + ) +{ +int Ligne ; int Colonne; int k ; double Mu ; double MuTest ; int NuScan; +double SeuilK ; double X ; int il; int IndiceLigne ; int kDeb; int iChoix; +char UtiliserLesSuperLignes; int * CNbTermMatriceActive; +int Rang; int MaxScan; int Kp; int NbTopt; int NbT; +int * PremLigne; int * SuivLigne; int * PremColonne; int * SuivColonne; + +char * LigneRejeteeTemporairementPourPivotage; char * ColonneRejeteeTemporairementPourPivotage; +double ValeurDuPivotMinExtreme; char ContexteDeLaFactorisation; char ExclureLesEchecsMarkowitz; + +int * Ldeb; int * LNbTerm; int * LIndiceColonne; double * Elm; +int * Cdeb; int * CNbTerm; int * CIndiceLigne; + +UtiliserLesSuperLignes = Matrice->UtiliserLesSuperLignes; +ValeurDuPivotMinExtreme = Matrice->ValeurDuPivotMinExtreme; +ContexteDeLaFactorisation = Matrice->ContexteDeLaFactorisation; +ExclureLesEchecsMarkowitz = Matrice->ExclureLesEchecsMarkowitz; + +Rang = Matrice->Rang; +PremLigne = Matrice->PremLigne; +SuivLigne = Matrice->SuivLigne; +PremColonne = Matrice->PremColonne; +SuivColonne = Matrice->SuivColonne; + +LigneRejeteeTemporairementPourPivotage = Matrice->LigneRejeteeTemporairementPourPivotage; +ColonneRejeteeTemporairementPourPivotage = Matrice->ColonneRejeteeTemporairementPourPivotage; + +*LignePivotChoisie = -1; +*ColonnePivotChoisie = -1; + +MaxScan = Matrice->MaxScan; +Kp = Matrice->Kp; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +Cdeb = Matrice->Cdeb; +CNbTerm = Matrice->CNbTerm; +CIndiceLigne = Matrice->CIndiceLigne; +CNbTermMatriceActive = Matrice->CNbTermMatriceActive; + +/* Balayage des lignes qui on 1 terme */ +Ligne = PremLigne[1]; +while ( Ligne >= 0 ) { + if ( LigneRejeteeTemporairementPourPivotage[Ligne] == NON_LU ) { + /* Recherche de la valeur du terme pour controler si pivot nul */ + /* De toutes facons si la ligne a un seul terme, il ne sera jamais modifie */ + if ( UtiliserLesSuperLignes == OUI_LU ) { + if ( Matrice->SuperLigneDeLaLigne[Ligne] != NULL ) { + /* Eviter de faire ca c'est a dire une recopie juste pour avoir la valeur */ + LU_RecopierUneLigneDeSuperLigneDansLigne( Matrice, Matrice->SuperLigneDeLaLigne[Ligne], Ligne ); + X = fabs( Elm[Ldeb[Ligne]] ); /* Car 1 seul terme dans la ligne */ + iChoix = Matrice->SuperLigneDeLaLigne[Ligne]->IndiceColonne[0]; + } + else { + X = fabs( Elm[Ldeb[Ligne]] ); + iChoix = LIndiceColonne[Ldeb[Ligne]]; + } + } + else { + X = fabs( Elm[Ldeb[Ligne]] ); + iChoix = LIndiceColonne[Ldeb[Ligne]]; + } + if ( X >= ValeurDuPivotMinExtreme ) { + /* Pivot acceptable */ + *LignePivotChoisie = Ligne; + *ColonnePivotChoisie = iChoix; + goto FinSelectionPivot; + } + else if ( ExclureLesEchecsMarkowitz == OUI_LU && X < ValeurDuPivotMinExtreme ) { + LigneRejeteeTemporairementPourPivotage[Ligne] = OUI_LU; + LU_DeClasserUneLigne( Matrice , Ligne , 1 ); + } + } + Ligne = SuivLigne[Ligne]; +} + +/* Balayage des colonnes qui on 1 terme */ +Colonne = PremColonne[1]; +while ( Colonne >= 0 ) { + /* Compacter la colonne */ + if ( CNbTerm[Colonne] != 1 ) { + LU_SupprimerTermesInutilesDansColonne( Matrice, Colonne, Cdeb[Colonne] ); + } + /* Recherche de la valeur du terme pour controler si pivot acceptable */ + IndiceLigne = CIndiceLigne[Cdeb[Colonne]]; + if ( LigneRejeteeTemporairementPourPivotage[IndiceLigne] == NON_LU ) { + /* Recherche de l'index auquel on trouve la valeur du terme pivot potentiel */ + + if ( UtiliserLesSuperLignes == OUI_LU ) { + if ( Matrice->SuperLigneDeLaLigne[IndiceLigne] != NULL ) { + for ( il = 0 ; Matrice->SuperLigneDeLaLigne[IndiceLigne]->IndiceColonne[il] != Colonne ; il++ ); + /* Dans ce cas la SuperLigne ne peut contenir qu'une seule ligne */ + il = Matrice->SuperLigneDeLaLigne[IndiceLigne]->CapaciteDesColonnes * il; + X = fabs( Matrice->SuperLigneDeLaLigne[IndiceLigne]->ElmColonneDeSuperLigne[il] ); + } + else { + for ( il = Ldeb[IndiceLigne] ; LIndiceColonne[il] != Colonne ; il++ ); + X = fabs( Elm[il] ); + } + } + else { + for ( il = Ldeb[IndiceLigne] ; LIndiceColonne[il] != Colonne ; il++ ); + X = fabs( Elm[il] ); + } + + /* De toutes facons si la colonne a une seul terme il ne sera jamais modifie donc on le prend */ + if ( X >= ValeurDuPivotMinExtreme) { + /* Pivot acceptable */ + *ColonnePivotChoisie = Colonne; + *LignePivotChoisie = IndiceLigne; + goto FinSelectionPivot; + } + else if ( ExclureLesEchecsMarkowitz == OUI_LU && X < ValeurDuPivotMinExtreme ) { + ColonneRejeteeTemporairementPourPivotage[Colonne] = OUI_LU; + LU_DeClasserUneColonne( Matrice , Colonne , 1 ); + } + } + Colonne = SuivColonne[Colonne]; +} + +/* Suite */ + +kDeb = 2; +Mu = Matrice->RangAuCarrePlus1; +MuTest = Mu; +NuScan = 0; + +if ( ContexteDeLaFactorisation == LU_SIMPLEXE ) goto ChoixPourSimplexe; + +/* Strategie colonne d'abord */ +for ( k = kDeb ; k <= Rang - Kp ; k++ ) { + /* Balayage des colonnes qui on k termes */ + Colonne = PremColonne[k]; + while ( Colonne >= 0 ) { + if ( ColonneRejeteeTemporairementPourPivotage[Colonne] == NON_LU ) { + LU_InitMinMarkowitzDeColonne( Matrice , Colonne , &Ligne , &X ); + if ( X < Mu ) { + Mu = X; + *LignePivotChoisie = Ligne; + *ColonnePivotChoisie = Colonne; + } + if ( X < MuTest ) NuScan++; + if ( NuScan == MaxScan ) goto FinSelectionPivot; + } + Colonne = SuivColonne[Colonne]; + } /* */ + /* Balayage des lignes qui on k termes */ + Ligne = PremLigne[k]; + while ( Ligne >= 0 ) { + if ( LigneRejeteeTemporairementPourPivotage[Ligne] == NON_LU ) { + LU_InitMinMarkowitzDeLigne( Matrice , Ligne , &Colonne , &X ); + if ( X < Mu ) { + Mu = X; + *LignePivotChoisie = Ligne; + *ColonnePivotChoisie = Colonne; + } + if ( X < MuTest ) NuScan++; + if ( NuScan == MaxScan ) goto FinSelectionPivot; + } + Ligne = SuivLigne[Ligne]; + } + /* */ +} + +goto FinSelectionPivot; + +ChoixPourSimplexe: + +/* Strategie ligne d'abord */ +NbTopt = Rang << 1; + +for ( k = kDeb ; k <= Rang ; k++ ) { + SeuilK = ( k - 1 ) * ( k - 1 ); + /* */ + /* Balayage des lignes qui on k termes */ + Ligne = PremLigne[k]; + while ( Ligne >= 0 ) { + if ( LigneRejeteeTemporairementPourPivotage[Ligne] == NON_LU ) { + LU_InitMinMarkowitzDeLigne( Matrice , Ligne , &Colonne , &X ); + if ( X < Mu ) { + Mu = X; + NbTopt = CNbTermMatriceActive[Colonne] - 1; + *LignePivotChoisie = Ligne; + *ColonnePivotChoisie = Colonne; + if ( Mu <= SeuilK ) goto FinSelectionPivot; + } + else if ( X == Mu ) { + NbT = CNbTermMatriceActive[Colonne] - 1; + if ( NbT < NbTopt ) { + Mu = X; + NbTopt = NbT; + *LignePivotChoisie = Ligne; + *ColonnePivotChoisie = Colonne; + if ( Mu <= SeuilK ) goto FinSelectionPivot; + } + } + if ( X < MuTest ) NuScan++; + if ( NuScan == MaxScan ) goto FinSelectionPivot; + } + Ligne = SuivLigne[Ligne]; + } + /* Balayage des colonnes qui on k termes */ + Colonne = PremColonne[k]; + while ( Colonne >= 0 ) { + if ( ColonneRejeteeTemporairementPourPivotage[Colonne] == NON_LU ) { + LU_InitMinMarkowitzDeColonne( Matrice , Colonne , &Ligne , &X ); + if ( X < Mu ) { + Mu = X; + NbTopt = k - 1; + *ColonnePivotChoisie = Colonne; + *LignePivotChoisie = Ligne; + if ( Mu <= SeuilK ) goto FinSelectionPivot; + } + else if ( X == Mu ) { + if ( k - 1 < NbTopt ) { + Mu = X; + NbTopt = k - 1; + *ColonnePivotChoisie = Colonne; + *LignePivotChoisie = Ligne; + if ( Mu <= SeuilK ) goto FinSelectionPivot; + } + } + if ( X < MuTest ) NuScan++; + if ( NuScan == MaxScan ) goto FinSelectionPivot; + } + Colonne = SuivColonne[Colonne]; + } + /* */ +} + +FinSelectionPivot: +if ( *ColonnePivotChoisie >= 0 ) { + if ( CNbTerm[*ColonnePivotChoisie] != CNbTermMatriceActive[*ColonnePivotChoisie] ) { + LU_SupprimerTermesInutilesDansColonne( Matrice, *ColonnePivotChoisie, Cdeb[*ColonnePivotChoisie] ); + } +} + +return; +} + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_selection_pivot_diagonal.c b/src/ext/Sirius_Solver/simplexe/lu/lu_selection_pivot_diagonal.c new file mode 100644 index 0000000000..0987a666bf --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_selection_pivot_diagonal.c @@ -0,0 +1,359 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Choix du pivot sur la diagonale. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------------------------------------------*/ +/* Plus grand terme d'une ligne */ + +double LU_TrouverPlusGrandTermeDeLigne( MATRICE * Matrice , int LignePivot ) +{ +int il; int ilDebLignePivot; double X; double Xmx; double * Elm; + +SUPER_LIGNE_DE_LA_MATRICE * SuperLigneDeLaLignePivot; int * NumerosDesLignesDeLaSuperLigne; + +int NombreDeLignesDeLaSuperLigne; int NombreDeTermes; int ic; +double * ElmColonneDeSuperLigne ; int CapaciteDesColonnes; + +if ( Matrice->UtiliserLesSuperLignes == OUI_LU ) { + SuperLigneDeLaLignePivot = Matrice->SuperLigneDeLaLigne[LignePivot]; + if ( SuperLigneDeLaLignePivot != NULL ) { + /* Recopie de la ligne pivot vers un tableau compact */ + NombreDeLignesDeLaSuperLigne = SuperLigneDeLaLignePivot->NombreDeLignesDeLaSuperLigne; + NumerosDesLignesDeLaSuperLigne = SuperLigneDeLaLignePivot->NumerosDesLignesDeLaSuperLigne; + for ( ic = 0 ; ic < NombreDeLignesDeLaSuperLigne ; ic++ ) { + if ( NumerosDesLignesDeLaSuperLigne[ic] == LignePivot ) { + /* ic est l'index qui correspond a la ligne */ + break; + } + } + NombreDeTermes = SuperLigneDeLaLignePivot->NombreDeTermes; + CapaciteDesColonnes = SuperLigneDeLaLignePivot->CapaciteDesColonnes; + ElmColonneDeSuperLigne = SuperLigneDeLaLignePivot->ElmColonneDeSuperLigne; + + Xmx = -1.; + for ( il = 0 ; il < NombreDeTermes ; il++ ) { + X = fabs( ElmColonneDeSuperLigne[ic] ); + if ( X > Xmx ) Xmx = X; + ic+= CapaciteDesColonnes; + } + + Matrice->AbsDuPlusGrandTermeDeLaLigne[LignePivot] = Xmx; + + return( Xmx ); + + } +} + +Elm = Matrice->Elm; +ilDebLignePivot = Matrice->Ldeb[LignePivot]; +Xmx = fabs( Elm[ilDebLignePivot] ); +for ( il = ilDebLignePivot + 1 ; il < ilDebLignePivot + Matrice->LNbTerm[LignePivot]; il++ ) { + X = fabs( Elm[il] ); + if ( X > Xmx ) Xmx = X; +} + +Matrice->AbsDuPlusGrandTermeDeLaLigne[LignePivot] = Xmx; + +return( Xmx ); +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Selection du pivot sur la diagonale */ + +void LU_SelectionDuPivotDiagonal( MATRICE * Matrice, + int * LignePivotChoisie, + int * ColonnePivotChoisie + ) +{ +int k; int Ligne ; int Colonne; int il ; +double MinMarkowitz; double Mu ; double MuTest ; int NuScan ; double X ; double Xsv ; +char MinMarkowitzSimplifie ; int * PremLigne; int * SuivLigne; double Pgt; double CoeffPgt; +int MaxScan; double PivotMin; int kFin; +int LignePivot; int ColonnePivot; char TestDeStabilite ; +double * AbsValeurDuTermeDiagonal ; double * AbsDuPlusGrandTermeDeLaLigne ; +int * Ldeb; double * Elm; int * CNbTerm; int * CNbTermMatriceActive; + +int NombreDeLignesDeLaSuperLigne; +SUPER_LIGNE_DE_LA_MATRICE * SuperLigneDeLaLigne ; int * NumerosDesLignesDeLaSuperLigne ; +double * ElmColonneDeSuperLigne ; int ic ; int CapaciteDesColonnes; char RegulOk; + +TestDeStabilite = 1; + +RechercheDuPivot: + +LignePivot = -1; +ColonnePivot = -1; + +Mu = Matrice->RangAuCarrePlus1; +MuTest = Mu; +NuScan = 0; +MaxScan = Matrice->MaxScan; +PivotMin = Matrice->PivotMin; + +CoeffPgt = PivotMin; + +if ( Matrice->LaMatriceEstSymetrique == OUI_LU || Matrice->LaMatriceEstSymetriqueEnStructure == OUI_LU ) { + MinMarkowitzSimplifie = OUI_LU; +} +else { + MinMarkowitzSimplifie = NON_LU; +} + +PremLigne = Matrice->PremLigne; +SuivLigne = Matrice->SuivLigne; + +AbsValeurDuTermeDiagonal = Matrice->AbsValeurDuTermeDiagonal; +AbsDuPlusGrandTermeDeLaLigne = Matrice->AbsDuPlusGrandTermeDeLaLigne; + +CNbTerm = Matrice->CNbTerm; +CNbTermMatriceActive = Matrice->CNbTermMatriceActive; + +kFin = Matrice->Rang - Matrice->Kp; +Xsv = -1.; +for ( k = 1 ; k <= kFin ; k++ ) { + /* On a trouve un pivot ? */ + if ( Mu < MuTest ) goto FinSelectionDuPivotDiagonal; + /* Balayage des lignes qui on k termes */ + Ligne = PremLigne[k]; + while ( Ligne >= 0 ) { + MinMarkowitz = MuTest; + X = AbsValeurDuTermeDiagonal[Ligne]; + if ( X > PivotMin ) { /* Controle supplementaire car au debut on classe aussi les pivots nuls */ + Colonne = Ligne; + if ( MinMarkowitzSimplifie == NON_LU ) { + MinMarkowitz = ( k - 1 ) * ( CNbTermMatriceActive[Colonne] - 1 ); + } + else { + MinMarkowitz = k; + } + if ( TestDeStabilite == 0 ) { + LignePivot = Ligne; + ColonnePivot = Colonne; + break; + } + goto Compare; + } + goto NextLigne; + + Compare: + /* Terme diagonal eventuellement trouve */ + if ( MinMarkowitz == Mu ) { + if ( X > Xsv ) { + /* Methode en test : on fait un controle grossier de stabilite. Resultat des tests: ca marche bien */ + if ( X < 1. ) { + Pgt = AbsDuPlusGrandTermeDeLaLigne[Ligne]; + if ( Pgt < 0. ) { + Pgt = LU_TrouverPlusGrandTermeDeLigne( Matrice , Ligne ); + /*AbsDuPlusGrandTermeDeLaLigne[Ligne] = Pgt;*/ + } + if ( X < CoeffPgt * Pgt ) { + goto NextLigne; + } + } + /* Fin methode en test */ + Xsv = X; + LignePivot = Ligne; + ColonnePivot = Colonne; + } + } + else if ( MinMarkowitz < Mu ) { + /* Methode en test : on fait un controle grossier de stabilite. Resultat des tests: ca marche bien */ + if ( X < 1. ) { + Pgt = AbsDuPlusGrandTermeDeLaLigne[Ligne]; + if ( Pgt < 0. ) { + Pgt = LU_TrouverPlusGrandTermeDeLigne( Matrice , Ligne ); + /*AbsDuPlusGrandTermeDeLaLigne[Ligne] = Pgt;*/ + } + if ( X < CoeffPgt * Pgt ) { + goto NextLigne; + } + } + /* Fin methode en test */ + Mu = MinMarkowitz; + Xsv = X; + LignePivot = Ligne; + ColonnePivot = Colonne; + /* Dans le cas hors point interieur on peut se contenter du premier pivot correct rencontre */ + /* donc chercher a remettre le test ci-dessous en service */ + /* goto FinSelectionDuPivotDiagonal; */ + } + + if ( MinMarkowitz < MuTest ) NuScan++; + + if ( NuScan == MaxScan ) goto FinSelectionDuPivotDiagonal; + + NextLigne: + Ligne = SuivLigne[Ligne]; + } + + /* On change de k: si on a trouve un pivot on arrete */ + if ( NuScan > 0 ) goto FinSelectionDuPivotDiagonal; + +} + +FinSelectionDuPivotDiagonal: + +*LignePivotChoisie = LignePivot; +*ColonnePivotChoisie = ColonnePivot; + +if ( LignePivot >= 0 && ColonnePivot >= 0 ) { + if ( MinMarkowitzSimplifie == NON_LU ) { + if ( CNbTerm[ColonnePivot] != CNbTermMatriceActive[ColonnePivot] ) { + LU_SupprimerTermesInutilesDansColonne( Matrice, ColonnePivot, Matrice->Cdeb[ColonnePivot] ); + } + } + return; +} + +if ( Matrice->OnPeutRegulariser == NON_LU ) return; +if ( Matrice->ValeurDeRegularisation <= Matrice->PivotMin ) return; + +/* On peut regulariser, donc on est dans le point interieur. Avant de se lancer dans la recgularisation, on + regarde s'il est possible de trouver un pivot sans faire le test de staibilite. En effet, il y a le risque + que l'on n'ai pas choisi de pivot a cause de la condition de stabilite, tout en ayant des pivot de valeur + plus grande que le terme de regularisation lui-męme. */ +if ( TestDeStabilite == 1 ) { + TestDeStabilite = 0; + goto RechercheDuPivot; +} + +/* Si on est tombe sur un pivot nul et qu'on est dans un contexte de point interieur, on regularise */ + +Ldeb = Matrice->Ldeb; +Elm = Matrice->Elm; + +RegulOk = NON_LU; +for ( k = 1 ; k <= kFin ; k++ ) { + /* Balayage des lignes qui on k termes */ + Ligne = PremLigne[k]; + while ( Ligne >= 0 ) { + AbsValeurDuTermeDiagonal[Ligne] = Matrice->ValeurDeRegularisation; + Matrice->TermeDeRegularisation[Ligne]+= Matrice->ValeurDeRegularisation; + RegulOk = OUI_LU; + Matrice->OnARegularise = OUI_LU; + *LignePivotChoisie = Ligne; + *ColonnePivotChoisie = Ligne; + /* On modifie aussi la valeur du terme diagonal pour etre en accord */ + if ( Matrice->UtiliserLesSuperLignes == OUI_LU ) { + SuperLigneDeLaLigne = Matrice->SuperLigneDeLaLigne[Ligne]; + if ( SuperLigneDeLaLigne != NULL ) { + NombreDeLignesDeLaSuperLigne = SuperLigneDeLaLigne->NombreDeLignesDeLaSuperLigne; + NumerosDesLignesDeLaSuperLigne = SuperLigneDeLaLigne->NumerosDesLignesDeLaSuperLigne; + CapaciteDesColonnes = SuperLigneDeLaLigne->CapaciteDesColonnes; + ElmColonneDeSuperLigne = SuperLigneDeLaLigne->ElmColonneDeSuperLigne; + for ( ic = 0 ; ic < NombreDeLignesDeLaSuperLigne ; ic++ ) { + if ( NumerosDesLignesDeLaSuperLigne[ic] == Ligne ) { + /* ic est l'index qui correspond a la ligne */ + il = SuperLigneDeLaLigne->IndexDuTermeDiagonal[ic]; + ElmColonneDeSuperLigne[ (il * CapaciteDesColonnes) + ic ] = Matrice->ValeurDeRegularisation; + break; + } + } + } + else { + Elm[Ldeb[Ligne]] = Matrice->ValeurDeRegularisation; + } + } + else { + Elm[Ldeb[Ligne]] = Matrice->ValeurDeRegularisation; + } + if ( RegulOk == OUI_LU ) break; + Ligne = SuivLigne[Ligne]; + } + if ( RegulOk == OUI_LU ) break; +} + +return; + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_selection_pivot_matrice_pleine.c b/src/ext/Sirius_Solver/simplexe/lu/lu_selection_pivot_matrice_pleine.c new file mode 100644 index 0000000000..c96b521c3b --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_selection_pivot_matrice_pleine.c @@ -0,0 +1,177 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Decomposition LU de la base. Methode de pivot total. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------*/ +/* Selection du pivot */ +/* Comme on est en matrice pleine on prend le plus grand terme */ +/* de la sous matrice active */ + +void LU_SelectionDuPivotMatricePleine( MATRICE * Matrice, + int * LignePivotChoisie, + int * ColonnePivotChoisie + ) +{ +/* Remarque, ça marche aussi dans le cas du pivotage diagonal car + dans ce cas le plus grand terme est recherche sur la diagonale */ +if ( Matrice->ValeurDuPlusGrandTerme > Matrice->PivotMin ) { + *LignePivotChoisie = Matrice->LigneDuPlusGrandTerme; + *ColonnePivotChoisie = Matrice->ColonneDuPlusGrandTerme; + + +} +else { + *LignePivotChoisie = -1; + *ColonnePivotChoisie = -1; +} +if ( *ColonnePivotChoisie >= 0 ) { + if ( Matrice->CNbTerm[*ColonnePivotChoisie] != Matrice->CNbTermMatriceActive[*ColonnePivotChoisie] ) { + LU_SupprimerTermesInutilesDansColonne( Matrice, *ColonnePivotChoisie, Matrice->Cdeb[*ColonnePivotChoisie] ); + } +} +return; +} + + +/*--------------------------------------------------------------*/ +/* Recherche du plus grand terme de la matrice active juste */ +/* avant le passage en mode matrice pleine */ + +void LU_RechercherLePlusGrandTermeDeLaMatriceActive( MATRICE * Matrice ) +{ +int Kp; int Ligne; int il; double X; int NombreDeTermes; int ilDeb; +int * Ldeb; int * LNbTerm; int * LIndiceColonne; double * Elm; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +Matrice->ValeurDuPlusGrandTerme = -1.; +if ( Matrice->FaireDuPivotageDiagonal == NON_LU ) { + for ( Kp = Matrice->Kp + 1 ; Kp < Matrice->Rang ; Kp++ ) { + Ligne = Matrice->OrdreLigne[Kp]; + ilDeb = Ldeb[Ligne]; + NombreDeTermes = LNbTerm[Ligne]; + for ( il = ilDeb ; il < ilDeb + NombreDeTermes ; il++ ) { + X = fabs( Elm[il] ); + if ( X > Matrice->ValeurDuPlusGrandTerme ) { + Matrice->ValeurDuPlusGrandTerme = X; + Matrice->LigneDuPlusGrandTerme = Ligne; + Matrice->ColonneDuPlusGrandTerme = LIndiceColonne[il]; + } + } + } +} +else { + /* Pivotage diagonal */ + for ( Kp = Matrice->Kp + 1 ; Kp < Matrice->Rang ; Kp++ ) { + Ligne = Matrice->OrdreLigne[Kp]; + ilDeb = Ldeb[Ligne]; + NombreDeTermes = LNbTerm[Ligne]; + for ( il = ilDeb ; il < ilDeb + NombreDeTermes ; il++ ) { + /* Recherche du terme diagonal */ + if ( LIndiceColonne[il] == Ligne ) { + X = fabs( Elm[il] ); + if ( X > Matrice->ValeurDuPlusGrandTerme ) { + Matrice->ValeurDuPlusGrandTerme = X; + Matrice->LigneDuPlusGrandTerme = Ligne; + Matrice->ColonneDuPlusGrandTerme = Ligne; + } + break; + } + } + } +} + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_calculs_hashcode.c b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_calculs_hashcode.c new file mode 100644 index 0000000000..81322f6caf --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_calculs_hashcode.c @@ -0,0 +1,293 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calculs de classements hascode pour les super lignes + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------------------------------------------*/ +/* Premier appel, on calcule les hashcode des lignes non encore eliminees. + Il n'y a encore aucune super ligne */ + +void LU_CreerLesHashCode( MATRICE * Matrice ) +{ +int Ligne; unsigned int hashCode; unsigned int * HashCodeLigne; int Colonne; +char * TypeDeClassementHashCodeAFaire; int * PoidsDesColonnes; int * OrdreLigne; int Kp; int il; +int ilMax; int * Ldeb; int * LNbTerm; int * LIndiceColonne; + +OrdreLigne = Matrice->OrdreLigne; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; + +PoidsDesColonnes = Matrice->PoidsDesColonnes; + +HashCodeLigne = Matrice->HashCodeLigne; +TypeDeClassementHashCodeAFaire = Matrice->TypeDeClassementHashCodeAFaire; + +for ( Kp = Matrice->Kp ; Kp < Matrice->Rang ; Kp++ ) { + Ligne = OrdreLigne[Kp]; + il = Ldeb[Ligne]; + ilMax = il + LNbTerm[Ligne]; + hashCode = 0; + while ( il < ilMax ) { + Colonne = LIndiceColonne[il]; + hashCode += PoidsDesColonnes[Colonne]; + il++; + } + HashCodeLigne[Ligne] = hashCode; + /* Normalement c'est deja le cas */ + TypeDeClassementHashCodeAFaire[Ligne] = ELEMENT_HASCODE_A_CLASSER; +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Au premier passage on classe toutes les lignes qui n'ont pas encore ete eliminees */ + +void LU_ClasserLesElementsEnFonctionDuHashCode( MATRICE * Matrice ) +{ +int HashModuloSize; int k ; int i; int Element ; +unsigned int * HashCodeLigne; unsigned int * HashCodeSuperLigne; int hashModulo; int hashModuloSuiv; + +int * HashNbModuloIdentiques; int * HashModuloPrec; int * HashModuloPrem; +int * HashModuloSuiv ; char * TypeDeClassementHashCodeAFaire; + +HashModuloSize = Matrice->HashModuloSize; + +HashCodeLigne = Matrice->HashCodeLigne; +HashCodeSuperLigne = Matrice->HashCodeSuperLigne; + +HashNbModuloIdentiques = Matrice->HashNbModuloIdentiques; +HashModuloPrec = Matrice->HashModuloPrec; +HashModuloPrem = Matrice->HashModuloPrem; +HashModuloSuiv = Matrice->HashModuloSuiv; +TypeDeClassementHashCodeAFaire = Matrice->TypeDeClassementHashCodeAFaire; + +for ( k = 0 ; k < HashModuloSize ; k++ ) { + HashModuloPrem [k] = -1; + HashNbModuloIdentiques[k] = 0; +} + +/* Classement des lignes */ +Element = 0; +for ( i = 0 ; i < Matrice->Rang ; i++ ) { + if ( TypeDeClassementHashCodeAFaire[Element] == ELEMENT_HASCODE_A_DECLASSER || + TypeDeClassementHashCodeAFaire[Element] == ELEMENT_HASCODE_A_NE_PAS_CLASSER ) { + /* Concerne les lignes deja eliminees */ + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_A_NE_PAS_CLASSER; + Element++; + continue; + } + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_CLASSE; + + /* Trouver autre chose comme test */ + hashModulo = HashCodeLigne[i] % HashModuloSize; + + hashModuloSuiv = HashModuloPrem[hashModulo]; + HashNbModuloIdentiques[hashModulo]++; + + HashModuloPrem[hashModulo] = Element; + + HashModuloSuiv[Element] = hashModuloSuiv; + + if ( hashModuloSuiv >= 0 ) HashModuloPrec[hashModuloSuiv] = Element; + + Matrice->HashModuloPrec[Element] = -(hashModulo+2); + + Element++; + +} +/* Classement des super lignes */ +Element = Matrice->Rang; +for ( i = 0 ; i < Matrice->NombreDeSuperLignes ; i++ ) { + if ( TypeDeClassementHashCodeAFaire[Element] == ELEMENT_HASCODE_A_DECLASSER ) { + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_A_NE_PAS_CLASSER; + Element++; + continue; + } + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_CLASSE; + + hashModulo = HashCodeSuperLigne[i] % HashModuloSize; + + hashModuloSuiv = HashModuloPrem[hashModulo]; + HashNbModuloIdentiques[hashModulo]++; + + HashModuloPrem[hashModulo] = Element; + + HashModuloSuiv[Element] = hashModuloSuiv; + + if ( hashModuloSuiv >= 0 ) HashModuloPrec[hashModuloSuiv] = Element; + + Matrice->HashModuloPrec[Element] = -(hashModulo+2); + + Element++; + +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_MajClassementDesElementsEnFonctionDuHashCode( MATRICE * Matrice ) +{ +int i; char AFaire; int Element; char * TypeDeClassementHashCodeAFaire; + +TypeDeClassementHashCodeAFaire = Matrice->TypeDeClassementHashCodeAFaire; + +/* Declassement / Classement des lignes */ +Element = 0; +for ( i = 0 ; i < Matrice->Rang ; i++ ) { + AFaire = TypeDeClassementHashCodeAFaire[Element]; + if ( AFaire == ELEMENT_HASCODE_A_NE_PAS_CLASSER ) { + Element++; + continue; + } + if ( AFaire == ELEMENT_HASCODE_A_DECLASSER ) { + LU_DeClasserEnFonctionDuHashCode( Matrice , Element ); + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_A_NE_PAS_CLASSER; + Element++; + continue; + } + if ( AFaire == ELEMENT_HASCODE_A_CLASSER ) { + LU_ClasserEnFonctionDuHashCode( Matrice , Element ); + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_CLASSE; + Element++; + continue; + } + if ( AFaire == ELEMENT_HASCODE_A_RECLASSER ) { + LU_DeClasserEnFonctionDuHashCode( Matrice , Element ); + LU_ClasserEnFonctionDuHashCode( Matrice , Element ); + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_CLASSE; + Element++; + continue; + } + Element++; +} +/* Classement des super lignes */ +Element = Matrice->Rang; +for ( i = 0 ; i < Matrice->NombreDeSuperLignes ; i++ ) { + AFaire = TypeDeClassementHashCodeAFaire[Element]; + if ( AFaire == ELEMENT_HASCODE_A_NE_PAS_CLASSER ) { + Element++; + continue; + } + if ( AFaire == ELEMENT_HASCODE_A_DECLASSER ) { + LU_DeClasserEnFonctionDuHashCode( Matrice , Element ); + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_A_NE_PAS_CLASSER; + Element++; + continue; + } + if ( AFaire == ELEMENT_HASCODE_A_CLASSER ) { + LU_ClasserEnFonctionDuHashCode( Matrice , Element ); + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_CLASSE; + Element++; + continue; + } + if ( AFaire == ELEMENT_HASCODE_A_RECLASSER ) { + LU_DeClasserEnFonctionDuHashCode( Matrice , Element ); + LU_ClasserEnFonctionDuHashCode( Matrice , Element ); + TypeDeClassementHashCodeAFaire[Element] = ELEMENT_HASCODE_CLASSE; + Element++; + continue; + } + Element++; +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_ClasserEnFonctionDuHashCode( MATRICE * Matrice , int Element ) +{ +int HashModulo; int HashModuloSuiv; + +if ( Element < Matrice->Rang ) { + HashModulo = Matrice->HashCodeLigne[Element] % Matrice->HashModuloSize; +} +else { + HashModulo = Matrice->HashCodeSuperLigne[Element-Matrice->Rang] % Matrice->HashModuloSize; +} + +HashModuloSuiv = Matrice->HashModuloPrem[HashModulo]; +Matrice->HashNbModuloIdentiques[HashModulo]++; + +Matrice->HashModuloPrem[HashModulo] = Element; +Matrice->HashModuloSuiv[Element] = HashModuloSuiv; + +if ( HashModuloSuiv >= 0 ) Matrice->HashModuloPrec[HashModuloSuiv] = Element; +Matrice->HashModuloPrec[Element] = -(HashModulo+2); + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_DeClasserEnFonctionDuHashCode( MATRICE * Matrice , int Element ) +{ +int HashModuloPrec; int HashModulo; int HashModuloSuiv; + +HashModuloPrec = Matrice->HashModuloPrec[Element]; + +if ( HashModuloPrec < 0 ) { + HashModulo = -HashModuloPrec; + HashModulo-=2; + /* On veut supprimer le premier terme */ + Matrice->HashNbModuloIdentiques[HashModulo]--; + Matrice->HashModuloPrem[HashModulo] = Matrice->HashModuloSuiv[Element]; + Matrice->HashModuloPrec[Element] = -1; + if ( Matrice->HashModuloSuiv[Element] >= 0 ) { + Matrice->HashModuloPrec[Matrice->HashModuloSuiv[Element]] = -(HashModulo+2); + } + goto FinDeclassement; +} + +HashModuloSuiv = Matrice->HashModuloSuiv[Element]; +Matrice->HashModuloSuiv[HashModuloPrec] = HashModuloSuiv; +if ( HashModuloSuiv >= 0 ) Matrice->HashModuloPrec[HashModuloSuiv] = HashModuloPrec; + +/* Ce n'est pas le premier element et on veut retrouver le HashModulo du groupe */ +while ( HashModuloPrec >= 0 ) { + HashModuloPrec = Matrice->HashModuloPrec[HashModuloPrec]; +} + +HashModulo = -HashModuloPrec; +HashModulo-=2; +Matrice->HashNbModuloIdentiques[HashModulo]--; + +Matrice->HashModuloPrec[Element] = -1; + +FinDeclassement: + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_creations_et_fusions.c b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_creations_et_fusions.c new file mode 100644 index 0000000000..302bf53747 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_creations_et_fusions.c @@ -0,0 +1,294 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Creation et fusion des super lignes + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ +/* Creation d'une super ligne ( 1ere creation ) */ + +SUPER_LIGNE_DE_LA_MATRICE * LU_CreerUneSuperLigne( MATRICE * Matrice , int * T , int NombreDeLignes , + int * NumeroDesLignes , int NbTermesLigne ) +{ +SUPER_LIGNE_DE_LA_MATRICE * SuperLigne; int Demande; int i; int Ligne; int ic; int il; int ilMax; + +int CapaciteDesColonnes; int * IndexDuTermeDiagonal; int * NumerosDesLignesDeLaSuperLigne; +SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneDeLaLigne; int * IndiceColonneDansSuperLigne; double * ElmColonneDeSuperLigne; +int * Ldeb; int * LNbTerm; int * LIndiceColonne; double * Elm; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +SuperLigneDeLaLigne = Matrice->SuperLigneDeLaLigne; + +SuperLigne = (SUPER_LIGNE_DE_LA_MATRICE *) malloc( sizeof( SUPER_LIGNE_DE_LA_MATRICE ) ); +if ( SuperLigne == NULL ) { + printf("Factorisation LU, sous-programme LU_CreerUneSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} + +SuperLigne->ScannerLaSuperLigne = NON_LU; + +Demande = NombreDeLignes + INCREMENT_ALLOC_NB_LIGNES_DE_SUPER_LIGNE; +SuperLigne->NumerosDesLignesDeLaSuperLigne = (int *) malloc( Demande * sizeof( int ) ); +if ( SuperLigne->NumerosDesLignesDeLaSuperLigne == NULL ) { + printf("Factorisation LU, sous-programme LU_CreerUneSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} + +/* L'index du terme diagonal n'est utilise que si pivotage diagonal */ +SuperLigne->IndexDuTermeDiagonal = (int *) malloc( Demande * sizeof( int ) ); +if ( SuperLigne->IndexDuTermeDiagonal == NULL ) { + printf("Factorisation LU, sous-programme LU_CreerUneSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); +} +IndexDuTermeDiagonal = SuperLigne->IndexDuTermeDiagonal; + +SuperLigne->CapaciteDesColonnes = Demande; +CapaciteDesColonnes = Demande; + +NumerosDesLignesDeLaSuperLigne = SuperLigne->NumerosDesLignesDeLaSuperLigne; +for ( i = 0 ; i < NombreDeLignes ; i++ ) { + Ligne = NumeroDesLignes[i]; + NumerosDesLignesDeLaSuperLigne[i] = Ligne; + SuperLigneDeLaLigne[Ligne] = SuperLigne; +} + +SuperLigne->NombreDeLignesDeLaSuperLigne = NombreDeLignes; + +/* Modele de la ligne */ +Demande = NbTermesLigne + INCREMENT_ALLOC_NB_COLONNES_DE_SUPER_LIGNE; +SuperLigne->IndiceColonne = (int *) malloc( Demande * sizeof( int ) ); +if ( SuperLigne->IndiceColonne == NULL ) { + printf("Factorisation LU, sous-programme LU_CreerUneSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} +IndiceColonneDansSuperLigne = SuperLigne->IndiceColonne; +SuperLigne->Capacite = Demande; + +Ligne = NumeroDesLignes[0]; + +il = Ldeb[Ligne]; +ilMax = il + LNbTerm[Ligne]; +i = 0; +while ( il < ilMax ) { + IndiceColonneDansSuperLigne[i] = LIndiceColonne[il]; + i++; + il++; +} + + +SuperLigne->NombreDeTermes = NbTermesLigne; +SuperLigne->NumeroDeLaSuperLigne = Matrice->NombreDeSuperLignes; +Matrice->HashCodeSuperLigne[Matrice->NombreDeSuperLignes] = Matrice->HashCodeLigne[Ligne]; +Matrice->SuperLigne [Matrice->NombreDeSuperLignes] = SuperLigne; + +Matrice->NombreDeSuperLignes++; + +Demande = CapaciteDesColonnes * SuperLigne->Capacite; +SuperLigne->ElmColonneDeSuperLigne = (double *) malloc( Demande * sizeof( double ) ); +if ( SuperLigne->ElmColonneDeSuperLigne == NULL ) { + printf("Factorisation LU, sous-programme LU_CreerUneSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} +ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; + +for ( i = 0 ; i < NombreDeLignes ; i++ ) { + Ligne = NumeroDesLignes[i]; + il = Ldeb[Ligne]; + ilMax = il + LNbTerm[Ligne]; + while ( il < ilMax ) { + ic = CapaciteDesColonnes * ( T[LIndiceColonne[il]] - 1 ); + /* Index du terme diagonal */ + if ( LIndiceColonne[il] == Ligne ) IndexDuTermeDiagonal[i] = T[LIndiceColonne[il]] - 1; + ic+= i; + ElmColonneDeSuperLigne[ic] = Elm[il]; + il++; + } +} + +return( SuperLigne ); +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_FusionnerDeuxSuperLignes( MATRICE * Matrice , int * T , + int PremiereSuperLigne, int DeuxiemeSuperLigne ) +{ +int il1; int il2; int ic1; int ic2; int i; int Ligne; int Demande; + +SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneDeLaLigne; +SUPER_LIGNE_DE_LA_MATRICE * SuperLigne1; SUPER_LIGNE_DE_LA_MATRICE * SuperLigne2; + +double * ElmColonneDeSuperLigne_1 ; int * IndexDuTermeDiagonal_1; int NombreDeLignesDeLaSuperLigne_1; +int * NumerosDesLignesDeLaSuperLigne_1; int CapaciteDesColonnes_1 ; + +double * ElmColonneDeSuperLigne_2 ; int * IndexDuTermeDiagonal_2; int NombreDeLignesDeLaSuperLigne_2; +int * NumerosDesLignesDeLaSuperLigne_2; int CapaciteDesColonnes_2 ; int * IndiceColonne_2 ; + +SuperLigneDeLaLigne = Matrice->SuperLigneDeLaLigne; + +SuperLigne1 = Matrice->SuperLigne[PremiereSuperLigne]; +SuperLigne2 = Matrice->SuperLigne[DeuxiemeSuperLigne]; + +Demande = SuperLigne1->NombreDeLignesDeLaSuperLigne + SuperLigne2->NombreDeLignesDeLaSuperLigne; +if ( Demande > SuperLigne1->CapaciteDesColonnes ) { + LU_AugmenterCapaciteDesColonnesDeSuperLigne( Matrice , SuperLigne1 , Demande ); +} + +ElmColonneDeSuperLigne_1 = SuperLigne1->ElmColonneDeSuperLigne; +ElmColonneDeSuperLigne_2 = SuperLigne2->ElmColonneDeSuperLigne; + +NombreDeLignesDeLaSuperLigne_2 = SuperLigne2->NombreDeLignesDeLaSuperLigne; +NumerosDesLignesDeLaSuperLigne_2 = SuperLigne2->NumerosDesLignesDeLaSuperLigne; +IndiceColonne_2 = SuperLigne2->IndiceColonne; +CapaciteDesColonnes_2 = SuperLigne2->CapaciteDesColonnes; + +NombreDeLignesDeLaSuperLigne_1 = SuperLigne1->NombreDeLignesDeLaSuperLigne; +NumerosDesLignesDeLaSuperLigne_1 = SuperLigne1->NumerosDesLignesDeLaSuperLigne; +CapaciteDesColonnes_1 = SuperLigne1->CapaciteDesColonnes; + +for ( il2 = 0 ; il2 < SuperLigne2->NombreDeTermes ; il2++ ) { + + il1 = T[IndiceColonne_2[il2]]; + il1--; + ic1 = CapaciteDesColonnes_1 * il1; + ic1+= NombreDeLignesDeLaSuperLigne_1; + + ic2 = CapaciteDesColonnes_2 * il2; + + memcpy( (char *) &(ElmColonneDeSuperLigne_1[ic1]) , + (char *) &(ElmColonneDeSuperLigne_2[ic2]) , + NombreDeLignesDeLaSuperLigne_2 * sizeof( double ) ); +} + +IndexDuTermeDiagonal_1 = SuperLigne1->IndexDuTermeDiagonal; +IndexDuTermeDiagonal_2 = SuperLigne2->IndexDuTermeDiagonal; + +for ( i = 0 ; i < NombreDeLignesDeLaSuperLigne_2; i++ ) { + Ligne = NumerosDesLignesDeLaSuperLigne_2[i]; + SuperLigneDeLaLigne[Ligne] = SuperLigne1; + NumerosDesLignesDeLaSuperLigne_1[NombreDeLignesDeLaSuperLigne_1] = Ligne; + + if ( Matrice->FaireDuPivotageDiagonal == OUI_LU ) { + /* Nouvel index du terme diagonal des lignes adjointes */ + il2 = IndexDuTermeDiagonal_2[i]; + /* il2 correspondait a la colonne SuperLigne2->IndiceColonne[il2] => on utilise la transformation T */ + IndexDuTermeDiagonal_1[NombreDeLignesDeLaSuperLigne_1] = T[IndiceColonne_2[il2]] - 1; + } + + NombreDeLignesDeLaSuperLigne_1++; +} +SuperLigne1->NombreDeLignesDeLaSuperLigne = NombreDeLignesDeLaSuperLigne_1; + +/* Liberation du struct de la super ligne */ + +SuperLigne2->NombreDeTermes = 0; +SuperLigne2->NombreDeLignesDeLaSuperLigne = 0; + +free( SuperLigne2->NumerosDesLignesDeLaSuperLigne ); +free( SuperLigne2->IndexDuTermeDiagonal ); +free( SuperLigne2->IndiceColonne ); +free( SuperLigne2->ElmColonneDeSuperLigne ); +free( SuperLigne2 ); + +Matrice->SuperLigne[DeuxiemeSuperLigne] = NULL; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_AjouterUneLigneDansUneSuperLigne( MATRICE * Matrice , SUPER_LIGNE_DE_LA_MATRICE * SuperLigne , + int * T , int LigneAAjouter ) +{ +int il2; int il2Max; int il1; int ic1; int Demande; int IndexDuTermeDiagonal; double * ElmColonneDeSuperLigne; +int CapaciteDesColonnes; int NombreDeLignesDeLaSuperLigne; +int * Ldeb; int * LNbTerm; int * LIndiceColonne; double * Elm; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +Demande = SuperLigne->NombreDeLignesDeLaSuperLigne + 1; +if ( Demande > SuperLigne->CapaciteDesColonnes ) { + LU_AugmenterCapaciteDesColonnesDeSuperLigne( Matrice , SuperLigne , Demande ); +} + +ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; +CapaciteDesColonnes = SuperLigne->CapaciteDesColonnes; +NombreDeLignesDeLaSuperLigne = SuperLigne->NombreDeLignesDeLaSuperLigne; + +IndexDuTermeDiagonal = 0; + +il2 = Ldeb[LigneAAjouter]; +il2Max = il2 + LNbTerm[LigneAAjouter]; +while ( il2 < il2Max ) { + + il1 = T[LIndiceColonne[il2]]; + + if ( LIndiceColonne[il2] == LigneAAjouter ) IndexDuTermeDiagonal = T[LIndiceColonne[il2]] - 1; + + il1--; + ic1 = CapaciteDesColonnes * il1; + ic1+= NombreDeLignesDeLaSuperLigne; + + ElmColonneDeSuperLigne[ic1] = Elm[il2]; + + il2++; +} + +Matrice->SuperLigneDeLaLigne[LigneAAjouter] = SuperLigne; + +SuperLigne->NumerosDesLignesDeLaSuperLigne[NombreDeLignesDeLaSuperLigne] = LigneAAjouter; +SuperLigne->IndexDuTermeDiagonal [NombreDeLignesDeLaSuperLigne] = IndexDuTermeDiagonal; +SuperLigne->NombreDeLignesDeLaSuperLigne++; + +return; + +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_declenchement.c b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_declenchement.c new file mode 100644 index 0000000000..37508432a2 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_declenchement.c @@ -0,0 +1,236 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Declenchement eventuel de la detection des super lignes + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_InitPourSuperLignes( MATRICE * Matrice ) +{ + +Matrice->MatricePleineDansUneSeuleSuperLigne = NON_LU; + +/* On fait une RAZ des tables de hash code */ +memset( (char *) Matrice->HashCodeLigne , 0 , Matrice->Rang * sizeof( unsigned int ) ); +memset( (char *) Matrice->TypeDeClassementHashCodeAFaire, ELEMENT_HASCODE_A_CLASSER , 2 * Matrice->Rang * sizeof( char ) ); + +Matrice->NbScanMin = 0; +Matrice->NombreDePassagesDansSuperLignes = 0; +Matrice->OnDeclenche = NON_LU; +Matrice->NbLignesSuperLignes = 0; +Matrice->NbFois = -1; +Matrice->Cycle = Matrice->Rang / 100; +Matrice->TauxPrec = 100.; +Matrice->NbScanSuperLignes = 0; +Matrice->LaMatriceEstPleine = NON_LU; + +Matrice->SeuilNombreDeSuperLigneAGrouper = SEUIL_NB_SUPER_LIGNES_A_GROUPER; +Matrice->SeuilNombreDeLignesAGrouper = SEUIL_1_NB_LIGNES_A_GROUPER; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +void LU_DeclenchementEventuelRechercheSuperLignes( MATRICE * Matrice ) +{ +int Kp; double Taux; char SuperLignesReamenagees; char ParVariationDeTaux; + +Kp = Matrice->Kp; + +Taux = (float)( Matrice->NombreDeTermes )/(float)( (float)(Matrice->Rang - Kp) * (float)(Matrice->Rang - Kp) ); +/* +printf("Kp %d NbFillIn %d Rang %d NombreDeTermes %d taux remplissage %f \n", +Kp,Matrice->NbFillIn,Matrice->Rang,Matrice->NombreDeTermes, +Taux ); +fflush(stdout); +*/ + +if ( ( Taux > 0.1 || Kp > 0.8 * Matrice->Rang ) && Matrice->NbFois == -1 ) { + Matrice->OnDeclenche = OUI_LU; + + Matrice->CycleDeBase = ( Matrice->Rang - Kp ) / 100; + Matrice->SeuilDeVariationDeBase = 0.1/*0.05*/; + + Matrice->Cycle = Matrice->CycleDeBase; + Matrice->SeuilDeVariation = Matrice->SeuilDeVariationDeBase; + + Matrice->NbFois = Matrice->Cycle; + + /*printf("Declenchement superlignes Kp = %d Rang = %d\n",Kp,Matrice->Rang);*/ + +} + +if ( Matrice->LaMatriceEstPleine == OUI_LU && Matrice->OnDeclenche == OUI_LU ) { + + /* printf("Kp = %d on met tout dans une seule super ligne\n",Kp); */ + + LU_MettreTouteLaMatriceDansUneSuperLigne( Matrice ); + Matrice->MatricePleineDansUneSeuleSuperLigne = OUI_LU; + Matrice->OnDeclenche = NON_LU; + Matrice->NbFois = Matrice->Rang; +} + +if ( Matrice->LaMatriceEstPleine == OUI_LU && Matrice->OnDeclenche == OUI_LU ) { + + printf("Kp = %d la matrice est pleine, on relance une recherche de super lignes car on devrait alors tout fusionner\n",Kp); + + LU_DetectionSuperLignes( Matrice , &SuperLignesReamenagees ); + Matrice->OnDeclenche = NON_LU; + + /* Verification. Il ne doit avoir qu'une seule super ligne rempli grace aux fusion */ + { + int j; int nbsl; + nbsl = 0; + for ( j = 0 ; j < Matrice->NombreDeSuperLignes ; j++ ) { + if ( Matrice->SuperLigne[j] == NULL ) continue; + nbsl++; + } + /* printf("############### NombreDeSuperLignes non vides %d Kp %d\n", nbsl, Kp); */ + if ( nbsl != 1 ) { + printf(" BUG, il doit y avoir 1 et 1 seul super ligne car la matrice est pleine\n"); + exit(0); + } + } + +} + +if ( Matrice->OnDeclenche == OUI_LU ) { + + /* printf(" Kp = %d Taux = %f\n",Kp,Taux); */ + + if ( Matrice->NbFois >= Matrice->Cycle || Taux > Matrice->TauxPrec + Matrice->SeuilDeVariation ) { + if ( Taux > Matrice->TauxPrec + Matrice->SeuilDeVariation ) ParVariationDeTaux = OUI_LU; + else ParVariationDeTaux = NON_LU; + Matrice->TauxPrec = Taux; + LU_DetectionSuperLignes( Matrice , &SuperLignesReamenagees ); + /* S'il n'y a pas eu de reamenagement de lignes, on diminue la frequence de recherche */ + if ( SuperLignesReamenagees == NON_LU && 0 ) { + if ( ParVariationDeTaux == OUI_LU ) { + Matrice->SeuilDeVariation+= Matrice->SeuilDeVariationDeBase; + if ( Matrice->TauxPrec + Matrice->SeuilDeVariation > 1.0 ) { + /* Pour ne pas bloquer on baisse un peu SeuilDeVariation */ + Matrice->SeuilDeVariation = 0.5 * ( 1 - Taux ); + } + } + else { + Matrice->Cycle+= Matrice->CycleDeBase; + /* Pour eviter de bloquer */ + if ( Matrice->Cycle > Matrice->Rang - Kp ) Matrice->Cycle = ceil ( 0.5 * ( Matrice->Rang - Kp ) ); + } + } + else { + /* + if ( ParVariationDeTaux == OUI_LU ) { + Matrice->SeuilDeVariation-= Matrice->SeuilDeVariationDeBase; + if ( Matrice->SeuilDeVariation < Matrice->SeuilDeVariationDeBase ) Matrice->SeuilDeVariation = Matrice->SeuilDeVariationDeBase; + } + else { + Matrice->Cycle-= Matrice->CycleDeBase; + if ( Matrice->Cycle < Matrice->CycleDeBase ) Matrice->Cycle = Matrice->CycleDeBase; + } + */ + } + /* + printf(" SuperLignes Kp = %d NombreDeSuperLignes = %d Taux = %f Cycle %d\n",Kp,Matrice->NombreDeSuperLignes,Taux,Matrice->Cycle); + */ + Matrice->NbFois = 0; + } + else { + Matrice->NbFois++; + } +} + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_detection.c b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_detection.c new file mode 100644 index 0000000000..b067b5c1d7 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_detection.c @@ -0,0 +1,351 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Detection des super lignes + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_RechercherUnGroupeDeLignes( MATRICE * Matrice, int * NbElements, int * NumeroDElement, + int ElementRef , int hashCodeRef , int NbTermesRef , + int * T , int * NbLignesAGrouper , + int * NbSuperLignesAGrouper + ) +{ int Element; int il; int ilMax; int k; int NbEl; int Rang; int NbLignes; int NbSuperLignes; +SUPER_LIGNE_DE_LA_MATRICE * ptSuperLigne; +int * HashModuloSuiv; unsigned int * HashCodeLigne; unsigned int * HashCodeSuperLigne; +SUPER_LIGNE_DE_LA_MATRICE ** SuperLigne; int * SIndiceColonne; +int * Ldeb; int * LNbTerm; int * LIndiceColonne; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; + +HashModuloSuiv = Matrice->HashModuloSuiv; +HashCodeLigne = Matrice->HashCodeLigne; +HashCodeSuperLigne = Matrice->HashCodeSuperLigne; + +SuperLigne = Matrice->SuperLigne; + +Rang = Matrice->Rang; + +NbEl = *NbElements; +NbLignes = *NbLignesAGrouper; +NbSuperLignes = *NbSuperLignesAGrouper; + +Element = HashModuloSuiv[ElementRef]; +while ( Element >= 0 ) { + if ( Element < Rang ) { + /* C'est une ligne */ + if ( HashCodeLigne[Element] != (unsigned int) hashCodeRef ) goto AutreElement; + + k = LNbTerm[Element]; + if ( k != NbTermesRef ) goto AutreElement; + + il = Ldeb[Element]; + ilMax = il + k; + while ( il < ilMax ) { + if ( T[LIndiceColonne[il]] == 0 ) goto AutreElement; + il++; + } + } + else { + /* C'est une super ligne */ + if ( HashCodeSuperLigne[Element - Rang] != (unsigned int) hashCodeRef ) goto AutreElement; + ptSuperLigne = SuperLigne[Element - Rang]; + k = ptSuperLigne->NombreDeTermes; + if ( k != NbTermesRef ) goto AutreElement; + SIndiceColonne = ptSuperLigne->IndiceColonne; + for ( il = 0 ; il < k ; il++ ) { + if ( T[SIndiceColonne[il]] == 0 ) goto AutreElement; + } + } + NumeroDElement[NbEl] = Element; + NbEl++; + + if ( Element < Rang ) NbLignes++; + else NbSuperLignes++; + + AutreElement: + Element = HashModuloSuiv[Element]; +} + +*NbElements = NbEl; +*NbLignesAGrouper = NbLignes; +*NbSuperLignesAGrouper = NbSuperLignes; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_DetectionSuperLignes( MATRICE * Matrice , char * SuperLignesReamenagees ) + +{ int k; int Ligne; int il; int * T; int Element; int ilS; int hashCodeRef; int NbTermesRef; int Rang; + int ii; + +int * NumeroDElement; int NbElements; int ElementRef; int NumeroSuperLigne1; int NumeroSuperLigne2; +int NbSuperLignesAGrouper; int NbLignesAGrouper; int SeuilNbModuloIdentiques; + +unsigned int * HashCodeLigne; unsigned int * HashCodeSuperLigne; int * IndiceColonne; +int * HashModuloPrem; int * HashNbModuloIdentiques; int * HashModuloSuiv; char * TypeDeClassementHashCodeAFaire; + +SUPER_LIGNE_DE_LA_MATRICE * SuperLigne ; +SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneDeLaMatrice; +SUPER_LIGNE_DE_LA_MATRICE * ptSuperLigne; + +int ilMax; int * Ldeb; int * LNbTerm; int * LIndiceColonne; int ilDeb; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; + +/* Classement de toutes les lignes en fonction de leur hashcode */ +if ( Matrice->NombreDePassagesDansSuperLignes == 0 ) { + LU_CreerLesHashCode( Matrice ); + LU_ClasserLesElementsEnFonctionDuHashCode( Matrice ); +} +else { + LU_MajClassementDesElementsEnFonctionDuHashCode( Matrice ); +} +Matrice->NombreDePassagesDansSuperLignes++; +*SuperLignesReamenagees = NON_LU; + +Rang = Matrice->Rang; + +T = (int *) Matrice->W; +memset( (char *) T , 0 , Matrice->Rang * sizeof( int ) ); + +HashCodeLigne = Matrice->HashCodeLigne; +HashCodeSuperLigne = Matrice->HashCodeSuperLigne; +HashModuloPrem = Matrice->HashModuloPrem; +HashNbModuloIdentiques = Matrice->HashNbModuloIdentiques; +HashModuloSuiv = Matrice->HashModuloSuiv; +TypeDeClassementHashCodeAFaire = Matrice->TypeDeClassementHashCodeAFaire; + +SuperLigneDeLaMatrice = Matrice->SuperLigne; + +NumeroDElement = (int *) Matrice->SolutionIntermediaire; + +if ( Matrice->NombreDeSuperLignes <= 0 ) { + SeuilNbModuloIdentiques = Matrice->SeuilNombreDeLignesAGrouper; +} +else { + if ( Matrice->SeuilNombreDeSuperLigneAGrouper < Matrice->SeuilNombreDeLignesAGrouper ) { + SeuilNbModuloIdentiques = Matrice->SeuilNombreDeSuperLigneAGrouper; + } + else { + SeuilNbModuloIdentiques = Matrice->SeuilNombreDeLignesAGrouper; + } +} + +for ( k = 0 ; k < Matrice->HashModuloSize ; k++ ) { + if ( HashNbModuloIdentiques[k] < SeuilNbModuloIdentiques ) continue; + Element = HashModuloPrem[k]; + while ( Element >= 0 ) { + NumeroDElement[0] = Element; + NbElements = 1; + ElementRef = Element; + NbLignesAGrouper = 0; + NbSuperLignesAGrouper = 0; + + if ( Element < Rang ) { + /* C'est une ligne */ + hashCodeRef = HashCodeLigne[Element]; + ilDeb = Ldeb[Element]; + NbTermesRef = LNbTerm[Element]; + IndiceColonne = LIndiceColonne; + il = ilDeb; + ilMax = il + NbTermesRef; + NbLignesAGrouper++; + } + else { + /* C'est une super ligne */ + hashCodeRef = HashCodeSuperLigne[Element - Rang]; + ptSuperLigne = SuperLigneDeLaMatrice[Element - Rang]; + NbTermesRef = ptSuperLigne->NombreDeTermes; + IndiceColonne = ptSuperLigne->IndiceColonne; + ilDeb = 0; + ilMax = NbTermesRef; + NbSuperLignesAGrouper++; + } + + for ( il = ilDeb , ii = 0 ; il < ilMax ; il++ , ii++ ) T[IndiceColonne[il]] = ii + 1; + + LU_RechercherUnGroupeDeLignes( Matrice , &NbElements, NumeroDElement, + ElementRef, hashCodeRef, NbTermesRef , T, + &NbLignesAGrouper , &NbSuperLignesAGrouper ); + + /* Il est imperatif d'avoir plus de 1 ligne dans SuperLigne a cause de LU_SelectionPivot */ + SuperLigne = NULL; + + if ( NbSuperLignesAGrouper == 0 ) { + if ( NbLignesAGrouper >= Matrice->SeuilNombreDeLignesAGrouper ) { + *SuperLignesReamenagees = OUI_LU; + /* + printf("Creation de la super ligne %d a %d lignes\n",Matrice->NombreDeSuperLignes,NbElements); + */ + SuperLigne = LU_CreerUneSuperLigne( Matrice , T , NbElements , NumeroDElement , NbTermesRef ); + + /* Il faut reinitialiser T avant de liberer IndiceColonne */ + + for ( il = ilDeb ; il < ilMax ; il++ ) T[IndiceColonne[il]] = 0; + + + /* Il faut dechainer les lignes sauf le premier element car c'est l'element courant de la boucle */ + for ( il = 1 ; il < NbElements ; il++ ) { + /* Il faut dechainer la ligne */ + Ligne = NumeroDElement[il]; + LU_DeClasserEnFonctionDuHashCode( Matrice , Ligne ); + + TypeDeClassementHashCodeAFaire[Ligne] = ELEMENT_HASCODE_A_NE_PAS_CLASSER; + + /* La ligne a ete mise dans la super ligne, on peut liberer de la place dans la structure ligne */ + /* On ne libere pas la ligne pour pouvoir la reutiliser plus tard dans Ldeb etc .. */ + } + + TypeDeClassementHashCodeAFaire[NumeroDElement[0]] = ELEMENT_HASCODE_A_DECLASSER; + + /* Il est inutile de classer la super ligne pour ce coup-ci. Cependant on positionne son + indicateur comme etant a classe */ + il = Matrice->NombreDeSuperLignes - 1; /* c'est le numero de la super ligne que l'on vient de creer */ + il+= Rang; + TypeDeClassementHashCodeAFaire[il] = ELEMENT_HASCODE_A_CLASSER; + goto ElementSuivant; + } + goto RazT; + } + /* Il y a des superlignes a grouper */ + if ( NbLignesAGrouper == 0 ) { + /* Que des superlignes */ + if ( NbSuperLignesAGrouper >= Matrice->SeuilNombreDeSuperLigneAGrouper ) { + *SuperLignesReamenagees = OUI_LU; + /* Dans ce cas on fusionne toutes les super lignes */ + il = 0; + NumeroSuperLigne1 = NumeroDElement[il] - Rang; + il++; + for ( ; il < NbElements ; il++ ) { + NumeroSuperLigne2 = NumeroDElement[il] - Rang; + /* + printf("QUE_DES_SUPER_LIGNES Fusion de la super ligne %d dans la super ligne %d\n",NumeroSuperLigne2,NumeroSuperLigne1); + */ + LU_FusionnerDeuxSuperLignes( Matrice, T, NumeroSuperLigne1, NumeroSuperLigne2 ); + /* On ne doit pas declasser le premier element (celui pour lequel il = 0 ) car c'est l'element + courant de la boucle */ + LU_DeClasserEnFonctionDuHashCode( Matrice , NumeroDElement[il] ); + TypeDeClassementHashCodeAFaire[NumeroDElement[il]] = ELEMENT_HASCODE_A_NE_PAS_CLASSER; + } + /* Il faut reinitialiser T */ + for ( il = ilDeb ; il < ilMax ; il++ ) T[IndiceColonne[il]] = 0; + goto ElementSuivant; + } + goto RazT; + } + /* Il y a des super lignes et des lignes ( au moins 1 de chaque ) */ + if ( NbSuperLignesAGrouper >= Matrice->SeuilNombreDeSuperLigneAGrouper || + NbLignesAGrouper >= Matrice->SeuilNombreDeLignesAGrouper ) { + *SuperLignesReamenagees = OUI_LU; + } + /* Il y a des lignes et des super lignes. On fusionne d'abord toutes les super lignes + puis on ajoute toutes les lignes dans la super ligne qui remplace les fusionnees */ + ilS = 0; + NumeroSuperLigne1 = 0; + for ( il = 0 ; il < NbElements ; il++ ) { + if ( NumeroDElement[il] >= Rang ) { + NumeroSuperLigne1 = NumeroDElement[il] - Rang; + ilS = il + 1; + break; + } + } + + /* Constitution du nouveau vecteur T concernant la super ligne qu'on garde */ + for ( il = ilDeb ; il < NbTermesRef ; il++ ) T[IndiceColonne[il]] = 0; + + ptSuperLigne = SuperLigneDeLaMatrice[NumeroSuperLigne1]; + NbTermesRef = ptSuperLigne->NombreDeTermes; + IndiceColonne = ptSuperLigne->IndiceColonne; + ilDeb = 0; + ilMax = NbTermesRef; + + for ( il = ilDeb , ii = 0 ; il < ilMax ; il++ , ii++ ) T[IndiceColonne[il]] = ii + 1; + + /* Il faut dechainer les elements sauf le premier element car c'est l'element courant de la boucle */ + for ( il = ilS ; il < NbElements ; il++ ) { + if ( NumeroDElement[il] >= Rang ) { + NumeroSuperLigne2 = NumeroDElement[il] - Rang; + /* + printf("Fusion de la super ligne %d dans la super ligne %d\n",NumeroSuperLigne2,NumeroSuperLigne1); + */ + LU_FusionnerDeuxSuperLignes( Matrice, T, NumeroSuperLigne1, NumeroSuperLigne2 ); + /* On ne doit pas declasser le premier element (celui pour lequel il = 0 ) */ + LU_DeClasserEnFonctionDuHashCode( Matrice , NumeroDElement[il] ); + TypeDeClassementHashCodeAFaire[NumeroDElement[il]] = ELEMENT_HASCODE_A_NE_PAS_CLASSER; + } + } + + for ( il = 0 ; il < NbElements ; il++ ) { + if ( NumeroDElement[il] < Rang ) { + Ligne = NumeroDElement[il]; + /* + printf("Ajout de la ligne %d dans la super ligne %d\n",Ligne,NumeroSuperLigne1); + */ + LU_AjouterUneLigneDansUneSuperLigne( Matrice, Matrice->SuperLigne[NumeroSuperLigne1] , T , Ligne ); + /* Il faut dechainer la ligne sauf si c'est la premier element car c'est l'element courant de + la boucle */ + if ( il != 0 ) { + LU_DeClasserEnFonctionDuHashCode( Matrice , Ligne ); + TypeDeClassementHashCodeAFaire[Ligne] = ELEMENT_HASCODE_A_NE_PAS_CLASSER; + } + else TypeDeClassementHashCodeAFaire[Ligne] = ELEMENT_HASCODE_A_DECLASSER; + + /* La ligne a ete mise dans la super ligne, on ne libere pas la place dans Ldeb etc.. */ + } + } + + /* Il faut reinitialiser T */ + for ( il = ilDeb ; il < ilMax ; il++ ) T[IndiceColonne[il]] = 0; + goto ElementSuivant; + + RazT: + /* Rien trouve */ + for ( il = ilDeb ; il < ilMax ; il++ ) T[IndiceColonne[il]] = 0; + + ElementSuivant: + Element = HashModuloSuiv[Element]; + } +} + +/* printf("-----------------> Nombre de super lignes %d\n",Matrice->NombreDeSuperLignes); */ + +/* Si on a detecte des superlignes, on change le seuil concernant les lignes */ +Matrice->SeuilNombreDeLignesAGrouper = SEUIL_2_NB_LIGNES_A_GROUPER; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_merge_toutes_super_lignes.c b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_merge_toutes_super_lignes.c new file mode 100644 index 0000000000..2726dbe7de --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_merge_toutes_super_lignes.c @@ -0,0 +1,280 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Merge de toutes les super lignes + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ +/* On remplit toute la matrice avec des 0 au besoin et on met tout ca dans une super ligne */ +/* Attention lŕ dessous c'est codé que pour les matrices symetriques */ + +void LU_MettreTouteLaMatriceDansUneSuperLigne( MATRICE * Matrice ) +{ +SUPER_LIGNE_DE_LA_MATRICE * SuperLigne; SUPER_LIGNE_DE_LA_MATRICE * SuperLigne2; +int Demande; int i; int NombreDeTermes; int Ligne; int Colonne; int NombreDeLignes; +int ic; int il; int Kp; int NbTermesLigne; int ic1; int ic2; int il1; int il2; int * T; +int NbTermesSuperLigne; int * OrdreColonne; int * OrdreLigne; +int * NumerosDesLignesDeLaSuperLigne; int * IndexDuTermeDiagonal; int * IndiceColonne; +double * ElmColonneDeSuperLigne; char FaireDuPivotageDiagonal; + +SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneDeLaLigne; double * ElmColonneDeSuperLigne_2; +int CapaciteDesColonnes; int CapaciteDesColonnes_2; int NombreDeLignesDeLaSuperLigne_2; +int * NumerosDesLignesDeLaSuperLigne_2; int * IndexDuTermeDiagonal_2; + +int * Ldeb; int * LNbTerm; int * LIndiceColonne; int ilDeb; double * Elm; + +/*printf("Matrice->Kp %d on met toutes les lignes dans une seule super ligne\n",Matrice->Kp);*/ + +SuperLigneDeLaLigne = Matrice->SuperLigneDeLaLigne; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +OrdreLigne = Matrice->OrdreLigne; +OrdreColonne = Matrice->OrdreColonne; +FaireDuPivotageDiagonal = Matrice->FaireDuPivotageDiagonal; + +T = (int *) Matrice->W; +memset( (char *) T , 0 , Matrice->Rang * sizeof( int ) ); + +/* Construction d'un structure de superligne dans laquelle on va mettre toutes les lignes + et les super lignes qu'il reste */ + +NbTermesLigne = Matrice->Rang - Matrice->Kp; +NombreDeLignes = NbTermesLigne; + +SuperLigne = (SUPER_LIGNE_DE_LA_MATRICE *) malloc( sizeof( SUPER_LIGNE_DE_LA_MATRICE ) ); +if ( SuperLigne == NULL ) { + printf("Factorisation LU, sous-programme LU_CreerUneSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env, Matrice->AnomalieDetectee ); +} + +Demande = NombreDeLignes; +SuperLigne->NumerosDesLignesDeLaSuperLigne = (int *) malloc( Demande * sizeof( int ) ); +if ( SuperLigne->NumerosDesLignesDeLaSuperLigne == NULL ) { + printf("Factorisation LU, sous-programme LU_CreerUneSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); +} + +SuperLigne->IndexDuTermeDiagonal = (int *) malloc( Demande * sizeof( int ) ); +if ( SuperLigne->IndexDuTermeDiagonal == NULL ) { + printf("Factorisation LU, sous-programme LU_CreerUneSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); +} + +Demande = NbTermesLigne; +SuperLigne->IndiceColonne = (int *) malloc( Demande * sizeof( int ) ); +if ( SuperLigne->IndiceColonne == NULL ) { + printf("Factorisation LU, sous-programme LU_CreerUneSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); +} + +SuperLigne->ScannerLaSuperLigne = NON_LU; +SuperLigne->CapaciteDesColonnes = NombreDeLignes; +SuperLigne->NombreDeLignesDeLaSuperLigne = NombreDeLignes; +SuperLigne->Capacite = NbTermesLigne; +SuperLigne->NombreDeTermes = NbTermesLigne; +SuperLigne->NumeroDeLaSuperLigne = Matrice->NombreDeSuperLignes; + +NbTermesSuperLigne = NbTermesLigne; + +NumerosDesLignesDeLaSuperLigne = SuperLigne->NumerosDesLignesDeLaSuperLigne; +IndexDuTermeDiagonal = SuperLigne->IndexDuTermeDiagonal; +IndiceColonne = SuperLigne->IndiceColonne; +CapaciteDesColonnes = SuperLigne->CapaciteDesColonnes; + +il = 0; +for ( Kp = Matrice->Kp ; Kp < Matrice->Rang ; Kp++ ) { + Colonne = OrdreColonne[Kp]; + IndiceColonne[il] = Colonne; + T[Colonne] = il + 1; + il++; +} + +/* Le hash code devient inutile */ +Matrice->HashCodeSuperLigne[Matrice->NombreDeSuperLignes] = 0; + +Matrice->SuperLigne[Matrice->NombreDeSuperLignes] = SuperLigne; +SuperLigne->NumeroDeLaSuperLigne = Matrice->NombreDeSuperLignes; +Matrice->NombreDeSuperLignes++; + +Demande = CapaciteDesColonnes * SuperLigne->Capacite; + +/* +printf("CapaciteDesColonnes %d\n",SuperLigne->CapaciteDesColonnes); +printf("Capacite %d\n",SuperLigne->Capacite); +printf("Demande %d\n",Demande); +*/ + +SuperLigne->ElmColonneDeSuperLigne = (double *) malloc( Demande * sizeof( double ) ); +if ( SuperLigne->ElmColonneDeSuperLigne == NULL ) { + printf("Factorisation LU, sous-programme LU_CreerUneSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); +} + +ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; +/* RAZ obligatoire */ +memset( (char *) ElmColonneDeSuperLigne , 0 , Demande * sizeof( double ) ); + +NombreDeLignes = 0; +/* On ajoute les lignes */ +for ( Kp = Matrice->Kp ; Kp < Matrice->Rang ; Kp++ ) { + Ligne = OrdreLigne[Kp]; + if ( SuperLigneDeLaLigne[Ligne] != NULL ) continue; /* La ligne est dans une super ligne */ + /* + printf("On ajoute la ligne %d\n",Ligne); + */ + /* On ajoute la ligne a la super ligne */ + ilDeb = Ldeb[Ligne]; + NbTermesLigne = LNbTerm[Ligne]; + + + for ( il = ilDeb ; il < ilDeb + NbTermesLigne ; il++ ) { + ic = CapaciteDesColonnes * ( T[LIndiceColonne[il]] - 1 ); + + if ( LIndiceColonne[il] == Ligne ) { + IndexDuTermeDiagonal[NombreDeLignes] = T[LIndiceColonne[il]] - 1; + } + + if ( ic >= 0 ) { + ic+= NombreDeLignes; + ElmColonneDeSuperLigne[ic] = Elm[il]; + } + else { + printf("Bug, les termes de la ligne %d ont un indice colonne faux %d\n",Ligne,IndiceColonne[il]); + } + } + /* + printf("OK\n"); + */ + SuperLigneDeLaLigne[Ligne] = SuperLigne; + NumerosDesLignesDeLaSuperLigne[NombreDeLignes] = Ligne; + NombreDeLignes++; + + /* On ne libere pas la ligne pour la reutiliser plus tard */ + + if ( NbTermesLigne != NbTermesSuperLigne ) { + LU_DeClasserUneLigne( Matrice , Ligne , NbTermesLigne ); + LU_ClasserUneLigne( Matrice , Ligne , NbTermesSuperLigne ); + } + +} + +/* On ajoute les super lignes */ +for ( Kp = 0 ; Kp < Matrice->NombreDeSuperLignes - 1 ; Kp++ ) { + SuperLigne2 = Matrice->SuperLigne[Kp]; + if ( SuperLigne2 == NULL ) continue; + /* Ajoute la super ligne a la super ligne */ + /* + printf("On ajoute la super ligne %X NombreDeTermes %d Nombre de lignes %d\n", + SuperLigne2,SuperLigne2->NombreDeTermes,SuperLigne2->NombreDeLignesDeLaSuperLigne); + */ + + NombreDeTermes = SuperLigne2->NombreDeTermes; + IndiceColonne = SuperLigne2->IndiceColonne; + ElmColonneDeSuperLigne_2 = SuperLigne2->ElmColonneDeSuperLigne; + CapaciteDesColonnes_2 = SuperLigne2->CapaciteDesColonnes; + NombreDeLignesDeLaSuperLigne_2 = SuperLigne2->NombreDeLignesDeLaSuperLigne; + IndexDuTermeDiagonal_2 = SuperLigne2->IndexDuTermeDiagonal; + + for ( il2 = 0 ; il2 < NombreDeTermes ; il2++ ) { + il1 = T[IndiceColonne[il2]] - 1; + if ( il1 >= 0 ) { + ic1 = CapaciteDesColonnes * il1; + ic1+= NombreDeLignes; + ic2 = CapaciteDesColonnes_2 * il2; + memcpy( (char *) &(ElmColonneDeSuperLigne[ic1]) , + (char *) &(ElmColonneDeSuperLigne_2[ic2]) , + NombreDeLignesDeLaSuperLigne_2 * sizeof( double ) ); + } + else { + printf("Bug, les termes de la super ligne %lX ont un indice colonne faux %d\n", + (unsigned long) SuperLigne2,SuperLigne2->IndiceColonne[il2]); + } + } + /*printf("OK\n");*/ + + NumerosDesLignesDeLaSuperLigne_2 = SuperLigne2->NumerosDesLignesDeLaSuperLigne; + for ( i = 0 ; i < NombreDeLignesDeLaSuperLigne_2; i++ ) { + Ligne = NumerosDesLignesDeLaSuperLigne_2[i]; + SuperLigneDeLaLigne[Ligne] = SuperLigne; + + if ( NombreDeTermes != NbTermesSuperLigne ) { + LU_DeClasserUneLigne( Matrice , Ligne , NombreDeTermes ); + LU_ClasserUneLigne( Matrice , Ligne , NbTermesSuperLigne ); + } + + NumerosDesLignesDeLaSuperLigne[NombreDeLignes] = Ligne; + + if ( FaireDuPivotageDiagonal == OUI_LU ) { + /* Nouvel index du terme diagonal des lignes adjointes */ + il2 = IndexDuTermeDiagonal_2[i]; + /* il2 correspondait a la colonne SuperLigne2->IndiceColonne[il2] => on utilise la transformation T */ + IndexDuTermeDiagonal[NombreDeLignes] = T[IndiceColonne[il2]] - 1; + } + + NombreDeLignes++; + } + + /* Liberation du struct de la super ligne */ + SuperLigne2->NombreDeTermes = 0; + SuperLigne2->NombreDeLignesDeLaSuperLigne = 0; + + free( NumerosDesLignesDeLaSuperLigne_2 ); + free( IndexDuTermeDiagonal_2 ); + free( IndiceColonne ); + free( ElmColonneDeSuperLigne_2 ); + free( SuperLigne2 ); + + Matrice->SuperLigne[Kp] = NULL; + +} + +memset( (char *) T , 0 , Matrice->Rang * sizeof( int ) ); + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_modifications.c b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_modifications.c new file mode 100644 index 0000000000..e500646df2 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_modifications.c @@ -0,0 +1,211 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Gestion des super lignes + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ +/* On peut regrouper la suppression et la recopie d'une ligne de super ligne */ + +void LU_SupprimerUneLigneDansUneSuperLigne( MATRICE * Matrice , SUPER_LIGNE_DE_LA_MATRICE * SuperLigne , int LigneASupprimer , + int ColonnePivot ) +{ +int ic; int i; int NumeroDeLaSuperLigne; int * IndiceColonne; double * ElmColonneDeSuperLigne; +int * NumerosDesLignesDeLaSuperLigne; int iccDeb; int icc; double X; int CapaciteDesColonnes; +int DernierIndexDeColonne; int * IndexDuTermeDiagonal; + +IndiceColonne = SuperLigne->IndiceColonne; +ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; +NumerosDesLignesDeLaSuperLigne = SuperLigne->NumerosDesLignesDeLaSuperLigne; +IndexDuTermeDiagonal = SuperLigne->IndexDuTermeDiagonal; +CapaciteDesColonnes = SuperLigne->CapaciteDesColonnes; + +DernierIndexDeColonne = SuperLigne->NombreDeLignesDeLaSuperLigne - 1; + +/* Recherche de l'indice ou se trouvent les termes de la ligne */ +for ( ic = 0 ; ic < SuperLigne->NombreDeLignesDeLaSuperLigne ; ic++ ) { + if ( NumerosDesLignesDeLaSuperLigne[ic] == LigneASupprimer ) { + /* Suppression de toute reference a LigneASupprimer dans la SuperLigne */ + NumerosDesLignesDeLaSuperLigne[ic] = NumerosDesLignesDeLaSuperLigne[DernierIndexDeColonne]; + IndexDuTermeDiagonal [ic] = IndexDuTermeDiagonal[DernierIndexDeColonne]; + break; + } +} + +for ( i = 0 ; i < SuperLigne->NombreDeTermes ; i++ ) { + if ( IndiceColonne[i] == ColonnePivot ) { + iccDeb = i * CapaciteDesColonnes; + icc = iccDeb + ic; + /* Suppression du terme de la super ligne */ + ElmColonneDeSuperLigne[icc] = ElmColonneDeSuperLigne[iccDeb + DernierIndexDeColonne]; + break; + } +} + +/* Suppression des termes de la super ligne */ +for ( i = 0 ; i < SuperLigne->NombreDeTermes ; i++ ) { + if ( IndiceColonne[i] == ColonnePivot ) continue; + /* Sauvegarde du terme de la ligne pivot */ + iccDeb = i * CapaciteDesColonnes; + icc = iccDeb + ic; + X = ElmColonneDeSuperLigne[icc]; + /* On supprime le terme de la ligne pivot */ + ElmColonneDeSuperLigne[icc] = ElmColonneDeSuperLigne[iccDeb + DernierIndexDeColonne]; +} + +SuperLigne->NombreDeLignesDeLaSuperLigne--; + +if ( SuperLigne->NombreDeLignesDeLaSuperLigne == 0 ) { + + NumeroDeLaSuperLigne = SuperLigne->NumeroDeLaSuperLigne; + + free( SuperLigne->NumerosDesLignesDeLaSuperLigne ); + free( SuperLigne->IndexDuTermeDiagonal ); + free( SuperLigne->IndiceColonne ); + free( SuperLigne->ElmColonneDeSuperLigne ); + free( SuperLigne ); + + if ( Matrice->TypeDeClassementHashCodeAFaire[NumeroDeLaSuperLigne+Matrice->Rang] == ELEMENT_HASCODE_A_CLASSER ) { + Matrice->TypeDeClassementHashCodeAFaire[NumeroDeLaSuperLigne+Matrice->Rang] = ELEMENT_HASCODE_A_NE_PAS_CLASSER; + } + else if ( Matrice->TypeDeClassementHashCodeAFaire[NumeroDeLaSuperLigne+Matrice->Rang] == ELEMENT_HASCODE_CLASSE ) { + Matrice->TypeDeClassementHashCodeAFaire[NumeroDeLaSuperLigne+Matrice->Rang] = ELEMENT_HASCODE_A_DECLASSER; + } + else if ( Matrice->TypeDeClassementHashCodeAFaire[NumeroDeLaSuperLigne+Matrice->Rang] == ELEMENT_HASCODE_A_RECLASSER ) { + Matrice->TypeDeClassementHashCodeAFaire[NumeroDeLaSuperLigne+Matrice->Rang] = ELEMENT_HASCODE_A_DECLASSER; + } + + Matrice->SuperLigne[NumeroDeLaSuperLigne] = NULL; + +} +else { + /* S'il reste des lignes mais trop de vide, on retasse */ + if ( SuperLigne->NombreDeLignesDeLaSuperLigne < 10 ) { + if ( SuperLigne->CapaciteDesColonnes - SuperLigne->NombreDeLignesDeLaSuperLigne > SuperLigne->NombreDeLignesDeLaSuperLigne ) { + LU_DiminuerCapaciteDesColonnesDeSuperLigne( Matrice , SuperLigne ); + } + } +} + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Supprimer une colonne dans une super ligne, c'est toujours les termes de la colonne pivot */ + +void LU_SupprimerUnTermeDansUneSuperLigne( MATRICE * Matrice, + SUPER_LIGNE_DE_LA_MATRICE * SuperLigne, + int icDebColonnePivot, + int NumeroDeColonneDansSuperLigne ) +{ +int ic; int ic1; int * IndiceColonne; int i; int * IndexDuTermeDiagonal; + +IndiceColonne = SuperLigne->IndiceColonne; + +Matrice->HashCodeSuperLigne[SuperLigne->NumeroDeLaSuperLigne]-= Matrice->PoidsDesColonnes[IndiceColonne[NumeroDeColonneDansSuperLigne]]; + +/* debut de la colonne pivot */ +ic = icDebColonnePivot; +/* Debut de la derniere colonne */ +ic1 = SuperLigne->CapaciteDesColonnes * ( SuperLigne->NombreDeTermes - 1 ); + +/* Rien a faire si on supprime le dernier terme */ +if ( ic != ic1 ) { + memcpy( (char *) &(SuperLigne->ElmColonneDeSuperLigne[ic]) , (char *) &(SuperLigne->ElmColonneDeSuperLigne[ic1]) , + SuperLigne->CapaciteDesColonnes * sizeof( double ) ); + + IndiceColonne[NumeroDeColonneDansSuperLigne] = IndiceColonne[SuperLigne->NombreDeTermes - 1]; + + /* Mise a jour des index des termes diagonaux */ + if ( Matrice->FaireDuPivotageDiagonal == OUI_LU ) { + IndexDuTermeDiagonal = SuperLigne->IndexDuTermeDiagonal; + for ( i = 0 ; i < SuperLigne->NombreDeLignesDeLaSuperLigne; i++ ) { + if ( IndexDuTermeDiagonal[i] == SuperLigne->NombreDeTermes - 1 ) { + IndexDuTermeDiagonal[i] = NumeroDeColonneDansSuperLigne; + break; + } + } + } + +} + +SuperLigne->NombreDeTermes--; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* On recopie une ligne d'une super ligne dans une ligne normale */ + +void LU_RecopierUneLigneDeSuperLigneDansLigne( MATRICE * Matrice, + SUPER_LIGNE_DE_LA_MATRICE * SuperLigne, + int LigneACopier ) +{ +int ic; int i; int il; int NombreDeLignesDeLaSuperLigne; int * NumerosDesLignesDeLaSuperLigne; +int NombreDeTermes; int CapaciteDesColonnes; double * ElmColonneDeSuperLigne; int * IndiceColonne; +int Demande; int ilDeb; int * Ldeb; int * LNbTerm; int * LIndiceColonne; double * Elm; + +NombreDeLignesDeLaSuperLigne = SuperLigne->NombreDeLignesDeLaSuperLigne; +NumerosDesLignesDeLaSuperLigne = SuperLigne->NumerosDesLignesDeLaSuperLigne; + +NombreDeTermes = SuperLigne->NombreDeTermes; +CapaciteDesColonnes = SuperLigne->CapaciteDesColonnes; +ElmColonneDeSuperLigne = SuperLigne->ElmColonneDeSuperLigne; +IndiceColonne = SuperLigne->IndiceColonne; + +Ldeb = Matrice->Ldeb; +LNbTerm = Matrice->LNbTerm; +LIndiceColonne = Matrice->LIndiceColonne; +Elm = Matrice->Elm; + +ilDeb = Ldeb[LigneACopier]; +if ( ilDeb + NombreDeTermes - 1 > Matrice->LDernierPossible[LigneACopier] ) { + Demande = NombreDeTermes; + LU_AugmenterLaTailleDeLaMatriceActive( Matrice , LigneACopier , Demande ); + ilDeb = Matrice->Ldeb[LigneACopier]; + LIndiceColonne = Matrice->LIndiceColonne; + Elm = Matrice->Elm; +} + +for ( ic = 0 ; ic < NombreDeLignesDeLaSuperLigne ; ic++ ) { + if ( NumerosDesLignesDeLaSuperLigne[ic] == LigneACopier ) break; +} + +il = ilDeb; +for ( i = 0 ; i < NombreDeTermes ; i++ ) { + Elm [il] = ElmColonneDeSuperLigne[ic]; + LIndiceColonne[il] = IndiceColonne[i]; + ic+= CapaciteDesColonnes; + il++; +} +LNbTerm[LigneACopier] = NombreDeTermes; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_reallocs.c b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_reallocs.c new file mode 100644 index 0000000000..0f0d21a9aa --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_super_lignes_reallocs.c @@ -0,0 +1,141 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Gestion des super lignes + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ + +void LU_AugmenterCapaciteDesColonnesDeSuperLigne( MATRICE * Matrice , + SUPER_LIGNE_DE_LA_MATRICE * SuperLigne , + int CapaciteMinDemandee ) +{ +int Demande; double * ElmColonneDeSuperLigne; int CapaciteDesColonnes; int ic; int ic1; int i; + +/* On augmente la capacite de la valeur d'increment */ + +Demande = CapaciteMinDemandee + INCREMENT_ALLOC_NB_LIGNES_DE_SUPER_LIGNE; +CapaciteDesColonnes = Demande; +/* On veut ajouter des lignes dans la super ligne */ +SuperLigne->NumerosDesLignesDeLaSuperLigne = (int *) realloc( SuperLigne->NumerosDesLignesDeLaSuperLigne , + Demande * sizeof( int ) ); +SuperLigne->IndexDuTermeDiagonal = (int *) realloc( SuperLigne->IndexDuTermeDiagonal , + Demande * sizeof( int ) ); +Demande*= SuperLigne->Capacite; +ElmColonneDeSuperLigne = (double *) malloc( Demande * sizeof( double ) ); +if ( ElmColonneDeSuperLigne == NULL ) { + printf("Factorisation LU, sous-programme LU_AugmenterCapaciteDesColonnesDeSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); +} + +ic = 0; +ic1 = 0; +for ( i = 0 ; i < SuperLigne->NombreDeTermes ; i++ ) { + memcpy( (char *) &ElmColonneDeSuperLigne[ic] , (char *) &(SuperLigne->ElmColonneDeSuperLigne[ic1]) , + SuperLigne->NombreDeLignesDeLaSuperLigne * sizeof( double ) ); + ic+= CapaciteDesColonnes; + ic1+= SuperLigne->CapaciteDesColonnes; +} + +SuperLigne->CapaciteDesColonnes = CapaciteDesColonnes; + +free( SuperLigne->ElmColonneDeSuperLigne ); + +SuperLigne->ElmColonneDeSuperLigne = ElmColonneDeSuperLigne; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Si la capacite est trop grande par rapport au nombre de ligne on enleve de la capacite pour + ameliorer le fonctionnement du cache memoire */ + +void LU_DiminuerCapaciteDesColonnesDeSuperLigne( MATRICE * Matrice , + SUPER_LIGNE_DE_LA_MATRICE * SuperLigne ) +{ +int Demande; double * ElmColonneDeSuperLigne; int CapaciteDesColonnes; int ic; int ic1; int i; + +Demande = SuperLigne->NombreDeLignesDeLaSuperLigne + INCREMENT_ALLOC_NB_LIGNES_DE_SUPER_LIGNE; +CapaciteDesColonnes = Demande; + +Demande*= SuperLigne->Capacite; +ElmColonneDeSuperLigne = (double *) malloc( Demande * sizeof( double ) ); +if ( ElmColonneDeSuperLigne == NULL ) { + printf("Factorisation LU, sous-programme LU_DiminuerCapaciteDesColonnesDeSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); +} + +ic = 0; +ic1 = 0; +for ( i = 0 ; i < SuperLigne->NombreDeTermes ; i++ ) { + memcpy( (char *) &ElmColonneDeSuperLigne[ic] , (char *) &(SuperLigne->ElmColonneDeSuperLigne[ic1]) , + SuperLigne->NombreDeLignesDeLaSuperLigne * sizeof( double ) ); + ic+= CapaciteDesColonnes; + ic1+= SuperLigne->CapaciteDesColonnes; +} + +SuperLigne->CapaciteDesColonnes = CapaciteDesColonnes; + +free( SuperLigne->ElmColonneDeSuperLigne ); + +SuperLigne->ElmColonneDeSuperLigne = ElmColonneDeSuperLigne; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* On veut augmenter le nombre de termes possibles dans les lignes de SuperLigne (pour ajouter des colonnes) */ + +void LU_AugmenterCapaciteDeSuperLigne( MATRICE * Matrice , SUPER_LIGNE_DE_LA_MATRICE * SuperLigne , int CapaciteMinDemandee ) +{ +int Demande; + +Demande = CapaciteMinDemandee + INCREMENT_ALLOC_NB_COLONNES_DE_SUPER_LIGNE; +SuperLigne->IndiceColonne = (int *) realloc( SuperLigne->IndiceColonne , Demande * sizeof( int ) ); +SuperLigne->Capacite = Demande; + +Demande = SuperLigne->Capacite * SuperLigne->CapaciteDesColonnes; +SuperLigne->ElmColonneDeSuperLigne = (double *) realloc( SuperLigne->ElmColonneDeSuperLigne , Demande * sizeof( double ) ); +if ( SuperLigne->ElmColonneDeSuperLigne == NULL ) { + printf("Factorisation LU, sous-programme LU_AugmenterCapaciteDeSuperLigne: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_switch_markowitz.c b/src/ext/Sirius_Solver/simplexe/lu/lu_switch_markowitz.c new file mode 100644 index 0000000000..4a08e15717 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_switch_markowitz.c @@ -0,0 +1,127 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Switch vers le pivotage de Markowitz en cas d'instabilite + de la factorisee + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# ifdef LU_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "lu_memoire.h" +# endif + +/*--------------------------------------------------------------------------------------------------*/ +void LU_SwitchVersMarkowitz( MATRICE * Matrice ) +{ +/* PB: pour l'instant je ne gere pas le fait de ne pas avoir cree de colonnes si la matrice est symetrique + ou symetrique en structure */ + +LU_ClasserLesColonnesRestantes( Matrice ); +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +void LU_ClasserLesColonnesRestantes( MATRICE * Matrice ) +{ + + +# ifdef ON_COMPILE + +int Kp; int Rang; int Colonne; int Ligne; int NbElements; int NombreDeTermes; +COLONNE_DE_LA_MATRICE ** ColonneDeLaMatrice;LIGNE_DE_LA_MATRICE ** LigneDeLaMatrice; +COLONNE_DE_LA_MATRICE * ptColonne; LIGNE_DE_LA_MATRICE * ptLigne; +int * IndiceColonne; int * IndiceLigne; + +SUPER_LIGNE_DE_LA_MATRICE ** SuperLigneDeLaLigne; SUPER_LIGNE_DE_LA_MATRICE * ptSuperLigne; +char UtiliserLesSuperLignes; + +UtiliserLesSuperLignes = Matrice->UtiliserLesSuperLignes; + +/* On etait en pivotage diagonal : les lignes sont classees mais il faut classer toutes les colonnes */ +Rang = Matrice->Rang; +ColonneDeLaMatrice = Matrice->ColonneDeLaMatrice; + +printf("Changement vers pivot total Matrice->Kp %d\n",Matrice->Kp); + +/* Si la matrice etait symetrique, il faut construire un chainage par colonne */ +if ( Matrice->LaMatriceEstSymetrique != OUI_LU ) goto ClassementDesColonnes; + +LigneDeLaMatrice = Matrice->LigneDeLaMatrice; + +SuperLigneDeLaLigne = Matrice->SuperLigneDeLaLigne; + +for ( Kp = Matrice->Kp ; Kp < Rang ; Kp++ ) { + Colonne = Matrice->OrdreColonne[Kp]; + ptColonne = ColonneDeLaMatrice[Colonne]; + /* La colonne aura le meme nombre de termes que la ligne */ + Ligne = Colonne; + + if ( UtiliserLesSuperLignes == OUI_LU ) { + if ( SuperLigneDeLaLigne[Ligne] == NULL ) { + ptLigne = LigneDeLaMatrice[Ligne]; + NombreDeTermes = ptLigne->NombreDeTermes; + IndiceColonne = ptLigne->IndiceColonne; + } + printf(" super ligne \n"); + ptSuperLigne = SuperLigneDeLaLigne[Ligne]; + NombreDeTermes = ptSuperLigne->NombreDeTermes; + IndiceColonne = ptSuperLigne->IndiceColonne; + } + else { + ptLigne = LigneDeLaMatrice[Ligne]; + NombreDeTermes = ptLigne->NombreDeTermes; + IndiceColonne = ptLigne->IndiceColonne; + } + + ptColonne->NombreDeTermes = NombreDeTermes; + + NbElements = NombreDeTermes + Matrice->MargePourCreationDeTermesColonnes; + ptColonne->DernierPossible = NbElements - 1; + + IndiceLigne = (int *) malloc( NbElements * sizeof( int ) ); + if ( IndiceLigne == NULL ) { + printf("Factorisation LU, sous-programme LU_ConstruireProbleme: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Matrice->AnomalieDetectee = SATURATION_MEMOIRE; + longjmp( Matrice->Env , Matrice->AnomalieDetectee ); + } + + memcpy( (char *) IndiceLigne, (char *) IndiceColonne, NombreDeTermes * sizeof( int ) ); + free( ptColonne->IndiceLigne ); + ptColonne->IndiceLigne = IndiceLigne; +} + +ClassementDesColonnes: +for ( Kp = Matrice->Kp ; Kp < Rang ; Kp++ ) { + Colonne = Matrice->OrdreColonne[Kp]; + printf("Classement colonne %d Nbtermes %d\n",Colonne,ColonneDeLaMatrice[Colonne]->NombreDeTermes); + LU_ClasserUneColonne( Matrice, Colonne, ColonneDeLaMatrice[Colonne]->NombreDeTermes); +} + +Matrice->LaMatriceEstSymetrique = NON_LU; +Matrice->FaireDuPivotageDiagonal = NON_LU; + +# endif + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_sys.h b/src/ext/Sirius_Solver/simplexe/lu/lu_sys.h new file mode 100644 index 0000000000..c8eb836568 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_sys.h @@ -0,0 +1,32 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# include +# include +# include +# include +# include +/* # include */ +# include +# include +# include +/* # include */ +/* +# include +# include +*/ + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/lu_update.c b/src/ext/Sirius_Solver/simplexe/lu/lu_update.c new file mode 100644 index 0000000000..d3f4662bf9 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/lu_update.c @@ -0,0 +1,715 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Pour le simplexe uniquement. Update de la factorisation LU + dans le cas d'une base adjacente. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "lu_define.h" +# include "lu_fonctions.h" + +# if OUTILS_DE_GESTION_MEMOIRE_DE_PNE_SOLVEUR + # include "mem_fonctions.h" +#endif + +# define MARGE 2 + +# define TEST_DE_STABILITE OUI_LU +# define SEUIL_DE_STABILITE 1.e+8 + +/*--------------------------------------------------------------------------------------------------*/ +/* On recoit: +- le numero de la colonne qui correspond a la variable sortante +- un pointeur sur la colonne A de la variable entrante +- la colonne A +*/ + +void LU_UpdateLuSpikePret( MATRICE * Matrice, int ColonneNativeConcernee, int * SuccesUpdate ) +{ +int Kp ; int i ; int il ; int ilMax; double X; int K2 ; int NbTermes ; int Colonne ; +int il1 ; int ic ; int icMax; int ic1 ; int icU; int ilDiag; int ilU ; int NbTermesLigneK2 ; +int j ; int iad; double PlusGrandTermeDeLaLigne ; int CapaciteDemandee ; double * ValeurElmSpike; +int Kp0C; int K1 ; int KpColonneInitial ; int KpLigneInitial ; int KpInitial ; +char * Marqueur ; double * W; int * OrdreUcolonne; int * InverseOrdreUcolonne; double * ElmDeU ; +int * IndicesLignesDuSpike ; int NbTermesNonNulsDuSpike ; int * CdebParColonneDeU ; +int * NbTermesParColonneDeU ; int * IndiceLigneParColonneDeU ; int * LdebParLigneDeU ; +int * NbTermesParLigneDeU ; int * StockageColonneVersLigneDeU; int * InverseOrdreColonne ; +int * StockageLigneVersColonneDeU; int * IndiceColonneDeU ; int * CapaciteParColonneDeU; +int * CapaciteParLigneDeU ; int * OrdreColonne ; double * ElmDeUParColonne ; +char LigneModifiee; int NbTrm; double SeuilPiv; double LambdaMax; + +Matrice->LuUpdateEnCours = OUI_LU; + +/* Trop de termes crees => on refuse de continuer, il est preferable de refactoriser */ +if ( Matrice->NbTermesCreesLuUpdate >= Matrice->MxTermesCreesLuUpdate ) { + # if VERBOSE_LU + printf("LU update refusee car trop de termes crees, LU update numero %d MxTermesCreesLuUpdate %d\n", + Matrice->NombreDeLuUpdates,Matrice->MxTermesCreesLuUpdate); + # endif + *SuccesUpdate = NON_LU; + return; +} + +if ( Matrice->NombreDeLuUpdates >= Matrice->NombreDeVecteursHAlloues ) { + # if VERBOSE_LU + printf("LU update refusee car cycle atteint \n"); + # endif + *SuccesUpdate = NON_LU; + return; +} + +/* Si on a cree trop de termes dans le triangle U sans pour autant avoir atteint le + nombre max d'Updates, on refactorise */ +if ( Matrice->IndexLibreDeUParColonne >= Matrice->LimiteUpdatePourRefactorisation ) { + # if VERBOSE_LU + printf("LU update refusee car le triangle U a trop de termes \n"); + printf(" nombre de termes dans le triangle U %d NombreDeLuUpdates %d\n",Matrice->IndexLibreDeUParColonne,Matrice->NombreDeLuUpdates); + # endif + *SuccesUpdate = NON_LU; + return; +} + +OrdreUcolonne = Matrice->OrdreUcolonne; +InverseOrdreUcolonne = Matrice->InverseOrdreUcolonne; + +/* Ordre d'elimination apres factorisation: KpColonneNativeConcernee */ +KpColonneInitial = Matrice->InverseOrdreColonne[ColonneNativeConcernee]; + +/* Sur ce KpColonneNativeConcernee il y a une matrice de permutation de U que l'on met a jour au moment des LU updates : + OrdreUcolonne -> permutation des colonnes OrdreUcolonne[i] = i en fin de factorisation +*/ + +K1 = InverseOrdreUcolonne[KpColonneInitial]; +KpLigneInitial = OrdreUcolonne[K1]; + +/* KpColonneInitial KpLigneInitial vont permettre d'utiliser le chainage de U */ + +*SuccesUpdate = OUI_LU; + +/* Il faut maintenant recalculer dans resolution, K2 comme etant le plus grand InverseOrdreUcolonne */ +IndicesLignesDuSpike = Matrice->IndicesLignesDuSpike; +ValeurElmSpike = Matrice->ValeurElmSpike; +NbTermesNonNulsDuSpike = Matrice->NbTermesNonNulsDuSpike; + +CdebParColonneDeU = Matrice->CdebParColonneDeU; +NbTermesParColonneDeU = Matrice->NbTermesParColonneDeU; +IndiceLigneParColonneDeU = Matrice->IndiceLigneParColonneDeU; +ElmDeUParColonne = Matrice->ElmDeUParColonne; +LdebParLigneDeU = Matrice->LdebParLigneDeU; +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +StockageColonneVersLigneDeU = Matrice->StockageColonneVersLigneDeU; +StockageLigneVersColonneDeU = Matrice->StockageLigneVersColonneDeU; +ElmDeU = Matrice->ElmDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; +CapaciteParColonneDeU = Matrice->CapaciteParColonneDeU; +CapaciteParLigneDeU = Matrice->CapaciteParLigneDeU; +OrdreColonne = Matrice->OrdreColonne; +InverseOrdreColonne = Matrice->InverseOrdreColonne; +Marqueur = Matrice->Marqueur; +W = Matrice->W; + +NbTrm = 0; +/* On supprime les termes de la colonne KpColonneNativeConcernee */ +ic = CdebParColonneDeU[KpColonneInitial]; +icMax = ic + NbTermesParColonneDeU[KpColonneInitial]; +NbTrm-= NbTermesParColonneDeU[KpColonneInitial]; /* Termes supprimes */ +while ( ic < icMax ) { + KpInitial = IndiceLigneParColonneDeU[ic]; + + il1 = LdebParLigneDeU[KpInitial] + NbTermesParLigneDeU[KpInitial] - 1; + il = StockageColonneVersLigneDeU[ic]; + + /* Pour retasser il suffit de mettre le dernier terme a la place de celui la et de decrementer le nombre de termes */ + ElmDeU [il] = ElmDeU[il1]; + IndiceColonneDeU[il] = IndiceColonneDeU[il1]; + /* */ + + i = StockageLigneVersColonneDeU[il1]; + StockageLigneVersColonneDeU[il] = i; + StockageColonneVersLigneDeU[i] = il; + + /* */ + NbTermesParLigneDeU[KpInitial]--; + /* */ + ic++; +} + +/* A ce stade, la colonne "ColonneConcernee" est vide */ +/* On place le spike dans la colonne KpColonneNativeConcernee du triangle U */ +/* On doit placer le spike dans la colonne et il faut qu'il y ait assez de place */ +if ( CapaciteParColonneDeU[KpColonneInitial] < NbTermesNonNulsDuSpike ) { + /* La place liberee ne suffit pas. On range la colonne a la fin et s'il n'y a pas assez de place on + fait une reallocation de U par colonne */ + CapaciteDemandee = NbTermesNonNulsDuSpike; + if ( Matrice->IndexLibreDeUParColonne + CapaciteDemandee > Matrice->DernierIndexLibreDeUParColonne ) { + CapaciteDemandee = NbTermesNonNulsDuSpike + MARGE; + LU_AugmenterLaTailleDuTriangleUParColonne( Matrice , CapaciteDemandee ); + IndiceLigneParColonneDeU = Matrice->IndiceLigneParColonneDeU; + ElmDeUParColonne = Matrice->ElmDeUParColonne; + StockageColonneVersLigneDeU = Matrice->StockageColonneVersLigneDeU; + } + /* On change la valeur de l'indice debut mais on ne recupere pas la place pour ne pas perdre de temps + a retasser tout le triangle */ + CdebParColonneDeU [KpColonneInitial] = Matrice->IndexLibreDeUParColonne; + CapaciteParColonneDeU[KpColonneInitial] = CapaciteDemandee; + Matrice->IndexLibreDeUParColonne+= CapaciteDemandee; +} +/* Nouvelle valeur du nombre de termes */ +NbTermesParColonneDeU[KpColonneInitial] = NbTermesNonNulsDuSpike; +NbTrm+= NbTermesNonNulsDuSpike; /* Nouveaux termes */ + +/* On place le spike dans la colonne KpColonneNativeConcernee du triangle U */ +K2 = -1; +ic = CdebParColonneDeU[KpColonneInitial]; +for ( i = 0 ; i < NbTermesNonNulsDuSpike ; i++ ) { + + KpInitial = IndicesLignesDuSpike[i]; + if ( InverseOrdreUcolonne[KpInitial] > K2 ) K2 = InverseOrdreUcolonne[KpInitial]; + + X = ValeurElmSpike[i]; + + /* On verifie s'il y a assez de place dans le chainage par ligne */ + NbTermes = NbTermesParLigneDeU[KpInitial]; + if ( CapaciteParLigneDeU[KpInitial] <= NbTermes ) { + /* On recopie la ligne a la fin avant de creer le terme */ + CapaciteDemandee = NbTermes + 1; + if ( Matrice->IndexLibreDeU + CapaciteDemandee > Matrice->DernierIndexLibreDeU ) { + CapaciteDemandee = NbTermes + MARGE; + LU_AugmenterLaTailleDuTriangleU( Matrice , CapaciteDemandee ); + ElmDeU = Matrice->ElmDeU; + IndiceColonneDeU = Matrice->IndiceColonneDeU; + StockageLigneVersColonneDeU = Matrice->StockageLigneVersColonneDeU; + } + CapaciteParLigneDeU[KpInitial] = CapaciteDemandee; + ilU = Matrice->IndexLibreDeU; + il = LdebParLigneDeU[KpInitial]; + ilMax = il + NbTermes; + LdebParLigneDeU[KpInitial] = ilU; + memcpy( &(ElmDeU[ilU]) , &(ElmDeU[il]) , NbTermes * sizeof( double ) ); + memcpy( &(IndiceColonneDeU[ilU]) , &(IndiceColonneDeU[il]) , NbTermes * sizeof( int ) ); + while ( il < ilMax ) { + iad = StockageLigneVersColonneDeU[il]; + StockageLigneVersColonneDeU[ilU] = iad; + StockageColonneVersLigneDeU[iad] = ilU; + il++; + ilU++; + } + Matrice->IndexLibreDeU+= CapaciteDemandee; + } + il = LdebParLigneDeU[KpInitial] + NbTermes; + ElmDeU [il] = X; + IndiceColonneDeU [il] = ColonneNativeConcernee; + /* */ + StockageLigneVersColonneDeU[il] = ic; + /* */ + NbTermesParLigneDeU[KpInitial]++; + /* */ + /* On met a jour le stockage par colonne */ + IndiceLigneParColonneDeU[ic] = KpInitial; + ElmDeUParColonne [ic] = X; + /* */ + StockageColonneVersLigneDeU[ic] = il; + /* */ + ic++; +} + +/* On permute les colonnes */ +Kp0C = OrdreUcolonne[K1]; +for ( Kp = K1 ; Kp < K2 ; Kp++ ) { + KpInitial = OrdreUcolonne[Kp + 1]; + OrdreUcolonne[Kp] = KpInitial; + InverseOrdreUcolonne[KpInitial] = Kp; +} +OrdreUcolonne[K2] = Kp0C; +InverseOrdreUcolonne[Kp0C] = K2; + +/*****************************************************************************************/ + +/* Elimination partielle: en sortie on a dans W la ligne qu'il faut mettre + en ligne K2 */ +LU_UpdateLuEliminations( Matrice, KpLigneInitial, K1, K2, &NbTermesLigneK2, SuccesUpdate, &LigneModifiee, &LambdaMax ); + +/* Mise a jour avec le nombre de termes qui resultent de l'echange des colonnes */ +Matrice->NbTermesCreesLuUpdate += NbTrm; + +if ( *SuccesUpdate == NON_LU ) return; + +/*****************************************************************************************/ + +/* A ce stade la, la ligne KpLigneInitial est stockee dans W */ + +if ( LigneModifiee == NON_LU && 0 ) { /* Inhibe car il se passe un truc bizarre sur certains jdd et */ + ilDiag = -1; /* pour l'instant je sais pas d'ou ca vient Ca se manifeste surtout */ + /* dans le branch and bound */ + il = LdebParLigneDeU[KpLigneInitial]; + ilMax = il + NbTermesParLigneDeU[KpLigneInitial]; + while ( il < ilMax ) { + Colonne = IndiceColonneDeU[il]; + W [Colonne] = 0.0; + Marqueur[Colonne] = 0; + if ( InverseOrdreColonne[Colonne] == KpLigneInitial ) { + ilDiag = il; + il++; + break; + } + il++; + } + while ( il < ilMax ) { + W [IndiceColonneDeU[il]] = 0.0; + Marqueur[IndiceColonneDeU[il]] = 0; + il++; + } + if ( ilDiag == -1 ) { + # if VERBOSE_LU + printf("LU_Update: Terme diagonal pas trouve\n"); + # endif + *SuccesUpdate = NON_LU; + return; + } + + /*SeuilPiv = 1.e-8;*/ /* <- 1.e-8 trop faible de plus le test ci-dessous doit etre NbTermesParColonneDeU[KpLigneInitial] == 1*/ + /*if ( NbTermesParLigneDeU[KpLigneInitial] == 1 && NbTermesParColonneDeU[KpLigneInitial] ) SeuilPiv = 1.e-9;*/ + + SeuilPiv = Matrice->ValeurDuPivotMin; + + if ( fabs( ElmDeU[ilDiag] ) < SeuilPiv /*Matrice->ValeurDuPivotMin*/ ) { + # if VERBOSE_LU + printf("Manque de precision dans la LU update numero %d\n",Matrice->NombreDeLuUpdates); + # endif + *SuccesUpdate = NON_LU; + return; + } + /* Placer le terme diagonale de KpLigneInitial */ + il = LdebParLigneDeU[KpLigneInitial]; + if ( ilDiag == il ) ElmDeU[il] = 1. / ElmDeU[il]; + else { + Colonne = IndiceColonneDeU[il]; + IndiceColonneDeU[il] = IndiceColonneDeU[ilDiag]; + IndiceColonneDeU[ilDiag] = Colonne; + X = ElmDeU[il]; + ElmDeU[il] = 1. / ElmDeU[ilDiag]; + ElmDeU[ilDiag] = X; + i = StockageLigneVersColonneDeU[ilDiag]; + j = StockageLigneVersColonneDeU[il]; + StockageLigneVersColonneDeU[il] = i; + StockageColonneVersLigneDeU[i] = il; + StockageLigneVersColonneDeU[ilDiag] = j; + StockageColonneVersLigneDeU[j] = ilDiag; + } + ic = CdebParColonneDeU[KpLigneInitial]; + ilDiag = StockageLigneVersColonneDeU[il]; + if ( ilDiag == ic ) ElmDeUParColonne[ic] = ElmDeU[il] /* 1. / ElmDeUParColonne[ic] */; + else { + X = ElmDeUParColonne[ic]; + j = IndiceLigneParColonneDeU[ic]; + ElmDeUParColonne [ic] = ElmDeU[il] /* 1. / ElmDeUParColonne[ilDiag] */; + IndiceLigneParColonneDeU[ic] = IndiceLigneParColonneDeU[ilDiag]; + ElmDeUParColonne [ilDiag] = X; + IndiceLigneParColonneDeU[ilDiag] = j; + i = StockageColonneVersLigneDeU[ilDiag]; + j = StockageColonneVersLigneDeU[ic]; + StockageColonneVersLigneDeU[ic] = i; + StockageLigneVersColonneDeU[i] = ic; + StockageColonneVersLigneDeU[ilDiag] = j; + StockageLigneVersColonneDeU[j] = ilDiag; + } + return; +} + +/* Cas ou la ligne est modifiee */ + +/* On enleve les termes de la ligne KpLigneInitial du stockage par colonne */ +il = LdebParLigneDeU[KpLigneInitial]; +ilMax = il + NbTermesParLigneDeU[KpLigneInitial]; +while ( il < ilMax ) { + + KpInitial = InverseOrdreColonne[IndiceColonneDeU[il]]; + + ic1 = CdebParColonneDeU[KpInitial] + NbTermesParColonneDeU[KpInitial] - 1; + ic = StockageLigneVersColonneDeU[il]; + + /* Pour retasser il suffit de mettre le dernier terme a la place de celui la et de decrementer le nombre de termes */ + IndiceLigneParColonneDeU[ic] = IndiceLigneParColonneDeU[ic1]; + ElmDeUParColonne [ic] = ElmDeUParColonne[ic1]; + /* */ + + i = StockageColonneVersLigneDeU[ic1]; + StockageColonneVersLigneDeU[ic] = i; + StockageLigneVersColonneDeU[i] = ic; + + /* */ + NbTermesParColonneDeU[KpInitial]--; + /* */ + il++; +} + +NbTermesParLigneDeU[KpLigneInitial] = 0; + +if ( CapaciteParLigneDeU[KpLigneInitial] < NbTermesLigneK2 ) { + /* La place liberee ne suffit pas. On range la colonne a la fin et s'il n'y a pas assez de place on + fait une reallocation de U par colonne */ + CapaciteDemandee = NbTermesLigneK2; + if ( Matrice->IndexLibreDeU + CapaciteDemandee > Matrice->DernierIndexLibreDeU ) { + CapaciteDemandee = NbTermesLigneK2 + MARGE; + LU_AugmenterLaTailleDuTriangleU( Matrice , CapaciteDemandee ); + ElmDeU = Matrice->ElmDeU; + IndiceColonneDeU = Matrice->IndiceColonneDeU; + StockageLigneVersColonneDeU = Matrice->StockageLigneVersColonneDeU; + } + /* On change la valeur de l'indice debut mais on ne recupere pas la place pour ne pas perdre de temps + a retasser tout le triangle */ + LdebParLigneDeU [KpLigneInitial] = Matrice->IndexLibreDeU; + CapaciteParLigneDeU[KpLigneInitial] = CapaciteDemandee; + Matrice->IndexLibreDeU+= CapaciteDemandee; +} + +/* On recopie les termes non nuls de la ligne W dans la ligne KpLigneInitial du triangle U et on met a jour le stockage par colonne */ +/* Attention a mettre le terme diagonal en debut de ligne KpLigneInitial */ +/* On regarde egalement si la condition de stabilite est verifiee sur la ligne KpLigneInitial */ +il = LdebParLigneDeU[KpLigneInitial]; +PlusGrandTermeDeLaLigne = -1; + +/* Index du terme diagonal */ +ilDiag = -1; +KpInitial = OrdreUcolonne[K2]; +if ( Marqueur[OrdreColonne[KpInitial]] == 1 ) ilDiag = il; + +for ( Kp = K2 ; Kp < Matrice->Rang ; Kp++ ) { + KpInitial = OrdreUcolonne[Kp]; + + Colonne = OrdreColonne[KpInitial]; + + if ( Marqueur[Colonne] == 1 ) { + X = W[Colonne]; + if ( fabs( X ) > PlusGrandTermeDeLaLigne ) PlusGrandTermeDeLaLigne = fabs( X ); + + ElmDeU [il] = X; + IndiceColonneDeU[il] = Colonne; + NbTermesParLigneDeU[KpLigneInitial]++; + + /* On verifie s'il y a assez de place dans le chainage par colonne */ + NbTermes = NbTermesParColonneDeU[KpInitial]; + if ( CapaciteParColonneDeU[KpInitial] <= NbTermes ) { + /* On recopie la ligne a la fin avant de creer le terme */ + CapaciteDemandee = NbTermes + 1; + if ( Matrice->IndexLibreDeUParColonne + CapaciteDemandee > Matrice->DernierIndexLibreDeUParColonne ) { + CapaciteDemandee = NbTermes + MARGE; + LU_AugmenterLaTailleDuTriangleUParColonne( Matrice , CapaciteDemandee ); + IndiceLigneParColonneDeU = Matrice->IndiceLigneParColonneDeU; + ElmDeUParColonne = Matrice->ElmDeUParColonne; + StockageColonneVersLigneDeU = Matrice->StockageColonneVersLigneDeU; + } + CapaciteParColonneDeU[KpInitial] = CapaciteDemandee; + icU = Matrice->IndexLibreDeUParColonne; + ic = CdebParColonneDeU[KpInitial]; + icMax = ic + NbTermes; + CdebParColonneDeU[KpInitial] = icU; + memcpy( &(IndiceLigneParColonneDeU[icU]), &(IndiceLigneParColonneDeU[ic]), NbTermes * sizeof( int ) ); + memcpy( &(ElmDeUParColonne[icU]) , &(ElmDeUParColonne[ic]) , NbTermes * sizeof( double ) ); + + while ( ic < icMax ) { + iad = StockageColonneVersLigneDeU[ic]; + StockageColonneVersLigneDeU[icU] = iad; + StockageLigneVersColonneDeU[iad] = icU; + ic++; + icU++; + } + + Matrice->IndexLibreDeUParColonne+= CapaciteDemandee; + } + ic = CdebParColonneDeU[KpInitial] + NbTermes; + IndiceLigneParColonneDeU[ic] = KpLigneInitial; + ElmDeUParColonne[ic] = X; + NbTermesParColonneDeU[KpInitial]++; + /* */ + StockageLigneVersColonneDeU[il] = ic; + StockageColonneVersLigneDeU[ic] = il; + /* */ + W [Colonne] = 0.0; + Marqueur[Colonne] = 0; + /* */ + il++; + } +} + +if ( ilDiag < 0 ) { + # if VERBOSE_LU + printf("LU_UpdateLu: pas de terme diagonal pour la colonne K2\n"); + # endif + *SuccesUpdate = NON_LU; + return; +} + +il = LdebParLigneDeU[KpLigneInitial]; +if ( ilDiag != il ) { + /* Normalement on ne passe jamais la dedans */ + Colonne = IndiceColonneDeU[il]; + IndiceColonneDeU[il] = IndiceColonneDeU[ilDiag]; + IndiceColonneDeU[ilDiag] = Colonne; + X = ElmDeU[il]; + ElmDeU[il] = ElmDeU[ilDiag]; + ElmDeU[ilDiag] = X; + + i = StockageLigneVersColonneDeU[ilDiag]; + j = StockageLigneVersColonneDeU[il]; + + StockageLigneVersColonneDeU[il] = i; + StockageColonneVersLigneDeU[i] = il; + + StockageLigneVersColonneDeU[ilDiag] = j; + StockageColonneVersLigneDeU[j] = ilDiag; +} +/* */ + +/*SeuilPiv = 1.e-8;*/ /* <- 1.e-8 trop faible de plus le test ci-dessous doit etre NbTermesParColonneDeU[KpLigneInitial] == 1*/ +/*if ( NbTermesParLigneDeU[KpLigneInitial] == 1 && NbTermesParColonneDeU[KpLigneInitial] ) SeuilPiv = 1.e-9;*/ + +SeuilPiv = Matrice->ValeurDuPivotMin; + +if ( fabs( ElmDeU[il] ) < SeuilPiv /*Matrice->ValeurDuPivotMin*/ ) { + # if VERBOSE_LU + printf("Manque de precision dans la LU update numero %d\n",Matrice->NombreDeLuUpdates); + printf(" SeuilPiv %e PlusGrandTermeDeLaLigne %e Valeur Diagonale %e 0.01 * PlusGrandTermeDeLaLigne %e\n", + SeuilPiv,PlusGrandTermeDeLaLigne,fabs( Matrice->ElmDeU[il] ), + 0.01*PlusGrandTermeDeLaLigne); + # endif + *SuccesUpdate = NON_LU; + return; +} + +/* Test de stabilite */ +# if TEST_DE_STABILITE == OUI_LU + /* ElmDeU[il] est le pivot */ + if ( LambdaMax * PlusGrandTermeDeLaLigne / fabs( ElmDeU[il] ) > SEUIL_DE_STABILITE ) { + # if VERBOSE_LU + printf("Manque de precision dans la LU update numero %d:\n",Matrice->NombreDeLuUpdates); + printf("LambdaMax %e PlusGrandTermeDeLaLigne %e Valeur Diagonale %e LambdaMax * PlusGrandTermeDeLaLigne / Valeur Diagonale ) = %e > %e\n", + LambdaMax,PlusGrandTermeDeLaLigne,fabs( Matrice->ElmDeU[il] ),LambdaMax * PlusGrandTermeDeLaLigne / fabs( ElmDeU[il] ),SEUIL_DE_STABILITE); + # endif + *SuccesUpdate = NON_LU; + return; + } +# endif + +ElmDeU[il] = 1. / ElmDeU[il]; + +/* */ +/* Pour le chainage par colonne, le terme diagonal vient d'etre place a la fin. On le place au debut */ +ic = CdebParColonneDeU[KpLigneInitial]; +ilDiag = ic + NbTermesParColonneDeU[KpLigneInitial] - 1; + +if ( ic == ilDiag ) ElmDeUParColonne [ic] = 1. / ElmDeUParColonne[ic]; +else { + X = ElmDeUParColonne[ic]; + j = IndiceLigneParColonneDeU[ic]; + + ElmDeUParColonne [ic] = 1. / ElmDeUParColonne[ilDiag]; + IndiceLigneParColonneDeU[ic] = IndiceLigneParColonneDeU[ilDiag]; + + ElmDeUParColonne [ilDiag] = X; + IndiceLigneParColonneDeU[ilDiag] = j; + + i = StockageColonneVersLigneDeU[ilDiag]; + j = StockageColonneVersLigneDeU[ic]; + + StockageColonneVersLigneDeU[ic] = i; + StockageLigneVersColonneDeU[i] = ic; + + StockageColonneVersLigneDeU[ilDiag] = j; + StockageLigneVersColonneDeU[j] = ilDiag; +} + +if ( LigneModifiee == OUI_LU ) Matrice->NombreDeLuUpdates++; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* K1 est la ligne (dans la numerotation Kp) dont il faut annuler les termes */ +/* K2 est la ligne (dans la numerotation Kp) du dernier terme non nul du spike */ +void LU_UpdateLuEliminations( MATRICE * Matrice, int KpLigneInitial, int K1, int K2, + int * NombreDeTermes, int * SuccesUpdate, char * LigneModifiee, double * LbdMax ) +{ +int il; int ilMax; int Colonne; int Kp; double Lambda; int NbTermes; int * NbTermesParLigneDeU; int * LdebParLigneDeU; +int * IndiceColonneDeU; char * Marqueur; int * HDeb; int * HLigne; int * HNbTerm; int * HIndiceColonne; double * ElmDeU; +double * W; double * HValeur; int * OrdreUcolonne; int KpInitial; int IndexHLibre; int NombreDElementsHAlloues; +int NombreDeLuUpdates; int NbTermesCreesLuUpdate; char Flag; double LambdaMax; + +/* */ + +*LbdMax = 1; +LambdaMax = -1; + +OrdreUcolonne = Matrice->OrdreUcolonne; + +NbTermesParLigneDeU = Matrice->NbTermesParLigneDeU; +LdebParLigneDeU = Matrice->LdebParLigneDeU; +IndiceColonneDeU = Matrice->IndiceColonneDeU; +ElmDeU = Matrice->ElmDeU; + +W = Matrice->W; +Marqueur = Matrice->Marqueur; + +NombreDeLuUpdates = Matrice->NombreDeLuUpdates; +NbTermesCreesLuUpdate = Matrice->NbTermesCreesLuUpdate; + +HDeb = Matrice->HDeb; +HLigne = Matrice->HLigne; +HNbTerm = Matrice->HNbTerm; +HValeur = Matrice->HValeur; +HIndiceColonne = Matrice->HIndiceColonne; +IndexHLibre = Matrice->IndexHLibre; +NombreDElementsHAlloues = Matrice->NombreDElementsHAlloues; + +NbTermes = NbTermesParLigneDeU[KpLigneInitial]; +il = LdebParLigneDeU[KpLigneInitial]; +ilMax = il + NbTermes; +while ( il < ilMax ) { + Colonne = IndiceColonneDeU[il]; + /* */ + W [Colonne] = ElmDeU[il]; + Marqueur[Colonne] = 1; + /* */ + il++; +} + +/* */ +HDeb [NombreDeLuUpdates] = IndexHLibre; +HLigne [NombreDeLuUpdates] = KpLigneInitial; +HNbTerm[NombreDeLuUpdates] = 0; +/* */ + +/* On annule la ligne */ + +Flag = NON_LU; + +for ( Kp = K1 ; Kp < K2 ; Kp++ ) { + /* Le premier terme de la ligne KpInitial est le terme "diagonal" */ + KpInitial = OrdreUcolonne[Kp]; + il = LdebParLigneDeU[KpInitial]; + Colonne = IndiceColonneDeU[il]; + /* S'il n'y a pas de terme dans la ligne K1, il n'y a rien a faire */ + if ( Marqueur[Colonne] == 0 ) continue; + + Flag = OUI_LU; + ilMax = il + NbTermesParLigneDeU[KpInitial]; + /* */ + Lambda = -W[Colonne] * ElmDeU[il]; /* Car le terme diagonal est deja inverse */ + + # if TEST_DE_STABILITE == OUI_LU + if ( fabs( Lambda ) > LambdaMax ) LambdaMax = fabs( Lambda ); + # endif + + W [Colonne] = 0.; + Marqueur[Colonne] = 0; + NbTermes--; + + NbTermesCreesLuUpdate--; /* Car on supprime un terme dans la triangualire superieure */ + + /*if ( Lambda == 0.0 ) continue;*/ + + if ( fabs( Lambda ) < VALEUR_NULLE_DE_LAMBDA_POUR_LU_UPDATE ) continue; + + /* */ + il++; + /* */ + HValeur [IndexHLibre] = -Lambda; + HIndiceColonne[IndexHLibre] = KpInitial; + HNbTerm[NombreDeLuUpdates]++; + IndexHLibre++; + if ( IndexHLibre >= NombreDElementsHAlloues ) { + /*printf("pas assez delements H alloues \n");*/ + Matrice->IndexHLibre = IndexHLibre; + Matrice->NbTermesCreesLuUpdate = NbTermesCreesLuUpdate; + *SuccesUpdate = NON_LU; + *LigneModifiee = Flag; + return; + } + /* */ + while ( il < ilMax ) { + Colonne = IndiceColonneDeU[il]; + W[Colonne] = W[Colonne] + ( Lambda * ElmDeU[il] ); + if ( Marqueur[Colonne] != 1 ) { + NbTermesCreesLuUpdate++; + NbTermes++; + } + Marqueur[Colonne] = 1; + il++; + } +} +*LigneModifiee = Flag; +*NombreDeTermes = NbTermes; +Matrice->IndexHLibre = IndexHLibre; +Matrice->NbTermesCreesLuUpdate = NbTermesCreesLuUpdate; + +if ( LambdaMax > 0 ) *LbdMax = LambdaMax; + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/lu/memstats.c b/src/ext/Sirius_Solver/simplexe/lu/memstats.c new file mode 100644 index 0000000000..1d065ece88 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/memstats.c @@ -0,0 +1,320 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ + +/* which implementation */ +#if defined(__TOS_WIN__) || defined(__WIN32__) || defined(_WIN64) || defined(_WIN32) +# define MEMSTAT_IMPL_WINDOWS +#else +# if defined(__linux) || defined(linux) || defined(__linux__) +# define MEMSTAT_IMPL_LINUX +# else +# define MEMSTAT_IMPL_FALLBACK +# warning Memstat: Implementation manquante pour cette platform +# endif +#endif + +/* 32 or 64 bits ? */ +#if defined(__IA64__) || defined(_IA64) || defined(__amd64__) || defined(__x86_64__) || defined(_M_IA64) || defined(_WIN64) +# define OS_64 +#else +# define OS_32 +#endif + + +#ifdef MEMSTAT_IMPL_LINUX +# include +# include +# include +#endif + +#ifdef MEMSTAT_IMPL_WINDOWS +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN 1 +# endif +# ifndef _WIN32_WINNT /* currently mingw does not define, mingw64 does */ +# define _WIN32_WINNT 0x0500 /* for MEMORYSTATUSEX */ +# endif +# include +# include +# include +# define __PRETTY_FUNCTION__ __FUNCDNAME__ +#endif + + +// Pour eviter tout conflit, il faut que ces includes restent apres +// les precedents defines +#include "memstats.h" +#include +#include + +/*! +** \brief Valeur par defaut pour la quantite total de memoire +** +** Cette constante est utilisee dans le cas ou il est impossible +** d'obtenir des informations sur la memoire. +*/ +# define MEMORY_STATS_DEFAULT_TOTAL_MEMORY 1024 * 1024 * 1024 /* 1Go */ + +/*! +** \brief Valeur par defaut pour la quantite de memoire disponible +** +** Cette constante est utilisee dans le cas ou il est impossible +** d'obtenir des informations sur la memoire. +*/ +# define MEMORY_STATS_DEFAULT_FREE_MEMORY 1024 * 1024 * 1024 /* 1Go */ + + + + + + +#ifdef MEMSTAT_IMPL_FALLBACK + +int MemoireStatistiques(MemoireInfo* info) +{ + /* assert */ + assert(NULL != info && "Meminfo: The given pointer must not be null"); + /* valeurs par default, implementation manquante */ + info->total = MEMORY_STATS_DEFAULT_TOTAL_MEMORY; + info->libre = MEMORY_STATS_DEFAULT_FREE_MEMORY; +} + +size_t MemoireDisponible() +{ + return MEMORY_STATS_DEFAULT_FREE_MEMORY; +} + +size_t MemoireTotal() +{ + return MEMORY_STATS_DEFAULT_TOTAL_MEMORY; +} + +# endif /* Fallback */ + + + + + + +#ifdef MEMSTAT_IMPL_LINUX + +/*! +** \brief Lit tous les caracters jusqu'au retour chariot ou fin de fichier +*/ +static int fgetline(FILE* fp, char* s, int maxlen) +{ + int i = 0; + char c; + + while ((c = fgetc(fp)) != EOF) + { + if (c == '\n') + { + *s = '\0'; + return i; + } + if (i >= maxlen) + return i; + + *s++ = c; + ++i; + } + + return (!i) ? EOF : i; +} + + +static size_t readvalue(char* line) +{ + /* + ** Exemple de contenu de /proc/meminfo : + ** + ** MemTotal: 1929228 kB + ** MemFree: 12732 kB + ** Buffers: 72176 kB + ** Cached: 1076572 kB + ** SwapCached: 151412 kB + ** Active: 1491184 kB + ** Inactive: 190832 kB + ** HighTotal: 0 kB + ** HighFree: 0 kB + ** LowTotal: 1929228 kB + ** LowFree: 12732 kB + ** SwapTotal: 2096472 kB + ** SwapFree: 1732964 kB + ** Dirty: 736 kB + ** Writeback: 0 kB + ** AnonPages: 512004 kB + ** Mapped: 702148 kB + ** Slab: 154320 kB + ** PageTables: 34712 kB + ** NFS_Unstable: 0 kB + ** Bounce: 0 kB + ** CommitLimit: 3061084 kB + ** Committed_AS: 1357596 kB + ** VmallocTotal: 34359738367 kB + ** VmallocUsed: 263492 kB + ** VmallocChunk: 34359474679 kB + ** HugePages_Total: 0 + ** HugePages_Free: 0 + ** HugePages_Rsvd: 0 + ** Hugepagesize: 2048 kB + */ + + const char* first; + + /* Suppression de tous les espaces du debut */ + while (*line == ' ' && *line != '\0') + ++line; + first = line; + + /* On recherche la fin du nombre */ + while (*line != ' ' && *line != '\0') + ++line; + /* On marque la fin du nombre comme etant une fin de chaine pour + ** conversion */ + *line = '\0'; + + # ifdef OS_32 + return (size_t) atol(first) * 1024u; + # else + return (size_t) atoll(first) * 1024u; + # endif +} + + + +int MemoireStatistiques(MemoireInfo* info) +{ + char line[90]; + size_t tailleLibre = 0; + size_t tailleCache = 0; + size_t tailleBuffer = 0; + int remains = 8; + FILE *fd; + + /* La seule facon valide de recuperer ces informations est de lire dans + ** /proc/meminfo. + ** La routine sysconf (3) renvoie effectivement la memoire libre et la + ** memoire libre et la memoire totale mais ne prend pas en compte la + ** memoire consommee par le cache. + */ + if ((fd = fopen("/proc/meminfo", "r"))) + { + info->total = 0; + while (EOF != fgetline(fd, line, (int) sizeof(line))) + { + if (!strncmp("MemTotal:", line, (size_t) 9)) + { + info->total = readvalue(line + 10); + if (!(remains >> 1)) + break; + } + if (!strncmp("MemFree:", line, (size_t) 8)) + { + tailleLibre = readvalue(line + 9); + if (!(remains >> 1)) + break; + } + if (!strncmp("Cached:", line, (size_t) 7)) + { + tailleCache = readvalue(line + 8); + if (!(remains >> 1)) + break; + } + if (!strncmp("Buffers:", line, (size_t) 8)) + { + tailleCache = readvalue(line + 9); + if (!(remains >> 1)) + break; + } + } + + info->libre = tailleLibre + tailleCache + tailleBuffer; + + fclose(fd); + return 0; + } + + /* Erreur, utilisation des valeurs par defaut */ + info->total = MEMORY_STATS_DEFAULT_TOTAL_MEMORY; + info->libre = MEMORY_STATS_DEFAULT_FREE_MEMORY; + return 1; +} + +size_t MemoireDisponible() +{ + MemoireInfo info; + MemoireStatistiques(&info); + return info.libre; +} + +size_t MemoireTotale() +{ + /* Appel system direct, plus rapide que de parser /proc/meminfo */ + struct sysinfo s; + return (!sysinfo(&s)) ? (s.mem_unit * s.totalram) : MEMORY_STATS_DEFAULT_TOTAL_MEMORY; +} + +# endif /* Linux */ + + + + +#ifdef MEMSTAT_IMPL_WINDOWS + +int MemoireStatistiques(MemoireInfo* info) +{ + // Getting informations from the system + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + + if (GlobalMemoryStatusEx(&statex)) + { + info->total = (size_t) statex.ullTotalPhys; + info->libre = (size_t) statex.ullAvailPhys; + return 0; + } + + /* Erreur, utilisation des valeurs par defaut */ + info->total = (size_t) MEMORY_STATS_DEFAULT_TOTAL_MEMORY; + info->libre = (size_t) MEMORY_STATS_DEFAULT_FREE_MEMORY; + return 1; +} + +size_t MemoireDisponible() +{ + // Getting informations from the system + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + return (GlobalMemoryStatusEx(&statex)) + ? (size_t) statex.ullAvailPhys + : (size_t) MEMORY_STATS_DEFAULT_FREE_MEMORY; +} + +size_t MemoireTotale() +{ + // Getting informations from the system + MEMORYSTATUSEX statex; + statex.dwLength = sizeof(statex); + return (GlobalMemoryStatusEx(&statex)) + ? (size_t) statex.ullTotalPhys + : (size_t) MEMORY_STATS_DEFAULT_TOTAL_MEMORY; +} + +#endif /* Windows */ + diff --git a/src/ext/Sirius_Solver/simplexe/lu/memstats.h b/src/ext/Sirius_Solver/simplexe/lu/memstats.h new file mode 100644 index 0000000000..f595129b41 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/lu/memstats.h @@ -0,0 +1,77 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +#ifndef __MEMSTATS_H__ +# define __MEMSTATS_H__ + +# include /* for size_t */ + + + + +/*! +** \brief Structure contenant des statistiques sur la memoire a un instant donne +*/ +typedef struct +{ + /*! Quantite de Memoire totale de la machine (en octets) */ + size_t total; + /*! Quantite de Memoire disponible (en octets) */ + size_t libre; + +} MemoireInfo; + + + + +# ifdef __cplusplus +extern "C" +{ +# endif + + +/*! +** \brief Recupere toutes les informations sur la memoire +** +** Dans tous les cas, la structure donnee est initialisee (avec des +** valeurs par defaut en cas d'erreur). +** +** \param[out] info Structure ou seront stockees les informations +** recoltees +** \return 0 en cas de reussite, une valeur quelconque en cas d'erreur +*/ +int MemoireStatistiques(MemoireInfo* info); + + + +/*! +** \brief Donne la quantite de memoire actuellement disponible +** \return Une taille en octets +*/ +size_t MemoireDisponible( void ); + +/*! +** \brief Donne la quantite de Memoire totale de la machine +** \return Une taille en octets +*/ +size_t MemoireTotale( void ); + + +# ifdef __cplusplus +} +# endif + +#endif /* __MEMSTATS_H__ */ diff --git a/src/ext/Sirius_Solver/simplexe/spx_ajouter_coupes.c b/src/ext/Sirius_Solver/simplexe/spx_ajouter_coupes.c new file mode 100644 index 0000000000..30a1cd4cd5 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_ajouter_coupes.c @@ -0,0 +1,297 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + FONCTION: Modification du probleme dans un contexte de branch and + cut. On ajoute les coupes (ce sont des contraintes d'inegalite) + La variable d'ecart est hors base (i.e. contraintes saturees) + ou en base. + En ce qui concerne le scaling, on ne fait pas participer la + coupe au scaling. En consequence ScaleB vaut 1 pour toutes + ces contraintes. + Remarque: a ce stade le probleme initial (avant coupes) est + deja sous la forme standard. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# define TERME_NUL 0.0 + +/*----------------------------------------------------------------------------*/ + +void SPX_AjouterLesCoupes( + PROBLEME_SPX * Spx, + /* La matrice des contraintes rangee par lignes */ + int NbContr_E, /* Nombre de contraintes (coupes a ajouter) */ + char * PositionDeLaVariableDEcart, /* HORS_BASE_SUR_BORNE_INF si la contrainte + est saturee, EN_BASE dans le cas contraire */ + int * Mdeb_E, /* Indice debut (dans A) des lignes de la matrice des + contraintes */ + int * NbTerm_E, /* Nombre de termes de la ligne */ + int * Indcol_E, /* Indice colonne des termes de chaque ligne. + Attention, les termes de la ligne doivent etre + ranges dans l'ordre croissant des indices de + colonnes */ + double * A_E, /* Les termes de la matrice de contraintes contenus + dans un grand vecteur */ + /* Le second membre */ + double * B_E /* Le second membre */ + ) +{ +int Cnt_E ; int il; int il_E ; int ilMax_E; int ilMax; int Var_E; +int Var; int VarSimplexe; double S; int NombreDeContraintes; +int NombreDeVariables; int * Mdeb; int * NbTerm; int * CorrespondanceVarEntreeVarSimplexe; +int * Indcol; char * TypeDeVariable; int * CorrespondanceVarSimplexeVarEntree; +int * VariableEnBaseDeLaContrainte; char * PositionDeLaVariable; int * ContrainteDeLaVariableEnBase; +char * OrigineDeLaVariable; int * CntVarEcartOuArtif; double * A; double * ScaleX; +double * ScaleB; double * B; double * BAvantTranslationEtApresScaling; double * XminEntree; +double * XmaxEntree; double * X; double * C; double * Xmin; double * Xmax; +double * SeuilDeViolationDeBorne; double * Csv; int * CNbTermesDeCoupes; +char * StatutBorneSupCourante; char * StatutBorneSupAuxiliaire; +int * CorrespondanceCntSimplexeCntEntree; int NombreDeContraintesDuProblemeSansCoupes; + +/* +printf("SPX_AjouterLesCoupes \n"); fflush(stdout); +*/ + +if ( Spx->NombreDeVariables >= Spx->NombreDeVariablesAllouees ) SPX_AugmenterLeNombreDeVariables( Spx ); +if ( Spx->NombreDeContraintes >= Spx->NombreDeContraintesAllouees ) SPX_AugmenterLeNombreDeContraintes( Spx ); + +NombreDeContraintesDuProblemeSansCoupes = Spx->NombreDeContraintesDuProblemeSansCoupes; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +CorrespondanceCntSimplexeCntEntree = Spx->CorrespondanceCntSimplexeCntEntree; +CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; +A = Spx->A; +Indcol = Spx->Indcol; +ScaleX = Spx->ScaleX; +ScaleB = Spx->ScaleB; +B = Spx->B; +BAvantTranslationEtApresScaling = Spx->BAvantTranslationEtApresScaling; +TypeDeVariable = Spx->TypeDeVariable; +XminEntree = Spx->XminEntree; +XmaxEntree = Spx->XmaxEntree; +X = Spx->X; +C = Spx->C; +Xmin = Spx->Xmin; +Xmax = Spx->Xmax; +SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; +CorrespondanceVarSimplexeVarEntree = Spx->CorrespondanceVarSimplexeVarEntree; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +PositionDeLaVariable = Spx->PositionDeLaVariable; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +Csv = Spx->Csv; +OrigineDeLaVariable = Spx->OrigineDeLaVariable; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +StatutBorneSupAuxiliaire = Spx->StatutBorneSupAuxiliaire; + +CntVarEcartOuArtif = Spx->CntVarEcartOuArtif; + +NombreDeContraintes = Spx->NombreDeContraintes; +NombreDeVariables = Spx->NombreDeVariables; + +/* Seules nous interessent les variables natives car pour les autres on sait que ça vaut 1 */ +CNbTermesDeCoupes = Spx->CNbTermesDeCoupes; +memset ( (char *) CNbTermesDeCoupes, 0 , Spx->NombreDeVariables * sizeof( int ) ); + +for ( Cnt_E = 0 ; Cnt_E < NbContr_E ; Cnt_E++ ) { + + if ( NbTerm_E[Cnt_E] <= 0 ) continue; + + il = Mdeb[NombreDeContraintes - 1] + NbTerm[NombreDeContraintes - 1]; + if ( il >= Spx->NbTermesAlloues ) { + Spx->NombreDeContraintes = NombreDeContraintes; + Spx->NombreDeVariables = NombreDeVariables; + SPX_AugmenterLaTailleDeLaMatriceDesContraintes( Spx ); + NombreDeContraintes = Spx->NombreDeContraintes; + NombreDeVariables = Spx->NombreDeVariables; + A = Spx->A; + Indcol = Spx->Indcol; + } + + Mdeb [NombreDeContraintes] = il; + NbTerm[NombreDeContraintes] = 0; + + il_E = Mdeb_E[Cnt_E]; + ilMax_E = il_E + NbTerm_E[Cnt_E]; + while ( il_E < ilMax_E) { + Var_E = Indcol_E[il_E]; + /* Ces variables ont toutes une correspondance avec les variables simplexe (sauf bug). + Au pire, si ce sont des variables qui on ete instanciees leurs bornes sont identiques + mais elles ne sont pas de type VARIABLE_FIXE */ + VarSimplexe = CorrespondanceVarEntreeVarSimplexe[Var_E]; + Indcol[il] = VarSimplexe; + A [il] = A_E[il_E]; + /* Scale en ScaleX de la contrainte */ + A[il] *= ScaleX[VarSimplexe]; + + if ( fabs( A[il] ) > TERME_NUL ) { + /* On ne prend en compte le terme que s'il n'est pas "infiniment petit" */ + + NbTerm[NombreDeContraintes]++; + CNbTermesDeCoupes[VarSimplexe]++; + + il++; + if ( il >= Spx->NbTermesAlloues ) { + Spx->NombreDeContraintes = NombreDeContraintes; + Spx->NombreDeVariables = NombreDeVariables; + SPX_AugmenterLaTailleDeLaMatriceDesContraintes( Spx ); + NombreDeContraintes = Spx->NombreDeContraintes; + NombreDeVariables = Spx->NombreDeVariables; + A = Spx->A; + Indcol = Spx->Indcol; + } + } + + il_E++; + } + + ScaleB[NombreDeContraintes] = 1.; + B[NombreDeContraintes] = B_E[Cnt_E] * ScaleB[NombreDeContraintes]; + + BAvantTranslationEtApresScaling[NombreDeContraintes] = B[NombreDeContraintes]; + + /* Pour le second membre il faut tenir compte de la translation des bornes aussi */ + il = Mdeb[NombreDeContraintes]; + ilMax = il + NbTerm[NombreDeContraintes]; + S = 0.; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( TypeDeVariable[Var] != NON_BORNEE ) { + S+= A[il] * XminEntree[Var] / ScaleX[Var]; + } + il++; + } + Spx->B[NombreDeContraintes]-=S; + + CorrespondanceCntSimplexeCntEntree[NombreDeContraintes] = NombreDeContraintesDuProblemeSansCoupes + Cnt_E; + + /* On ajoute la variable d'ecart dans la contrainte */ + /* Creation de la variable d'ecart */ + + XminEntree [NombreDeVariables] = 0.; + XmaxEntree [NombreDeVariables] = LINFINI_POUR_X; + X [NombreDeVariables] = 0.; + C [NombreDeVariables] = 0.; + Xmin [NombreDeVariables] = 0.; + Xmax [NombreDeVariables] = LINFINI_POUR_X; + TypeDeVariable[NombreDeVariables] = BORNEE_INFERIEUREMENT; + + SeuilDeViolationDeBorne[NombreDeVariables] = SEUIL_DE_VIOLATION_DE_BORNE_VARIABLES_ECART_COUPES; + + Spx->SeuilDAmissibiliteDuale1[NombreDeVariables] = SEUIL_ADMISSIBILITE_DUALE_1; + Spx->SeuilDAmissibiliteDuale2[NombreDeVariables] = SEUIL_ADMISSIBILITE_DUALE_2; + + CorrespondanceVarSimplexeVarEntree[NombreDeVariables] = -1; + + VariableEnBaseDeLaContrainte[NombreDeContraintes] = -1; + if ( PositionDeLaVariableDEcart[Cnt_E] == EN_BASE ) { + PositionDeLaVariable [NombreDeVariables] = EN_BASE_LIBRE; + ContrainteDeLaVariableEnBase[NombreDeVariables] = NombreDeContraintes; + VariableEnBaseDeLaContrainte[NombreDeContraintes] = NombreDeVariables; + } + else if ( PositionDeLaVariableDEcart[Cnt_E] == HORS_BASE_SUR_BORNE_INF ) { + PositionDeLaVariable[NombreDeVariables] = HORS_BASE_SUR_BORNE_INF; + } + else { + printf("Bug dans le sous programme SPX_AjouterLesCoupes. Arret d'urgence\n"); + exit(0); + } + /* On la met dans l'equation de la contrainte */ + il = Mdeb[NombreDeContraintes] + NbTerm[NombreDeContraintes]; + + if ( il >= Spx->NbTermesAlloues ) { + Spx->NombreDeContraintes = NombreDeContraintes; + Spx->NombreDeVariables = NombreDeVariables; + SPX_AugmenterLaTailleDeLaMatriceDesContraintes( Spx ); + NombreDeContraintes = Spx->NombreDeContraintes; + NombreDeVariables = Spx->NombreDeVariables; + A = Spx->A; + Indcol = Spx->Indcol; + } + + NbTerm[NombreDeContraintes]++; + Indcol[il] = NombreDeVariables; + A [il] = 1.; + + Csv [NombreDeVariables] = 0.; + ScaleX [NombreDeVariables] = 1.; + OrigineDeLaVariable [NombreDeVariables] = ECART; + StatutBorneSupCourante [NombreDeVariables] = BORNE_NATIVE; + StatutBorneSupAuxiliaire[NombreDeVariables] = BORNE_AUXILIAIRE_INVALIDE; + + CntVarEcartOuArtif [NombreDeVariables] = NombreDeContraintes; + + /* Incrementation du nombre de variables */ + NombreDeVariables++; + if ( NombreDeVariables >= Spx->NombreDeVariablesAllouees ) { + Spx->NombreDeContraintes = NombreDeContraintes; + Spx->NombreDeVariables = NombreDeVariables; + SPX_AugmenterLeNombreDeVariables( Spx ); + NombreDeContraintes = Spx->NombreDeContraintes; + NombreDeVariables = Spx->NombreDeVariables; + C = Spx->C; + Csv = Spx->Csv; + X = Spx->X; + Xmin = Spx->Xmin; + Xmax = Spx->Xmax; + TypeDeVariable = Spx->TypeDeVariable; + OrigineDeLaVariable = Spx->OrigineDeLaVariable; + StatutBorneSupCourante = Spx->StatutBorneSupCourante; + StatutBorneSupAuxiliaire = Spx->StatutBorneSupAuxiliaire; + CntVarEcartOuArtif = Spx->CntVarEcartOuArtif; + CNbTermesDeCoupes = Spx->CNbTermesDeCoupes; + XminEntree = Spx->XminEntree; + XmaxEntree = Spx->XmaxEntree; + SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; + ScaleX = Spx->ScaleX ; + CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; + CorrespondanceVarSimplexeVarEntree = Spx->CorrespondanceVarSimplexeVarEntree; + PositionDeLaVariable = Spx->PositionDeLaVariable; + ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; + } + + /* Incrementation du nombre de contraintes */ + NombreDeContraintes++; + if ( NombreDeContraintes >= Spx->NombreDeContraintesAllouees ) { + Spx->NombreDeContraintes = NombreDeContraintes; + Spx->NombreDeVariables = NombreDeVariables; + SPX_AugmenterLeNombreDeContraintes( Spx ); + NombreDeContraintes = Spx->NombreDeContraintes; + NombreDeVariables = Spx->NombreDeVariables; + B = Spx->B; + CorrespondanceCntSimplexeCntEntree = Spx->CorrespondanceCntSimplexeCntEntree; + BAvantTranslationEtApresScaling = Spx->BAvantTranslationEtApresScaling; + ScaleB = Spx->ScaleB; + Mdeb = Spx->Mdeb; + NbTerm = Spx->NbTerm; + VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + } + +} + +Spx->NombreDeContraintes = NombreDeContraintes; +Spx->NombreDeVariables = NombreDeVariables; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_allouer_probleme.c b/src/ext/Sirius_Solver/simplexe/spx_allouer_probleme.c new file mode 100644 index 0000000000..59f8e153f2 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_allouer_probleme.c @@ -0,0 +1,867 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Allouer / desallouer la structure du probleme + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "lu_fonctions.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void SPX_AllouerProbleme( PROBLEME_SPX * Spx, + int NbVar_E, + int NbContr_E, + int * Mdeb_E, + int * NbTerm_E ) +{ +int i; int NbTrm; int NbVarMx; + +Spx->MatriceFactorisee = NULL; +Spx->ProblemePneDeSpx = NULL; + +NbVarMx = NbVar_E + ( 2 * NbContr_E ); + +Spx->NombreDeVariablesAllouees = NbVarMx; + +Spx->NumeroDesVariablesACoutNonNul = (int *) malloc( NbVarMx * sizeof( int ) ); +Spx->C = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->Csv = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->X = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->Xmin = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->Xmax = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->TypeDeVariable = (char *) malloc( NbVarMx * sizeof( char ) ); +Spx->OrigineDeLaVariable = (char *) malloc( NbVarMx * sizeof( char ) ); +Spx->StatutBorneSupCourante = (char *) malloc( NbVarMx * sizeof( char ) ); +Spx->BorneSupAuxiliaire = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->StatutBorneSupAuxiliaire = (char *) malloc( NbVarMx * sizeof( char ) ); + +Spx->CntVarEcartOuArtif = (int *) malloc( NbVarMx * sizeof( int ) ); +Spx->XEntree = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->XminEntree = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->XmaxEntree = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->SeuilDeViolationDeBorne = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->SeuilDAmissibiliteDuale1 = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->SeuilDAmissibiliteDuale2 = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->ScaleX = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->CorrespondanceVarEntreeVarSimplexe = (int *) malloc( NbVarMx * sizeof( int ) ); +Spx->CorrespondanceVarSimplexeVarEntree = (int *) malloc( NbVarMx * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->NombreDeContraintesAllouees = NbContr_E; + +Spx->B = (double *) malloc( NbContr_E * sizeof( double ) ); +Spx->BAvantTranslationEtApresScaling = (double *) malloc( NbContr_E * sizeof( double ) ); +Spx->ScaleB = (double *) malloc( NbContr_E * sizeof( double ) ); +Spx->Mdeb = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->NbTerm = (int *) malloc( NbContr_E * sizeof( int ) ); + +/* Calcul du nombre de termes */ +for ( NbTrm = -1 , i = 0 ; i < NbContr_E ; i++ ) { + if ( ( Mdeb_E[i] + NbTerm_E[i] ) > NbTrm ) NbTrm = Mdeb_E[i] + NbTerm_E[i]; /* Un terme de plus */ +} + +NbTrm+= NbContr_E; /* Par exces pour les variables d'ecart sur les inegalites */ +NbTrm+= NbContr_E; /* Par exces pour la base triviale de depart */ + +if ( NbTrm <= 0 ) NbTrm = 1; + +Spx->NbTermesAlloues = NbTrm; + +Spx->A = (double *) malloc( NbTrm * sizeof( double ) ); +Spx->Indcol = (int *) malloc( NbTrm * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->CorrespondanceCntSimplexeCntEntree = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->CorrespondanceCntEntreeCntSimplexe = (int *) malloc( NbContr_E * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->Cdeb = (int *) malloc( NbVarMx * sizeof( int ) ); +Spx->CNbTerm = (int *) malloc( NbVarMx * sizeof( int ) ); +Spx->CNbTermSansCoupes = (int *) malloc( NbVarMx * sizeof( int ) ); +Spx->CNbTermesDeCoupes = (int *) malloc( NbVarMx * sizeof( int ) ); +Spx->Csui = (int *) malloc( NbTrm * sizeof( int ) ); +Spx->ACol = (double *) malloc( NbTrm * sizeof( double ) ); +Spx->NumeroDeContrainte = (int *) malloc( NbTrm * sizeof( int ) ); +Spx->CdebBase = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->NbTermesDesColonnesDeLaBase = (int *) malloc( NbContr_E * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +NbTrm = CYCLE_DE_REFACTORISATION + 1 /* Marge */; + +Spx->EtaDeb = (int *) malloc( NbTrm * sizeof( int ) ); +Spx->EtaNbTerm = (int *) malloc( NbTrm * sizeof( int ) ); +Spx->EtaColonne = (int *) malloc( NbTrm * sizeof( int ) ); + +NbTrm*= NbContr_E; +Spx->EtaIndiceLigne = (int *) malloc( NbTrm * sizeof( int ) ); +Spx->EtaMoins1Valeur = (double *) malloc( NbTrm * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->T = (int *) malloc( NbVarMx * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->CntDeABarreSNonNuls = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->ABarreS = (double *) malloc( NbContr_E * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->Bs = (double *) malloc( NbContr_E * sizeof( double ) ); +Spx->BBarre = (double *) malloc( NbContr_E * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->BoundFlip = (int *) malloc( NbVarMx * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->Pi = (double *) malloc( NbContr_E * sizeof( double ) ); +Spx->CBarre = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->PositionDeLaVariable = (char *) malloc( NbVarMx * sizeof( char ) ); +Spx->ContrainteDeLaVariableEnBase = (int *) malloc( NbVarMx * sizeof( int ) ); +Spx->VariableEnBaseDeLaContrainte = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->NombreDeVariablesHorsBaseDeLaContrainte = (int *) malloc( NbContr_E * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->IndexDansContrainteASurveiller = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->NumerosDesContraintesASurveiller = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->ValeurDeViolationDeBorne = (double *) malloc( NbContr_E * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->NumerosDesVariablesHorsBase = (int *) malloc( ( NbVarMx - NbContr_E ) * sizeof( int ) ); +Spx->NBarreR = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->IndexDeLaVariableDansLesVariablesHorsBase = (int *) malloc( NbVarMx * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->NumVarNBarreRNonNul = (int *) malloc( ( NbVarMx - NbContr_E ) * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->NumeroDesVariableATester = (int *) malloc( NbVarMx * sizeof( int ) ); +Spx->CBarreSurNBarreR = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->CBarreSurNBarreRAvecTolerance = (double *) malloc( NbVarMx * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->IndexTermesNonNulsDeErBMoinsUn = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->ErBMoinsUn = (double *) malloc( NbContr_E * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->InDualFramework = (char *) malloc( NbVarMx * sizeof( char ) ); +Spx->DualPoids = (double *) malloc( NbContr_E * sizeof( double ) ); +Spx->Tau = (double *) malloc( NbContr_E * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->CorrectionDuale = (char *) malloc( NbVarMx * sizeof( char ) ); +/*------------------------------------------------------------------------*/ +Spx->V = (double *) malloc( NbContr_E * sizeof( double ) ); +Spx->FaisabiliteDeLaVariable = (char *) malloc( NbVarMx * sizeof( char ) ); +/*------------------------------------------------------------------------*/ +Spx->PositionHorsBaseReduiteAutorisee = (char *) malloc( NbVarMx * sizeof( char ) ); +Spx->OrdreColonneDeLaBaseFactorisee = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->ColonneDeLaBaseFactorisee = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->OrdreLigneDeLaBaseFactorisee = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->LigneDeLaBaseFactorisee = (int *) malloc( NbContr_E * sizeof( int ) ); + +Spx->AReduit = (double *) malloc( NbContr_E * sizeof( double ) ); +Spx->IndexAReduit = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->Marqueur = (int *) malloc( NbContr_E * sizeof( int ) ); + +/*------------------------------------------------------------------------*/ + +if ( + Spx->NumeroDesVariablesACoutNonNul == NULL || + Spx->C == NULL || + Spx->Csv == NULL || + Spx->X == NULL || + Spx->Xmin == NULL || + Spx->Xmax == NULL || + Spx->TypeDeVariable == NULL || + Spx->OrigineDeLaVariable == NULL || + Spx->StatutBorneSupCourante == NULL || + Spx->BorneSupAuxiliaire == NULL || + Spx->StatutBorneSupAuxiliaire == NULL || +/*------------------------------------------------------------------------*/ + Spx->CntVarEcartOuArtif == NULL || + Spx->XEntree == NULL || + Spx->XminEntree == NULL || + Spx->XmaxEntree == NULL || + Spx->SeuilDeViolationDeBorne == NULL || + Spx->SeuilDAmissibiliteDuale1 == NULL || + Spx->SeuilDAmissibiliteDuale2 == NULL || + Spx->ScaleX == NULL || + Spx->CorrespondanceVarEntreeVarSimplexe == NULL || + Spx->CorrespondanceVarSimplexeVarEntree == NULL || +/*------------------------------------------------------------------------*/ + Spx->B == NULL || + Spx->BAvantTranslationEtApresScaling == NULL || + Spx->ScaleB == NULL || + Spx->Mdeb == NULL || + Spx->NbTerm == NULL || + Spx->A == NULL || + Spx->Indcol == NULL || +/*------------------------------------------------------------------------*/ + Spx->CorrespondanceCntSimplexeCntEntree == NULL || + Spx->CorrespondanceCntEntreeCntSimplexe == NULL || +/*------------------------------------------------------------------------*/ + Spx->Cdeb == NULL || + Spx->CNbTerm == NULL || + Spx->CNbTermSansCoupes == NULL || + Spx->CNbTermesDeCoupes == NULL || + Spx->ACol == NULL || + Spx->Csui == NULL || + Spx->NumeroDeContrainte == NULL || + Spx->CdebBase == NULL || + Spx->NbTermesDesColonnesDeLaBase == NULL || +/*------------------------------------------------------------------------*/ + Spx->EtaDeb == NULL || + Spx->EtaNbTerm == NULL || + Spx->EtaColonne == NULL || + Spx->EtaIndiceLigne == NULL || + Spx->EtaMoins1Valeur == NULL || +/*------------------------------------------------------------------------*/ + Spx->T == NULL || +/*------------------------------------------------------------------------*/ + Spx->CntDeABarreSNonNuls == NULL || + Spx->ABarreS == NULL || +/*------------------------------------------------------------------------*/ + Spx->Bs == NULL || + Spx->BBarre == NULL || +/*------------------------------------------------------------------------*/ + Spx->BoundFlip == NULL || +/*------------------------------------------------------------------------*/ + Spx->Pi == NULL || + Spx->CBarre == NULL || + Spx->PositionDeLaVariable == NULL || + Spx->ContrainteDeLaVariableEnBase == NULL || + Spx->VariableEnBaseDeLaContrainte == NULL || + Spx->NombreDeVariablesHorsBaseDeLaContrainte == NULL || +/*------------------------------------------------------------------------*/ + Spx->IndexDansContrainteASurveiller == NULL || + Spx->NumerosDesContraintesASurveiller == NULL || + Spx->ValeurDeViolationDeBorne == NULL || +/*------------------------------------------------------------------------*/ + Spx->NumerosDesVariablesHorsBase == NULL || + Spx->NBarreR == NULL || + Spx->IndexDeLaVariableDansLesVariablesHorsBase == NULL || +/*------------------------------------------------------------------------*/ + Spx->NumVarNBarreRNonNul == NULL || +/*------------------------------------------------------------------------*/ + Spx->NumeroDesVariableATester == NULL || + Spx->CBarreSurNBarreR == NULL || + Spx->CBarreSurNBarreRAvecTolerance == NULL || +/*------------------------------------------------------------------------*/ + Spx->IndexTermesNonNulsDeErBMoinsUn == NULL || + Spx->ErBMoinsUn == NULL || +/*------------------------------------------------------------------------*/ + Spx->InDualFramework == NULL || + Spx->DualPoids == NULL || + Spx->Tau == NULL || +/*------------------------------------------------------------------------*/ + Spx->CorrectionDuale == NULL || +/*------------------------------------------------------------------------*/ + Spx->V == NULL || + Spx->FaisabiliteDeLaVariable == NULL || +/*------------------------------------------------------------------------*/ + Spx->PositionHorsBaseReduiteAutorisee == NULL || + Spx->OrdreColonneDeLaBaseFactorisee == NULL || + Spx->ColonneDeLaBaseFactorisee == NULL || + Spx->OrdreLigneDeLaBaseFactorisee == NULL || + Spx->LigneDeLaBaseFactorisee == NULL || + + Spx->AReduit == NULL || + Spx->IndexAReduit == NULL || + Spx->Marqueur == NULL + + ) { + + printf("Simplexe, sous-programme SPX_AllouerProbleme: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +/* Finalement on le fait toujours car on en a besoin pour sauvegarder les bases */ +/*if ( Spx.Contexte != BRANCH_AND_BOUND_OU_CUT ) return;*/ + +Spx->XSV = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->PositionDeLaVariableSV = (char *) malloc( NbVarMx * sizeof( char ) ); +Spx->CBarreSV = (double *) malloc( NbVarMx * sizeof( double ) ); +Spx->InDualFrameworkSV = (char *) malloc( NbVarMx * sizeof( char ) ); +Spx->ContrainteDeLaVariableEnBaseSV = (int *) malloc( NbVarMx * sizeof( int ) ); + +Spx->BBarreSV = (double *) malloc( NbContr_E * sizeof( double ) ); +Spx->DualPoidsSV = (double *) malloc( NbContr_E * sizeof( double ) ); +Spx->VariableEnBaseDeLaContrainteSV = (int *) malloc( NbContr_E * sizeof( int ) ); + +Spx->CdebBaseSV = (int *) malloc( NbContr_E * sizeof( int ) ); +Spx->NbTermesDesColonnesDeLaBaseSV = (int *) malloc( NbContr_E * sizeof( int ) ); + +if ( + Spx->XSV == NULL || + Spx->PositionDeLaVariableSV == NULL || + Spx->CBarreSV == NULL || + Spx->InDualFrameworkSV == NULL || + Spx->ContrainteDeLaVariableEnBaseSV == NULL || + + Spx->BBarreSV == NULL || + Spx->DualPoidsSV == NULL || + Spx->VariableEnBaseDeLaContrainteSV == NULL || + + Spx->CdebBaseSV == NULL || + Spx->NbTermesDesColonnesDeLaBaseSV == NULL + + ) { + + printf("Simplexe, sous-programme SPX_AllouerProbleme: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); +} + +Spx->DonneesPourCoupesDIntersection = NULL; +Spx->CoupesDintersectionAllouees = NON_SPX; + +for ( i = 0 ; i < NbVarMx ; i++ ) Spx->T[i] = -1; + +Spx->NbElementsAllouesPourLeProblemeReduit = NbContr_E; +Spx->CdebProblemeReduit = (int *) malloc( NbVarMx * sizeof( int ) ); +Spx->CNbTermProblemeReduit = (int *) malloc( NbVarMx * sizeof( int ) ); +Spx->ValeurDesTermesDesColonnesDuProblemeReduit = (double *) malloc( Spx->NbElementsAllouesPourLeProblemeReduit * sizeof( double ) ); +Spx->IndicesDeLigneDesTermesDuProblemeReduit = (int *) malloc( Spx->NbElementsAllouesPourLeProblemeReduit * sizeof( int ) ); +if ( + Spx->CdebProblemeReduit == NULL || Spx->CNbTermProblemeReduit == NULL || + Spx->ValeurDesTermesDesColonnesDuProblemeReduit == NULL || Spx->IndicesDeLigneDesTermesDuProblemeReduit == NULL + ) { + + printf("Simplexe, sous-programme SPX_AllouerProbleme: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); +} + +memset( (double *) Spx->AReduit, 0, NbContr_E * sizeof( double ) ); + +for ( i = 0 ; i < NbContr_E ; i++ ) Spx->Marqueur[i] = -1; + +Spx->IndexDansLaMatriceHorsBase = NULL; +Spx->MdebHorsBase = NULL; +Spx->NbTermHorsBase = NULL; +Spx->AHorsBase = NULL; +Spx->IndcolHorsBase = NULL; +Spx->InverseIndexDansLaMatriceHorsBase = NULL; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_AugmenterLeNombreDeVariables( PROBLEME_SPX * Spx ) +{ +int NbVarMx; int i; + +/*printf(" SIMPLEXE Augmentation du nombre de variables\n"); fflush(stdout);*/ + +NbVarMx = Spx->NombreDeVariablesAllouees + INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_VARIABLES_SPX; + +Spx->NombreDeVariablesAllouees = NbVarMx; + +Spx->C = (double *) realloc( Spx->C , NbVarMx * sizeof( double ) ); +Spx->Csv = (double *) realloc( Spx->Csv , NbVarMx * sizeof( double ) ); +Spx->X = (double *) realloc( Spx->X , NbVarMx * sizeof( double ) ); +Spx->Xmin = (double *) realloc( Spx->Xmin , NbVarMx * sizeof( double ) ); +Spx->Xmax = (double *) realloc( Spx->Xmax , NbVarMx * sizeof( double ) ); +Spx->TypeDeVariable = (char *) realloc( Spx->TypeDeVariable , NbVarMx * sizeof( char ) ); +Spx->OrigineDeLaVariable = (char *) realloc( Spx->OrigineDeLaVariable, NbVarMx * sizeof( char ) ); + +Spx->StatutBorneSupCourante = (char *) realloc( Spx->StatutBorneSupCourante , NbVarMx * sizeof( char ) ); +Spx->BorneSupAuxiliaire = (double *) realloc( Spx->BorneSupAuxiliaire , NbVarMx * sizeof( double ) ); +Spx->StatutBorneSupAuxiliaire = (char *) realloc( Spx->StatutBorneSupAuxiliaire, NbVarMx * sizeof( char ) ); + +Spx->CntVarEcartOuArtif = (int *) realloc( Spx->CntVarEcartOuArtif , NbVarMx * sizeof( int ) ); +Spx->XEntree = (double *) realloc( Spx->XEntree , NbVarMx * sizeof( double ) ); +Spx->XminEntree = (double *) realloc( Spx->XminEntree, NbVarMx * sizeof( double ) ); +Spx->XmaxEntree = (double *) realloc( Spx->XmaxEntree, NbVarMx * sizeof( double ) ); +Spx->SeuilDeViolationDeBorne = (double *) realloc( Spx->SeuilDeViolationDeBorne, NbVarMx * sizeof( double ) ); +Spx->SeuilDAmissibiliteDuale1 = (double *) realloc( Spx->SeuilDAmissibiliteDuale1, NbVarMx * sizeof( double ) ); +Spx->SeuilDAmissibiliteDuale2 = (double *) realloc( Spx->SeuilDAmissibiliteDuale2, NbVarMx * sizeof( double ) ); +Spx->ScaleX = (double *) realloc( Spx->ScaleX , NbVarMx * sizeof( double ) ); +Spx->CorrespondanceVarEntreeVarSimplexe = (int *) realloc( Spx->CorrespondanceVarEntreeVarSimplexe, NbVarMx * sizeof( int ) ); +Spx->CorrespondanceVarSimplexeVarEntree = (int *) realloc( Spx->CorrespondanceVarSimplexeVarEntree, NbVarMx * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->Cdeb = (int *) realloc( Spx->Cdeb , NbVarMx * sizeof( int ) ); +Spx->CNbTerm = (int *) realloc( Spx->CNbTerm, NbVarMx * sizeof( int ) ); +Spx->CNbTermSansCoupes = (int *) realloc( Spx->CNbTermSansCoupes, NbVarMx * sizeof( int ) ); +Spx->CNbTermesDeCoupes = (int *) realloc( Spx->CNbTermesDeCoupes, NbVarMx * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->T = (int *) realloc( Spx->T, NbVarMx * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->CBarre = (double *) realloc( Spx->CBarre , NbVarMx * sizeof( double ) ); +Spx->PositionDeLaVariable = (char *) realloc( Spx->PositionDeLaVariable , NbVarMx * sizeof( char ) ); +Spx->ContrainteDeLaVariableEnBase = (int *) realloc( Spx->ContrainteDeLaVariableEnBase, NbVarMx * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->NumerosDesVariablesHorsBase = (int *) realloc( Spx->NumerosDesVariablesHorsBase , ( NbVarMx - Spx->NombreDeContraintesAllouees ) * sizeof( int ) ); +Spx->NBarreR = (double *) realloc( Spx->NBarreR , NbVarMx * sizeof( double ) ); +Spx->IndexDeLaVariableDansLesVariablesHorsBase = (int *) realloc( Spx->IndexDeLaVariableDansLesVariablesHorsBase , NbVarMx * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->NumVarNBarreRNonNul = (int *) realloc( Spx->NumVarNBarreRNonNul , ( NbVarMx - Spx->NombreDeContraintesAllouees ) * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->NumeroDesVariableATester = (int *) realloc( Spx->NumeroDesVariableATester , NbVarMx * sizeof( int ) ); +Spx->CBarreSurNBarreR = (double *) realloc( Spx->CBarreSurNBarreR , NbVarMx * sizeof( double ) ); +Spx->CBarreSurNBarreRAvecTolerance = (double *) realloc( Spx->CBarreSurNBarreRAvecTolerance, NbVarMx * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->InDualFramework = (char *) realloc( Spx->InDualFramework, NbVarMx * sizeof( char ) ); +/*------------------------------------------------------------------------*/ +Spx->CorrectionDuale = (char *) realloc( Spx->CorrectionDuale, NbVarMx * sizeof( char ) ); +/*------------------------------------------------------------------------*/ +Spx->FaisabiliteDeLaVariable = (char *) realloc( Spx->FaisabiliteDeLaVariable, NbVarMx * sizeof( char ) ); +/*------------------------------------------------------------------------*/ +Spx->BoundFlip = (int *) realloc( Spx->BoundFlip, NbVarMx * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->PositionHorsBaseReduiteAutorisee = (char *) realloc( Spx->PositionHorsBaseReduiteAutorisee, NbVarMx * sizeof( char ) ); +/*------------------------------------------------------------------------*/ +Spx->CdebProblemeReduit = (int *) realloc( Spx->CdebProblemeReduit, NbVarMx * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->CNbTermProblemeReduit = (int *) realloc( Spx->CNbTermProblemeReduit, NbVarMx * sizeof( int ) ); + +if ( + Spx->C == NULL || + Spx->Csv == NULL || + Spx->X == NULL || + Spx->Xmin == NULL || + Spx->Xmax == NULL || + Spx->TypeDeVariable == NULL || + Spx->OrigineDeLaVariable == NULL || + Spx->StatutBorneSupCourante == NULL || + Spx->BorneSupAuxiliaire == NULL || + Spx->StatutBorneSupAuxiliaire == NULL || + Spx->CntVarEcartOuArtif == NULL || + Spx->XEntree == NULL || + Spx->XminEntree == NULL || + Spx->XmaxEntree == NULL || + Spx->SeuilDeViolationDeBorne == NULL || + Spx->SeuilDAmissibiliteDuale1 == NULL || + Spx->SeuilDAmissibiliteDuale2 == NULL || + Spx->ScaleX == NULL || + Spx->CorrespondanceVarEntreeVarSimplexe == NULL || + Spx->CorrespondanceVarSimplexeVarEntree == NULL || +/*------------------------------------------------------------------------*/ + Spx->Cdeb == NULL || + Spx->CNbTerm == NULL || + Spx->CNbTermSansCoupes == NULL || + Spx->CNbTermesDeCoupes == NULL || +/*------------------------------------------------------------------------*/ + Spx->T == NULL || +/*------------------------------------------------------------------------*/ + Spx->CBarre == NULL || + Spx->PositionDeLaVariable == NULL || + Spx->ContrainteDeLaVariableEnBase == NULL || +/*------------------------------------------------------------------------*/ + Spx->NumerosDesVariablesHorsBase == NULL || + Spx->NBarreR == NULL || + Spx->IndexDeLaVariableDansLesVariablesHorsBase == NULL || +/*------------------------------------------------------------------------*/ + Spx->NumVarNBarreRNonNul == NULL || +/*------------------------------------------------------------------------*/ + Spx->NumeroDesVariableATester == NULL || + Spx->CBarreSurNBarreR == NULL || + Spx->CBarreSurNBarreRAvecTolerance == NULL || +/*------------------------------------------------------------------------*/ + Spx->InDualFramework == NULL || +/*------------------------------------------------------------------------*/ + Spx->CorrectionDuale == NULL || +/*------------------------------------------------------------------------*/ + Spx->FaisabiliteDeLaVariable == NULL || +/*------------------------------------------------------------------------*/ + Spx->BoundFlip == NULL || +/*------------------------------------------------------------------------*/ + Spx->CdebProblemeReduit == NULL || +/*------------------------------------------------------------------------*/ + Spx->CNbTermProblemeReduit == NULL + + ) { + + printf("Simplexe, sous-programme SPX_AugmenterLeNombreDeVariables: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +for ( i = 0 ; i < NbVarMx ; i++ ) Spx->T[i] = -1; +for ( i = Spx->NombreDeVariables ; i < NbVarMx ; i++ ) Spx->PositionHorsBaseReduiteAutorisee[i] = OUI_1_FOIS; + +Spx->XSV = (double *) realloc( Spx->XSV , NbVarMx * sizeof( double ) ); +Spx->PositionDeLaVariableSV = (char *) realloc( Spx->PositionDeLaVariableSV , NbVarMx * sizeof( char ) ); +Spx->CBarreSV = (double *) realloc( Spx->CBarreSV , NbVarMx * sizeof( double ) ); +Spx->InDualFrameworkSV = (char *) realloc( Spx->InDualFrameworkSV , NbVarMx * sizeof( char ) ); +Spx->ContrainteDeLaVariableEnBaseSV = (int *) realloc( Spx->ContrainteDeLaVariableEnBaseSV, NbVarMx * sizeof( int ) ); + +if ( + Spx->XSV == NULL || + Spx->PositionDeLaVariableSV == NULL || + Spx->CBarreSV == NULL || + Spx->InDualFrameworkSV == NULL || + Spx->ContrainteDeLaVariableEnBaseSV == NULL + ) { + + printf("Simplexe, sous-programme SPX_AugmenterLeNombreDeVariables: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); +} +/* +printf(" Fin augmentation du nombre de variables\n"); fflush(stdout); +*/ +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_AugmenterLeNombreDeContraintes( PROBLEME_SPX * Spx ) +{ +int NbContr_E; int NbTrm; int i; + +/*printf(" SIMPLEXE Augmentation du nombre de contraintes\n"); fflush(stdout);*/ + +NbContr_E = Spx->NombreDeContraintesAllouees + INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_CONTRAINTES_SPX; +Spx->NombreDeContraintesAllouees = NbContr_E; + +/*------------------------------------------------------------------------*/ +Spx->B = (double *) realloc( Spx->B , NbContr_E * sizeof( double ) ); +Spx->BAvantTranslationEtApresScaling = (double *) realloc( Spx->BAvantTranslationEtApresScaling, NbContr_E * sizeof( double ) ); +Spx->ScaleB = (double *) realloc( Spx->ScaleB , NbContr_E * sizeof( double ) ); +Spx->Mdeb = (int *) realloc( Spx->Mdeb , NbContr_E * sizeof( int ) ); +Spx->NbTerm = (int *) realloc( Spx->NbTerm , NbContr_E * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->CorrespondanceCntSimplexeCntEntree = (int *) realloc( Spx->CorrespondanceCntSimplexeCntEntree, NbContr_E * sizeof( int ) ); +Spx->CorrespondanceCntEntreeCntSimplexe = (int *) realloc( Spx->CorrespondanceCntEntreeCntSimplexe, NbContr_E * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->CdebBase = (int *) realloc( Spx->CdebBase , NbContr_E * sizeof( int ) ); +Spx->NbTermesDesColonnesDeLaBase = (int *) realloc( Spx->NbTermesDesColonnesDeLaBase, NbContr_E * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +NbTrm = CYCLE_DE_REFACTORISATION + 1 /* Marge */; +NbTrm*= NbContr_E; +Spx->EtaIndiceLigne = (int *) realloc( Spx->EtaIndiceLigne , NbTrm * sizeof( int ) ); +Spx->EtaMoins1Valeur = (double *) realloc( Spx->EtaMoins1Valeur, NbTrm * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->CntDeABarreSNonNuls = (int *) realloc( Spx->CntDeABarreSNonNuls, NbContr_E * sizeof( int ) ); +Spx->ABarreS = (double *) realloc( Spx->ABarreS , NbContr_E * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->Bs = (double *) realloc( Spx->Bs , NbContr_E * sizeof( double ) ); +Spx->BBarre = (double *) realloc( Spx->BBarre , NbContr_E * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->Pi = (double *) realloc( Spx->Pi, NbContr_E * sizeof( double ) ); +Spx->VariableEnBaseDeLaContrainte = (int *) realloc( Spx->VariableEnBaseDeLaContrainte, NbContr_E * sizeof( int ) ); +Spx->NombreDeVariablesHorsBaseDeLaContrainte = (int *) realloc( Spx->NombreDeVariablesHorsBaseDeLaContrainte, NbContr_E * sizeof( int) ); +/*------------------------------------------------------------------------*/ +Spx->IndexDansContrainteASurveiller = (int *) realloc( Spx->IndexDansContrainteASurveiller , NbContr_E * sizeof( int ) ); +Spx->NumerosDesContraintesASurveiller = (int *) realloc( Spx->NumerosDesContraintesASurveiller, NbContr_E * sizeof( int ) ); +Spx->ValeurDeViolationDeBorne = (double *) realloc( Spx->ValeurDeViolationDeBorne , NbContr_E * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +/* Il n'y a pas lieu de diminuer la taille allouee aux tableaux ci-dessous */ +/* +Spx->NumerosDesVariablesHorsBase = (int *) realloc( Spx->NumerosDesVariablesHorsBase , ( Spx->NombreDeVariablesAllouees - NbContr_E ) * sizeof( int ) ); +Spx->NBarreRHorsBase = (double *) realloc( Spx->NBarreRHorsBase , ( Spx->NombreDeVariablesAllouees - NbContr_E ) * sizeof( double ) ); +*/ +/*------------------------------------------------------------------------*/ +Spx->IndexTermesNonNulsDeErBMoinsUn = (int *) realloc( Spx->IndexTermesNonNulsDeErBMoinsUn , NbContr_E * sizeof( int ) ); +Spx->ErBMoinsUn = (double *) realloc( Spx->ErBMoinsUn , NbContr_E * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->DualPoids = (double *) realloc( Spx->DualPoids, NbContr_E * sizeof( double ) ); +Spx->Tau = (double *) realloc( Spx->Tau , NbContr_E * sizeof( double ) ); +/*------------------------------------------------------------------------*/ +Spx->V = (double *) realloc( Spx->V, NbContr_E * sizeof( double ) ); +/*------------------------------------------------------------------------*/ + +Spx->OrdreColonneDeLaBaseFactorisee = (int *) realloc( Spx->OrdreColonneDeLaBaseFactorisee, NbContr_E * sizeof( int ) ); +Spx->ColonneDeLaBaseFactorisee = (int *) realloc( Spx->ColonneDeLaBaseFactorisee, NbContr_E * sizeof( int ) ); +Spx->OrdreLigneDeLaBaseFactorisee = (int *) realloc( Spx->OrdreLigneDeLaBaseFactorisee, NbContr_E * sizeof( int ) ); +Spx->LigneDeLaBaseFactorisee = (int *) realloc( Spx->LigneDeLaBaseFactorisee, NbContr_E * sizeof( int ) ); + +Spx->AReduit = (double *) realloc( Spx->AReduit, NbContr_E * sizeof( double ) ); +Spx->IndexAReduit = (int *) realloc( Spx->IndexAReduit, NbContr_E * sizeof( int ) ); +Spx->Marqueur = (int *) realloc( Spx->Marqueur, NbContr_E * sizeof( int ) ); + +if ( + Spx->B == NULL || + Spx->BAvantTranslationEtApresScaling == NULL || + Spx->ScaleB == NULL || + Spx->Mdeb == NULL || + Spx->NbTerm == NULL || +/*------------------------------------------------------------------------*/ + Spx->CorrespondanceCntSimplexeCntEntree == NULL || + Spx->CorrespondanceCntEntreeCntSimplexe == NULL || +/*------------------------------------------------------------------------*/ + Spx->CdebBase == NULL || + Spx->NbTermesDesColonnesDeLaBase == NULL || +/*------------------------------------------------------------------------*/ + Spx->CntDeABarreSNonNuls == NULL || + Spx->ABarreS == NULL || +/*------------------------------------------------------------------------*/ + Spx->Bs == NULL || + Spx->BBarre == NULL || +/*------------------------------------------------------------------------*/ + Spx->Pi == NULL || + Spx->VariableEnBaseDeLaContrainte == NULL || + Spx->NombreDeVariablesHorsBaseDeLaContrainte == NULL || +/*------------------------------------------------------------------------*/ + Spx->IndexDansContrainteASurveiller == NULL || + Spx->NumerosDesContraintesASurveiller == NULL || + Spx->ValeurDeViolationDeBorne == NULL || +/*------------------------------------------------------------------------*/ + Spx->NumerosDesVariablesHorsBase == NULL || + Spx->NBarreR == NULL || +/*------------------------------------------------------------------------*/ + Spx->IndexTermesNonNulsDeErBMoinsUn == NULL || + Spx->ErBMoinsUn == NULL || +/*------------------------------------------------------------------------*/ + Spx->DualPoids == NULL || + Spx->Tau == NULL || +/*------------------------------------------------------------------------*/ + Spx->CorrectionDuale == NULL || +/*------------------------------------------------------------------------*/ + Spx->V == NULL || +/*------------------------------------------------------------------------*/ + Spx->OrdreColonneDeLaBaseFactorisee == NULL || + Spx->ColonneDeLaBaseFactorisee == NULL || + Spx->OrdreLigneDeLaBaseFactorisee == NULL || + Spx->LigneDeLaBaseFactorisee == NULL || + + Spx->AReduit == NULL || + Spx->IndexAReduit == NULL || + Spx->Marqueur == NULL + + ) { + + printf("Simplexe, sous-programme SPX_AugmenterLeNombreDeContraintes: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +memset( (double *) Spx->AReduit, 0, NbContr_E * sizeof( double ) ); + +for ( i = 0 ; i < NbContr_E ; i++ ) Spx->Marqueur[i] = -1; + +Spx->BBarreSV = (double *) realloc( Spx->BBarreSV , NbContr_E * sizeof( double ) ); +Spx->DualPoidsSV = (double *) realloc( Spx->DualPoidsSV , NbContr_E * sizeof( double ) ); +Spx->VariableEnBaseDeLaContrainteSV = (int *) realloc( Spx->VariableEnBaseDeLaContrainteSV, NbContr_E * sizeof( int ) ); + +Spx->CdebBaseSV = (int *) realloc( Spx->CdebBaseSV , NbContr_E * sizeof( int ) ); +Spx->NbTermesDesColonnesDeLaBaseSV = (int *) realloc( Spx->NbTermesDesColonnesDeLaBaseSV, NbContr_E * sizeof( int ) ); + +if ( + Spx->BBarreSV == NULL || + Spx->DualPoidsSV == NULL || + Spx->VariableEnBaseDeLaContrainteSV == NULL || + + Spx->CdebBaseSV == NULL || + Spx->NbTermesDesColonnesDeLaBaseSV == NULL + ) { + + printf("Simplexe, sous-programme SPX_AugmenterLeNombreDeContraintes: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + fflush(stdout); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_AugmenterLaTailleDeLaMatriceDesContraintes( PROBLEME_SPX * Spx ) +{ + +int NbTrm; +/* +printf(" SIMPLEXE Augmentation de la taille de la matrice des contraintes NbTermesAlloues %d\n",Spx.NbTermesAlloues); fflush(stdout); +*/ +NbTrm = Spx->NbTermesAlloues + INCREMENT_DALLOCATION_POUR_LA_MATRICE_DES_CONTRAINTES_SPX; +Spx->NbTermesAlloues = NbTrm; + +/*------------------------------------------------------------------------*/ +Spx->A = (double *) realloc( Spx->A, NbTrm * sizeof( double ) ); +Spx->Indcol = (int *) realloc( Spx->Indcol, NbTrm * sizeof( int ) ); +/*------------------------------------------------------------------------*/ +Spx->Csui = (int *) realloc( Spx->Csui, NbTrm * sizeof( int ) ); +Spx->ACol = (double *) realloc( Spx->ACol, NbTrm * sizeof( double ) ); +Spx->NumeroDeContrainte = (int *) realloc( Spx->NumeroDeContrainte, NbTrm * sizeof( int ) ); +/*------------------------------------------------------------------------*/ + +if ( + Spx->A == NULL || + Spx->Indcol == NULL || +/*------------------------------------------------------------------------*/ + Spx->Csui == NULL || + Spx->ACol == NULL || + Spx->NumeroDeContrainte == NULL + ) { + + printf("Simplexe, sous-programme SPX_AugmenterLaTailleDeLaMatriceDesContraintes: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_LibererProbleme( PROBLEME_SPX * Spx ) +{ + +if ( Spx->MatriceFactorisee != NULL ) { + LU_LibererMemoireLU( (MATRICE *) Spx->MatriceFactorisee ); +} + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + MEM_Quit( Spx->Tas ); + return; +# endif + +free( Spx->NumeroDesVariablesACoutNonNul ); +free( Spx->C ); +free( Spx->Csv ); +free( Spx->X ); +free( Spx->Xmin ); +free( Spx->Xmax ); +free( Spx->TypeDeVariable ); +free( Spx->OrigineDeLaVariable ); + +free( Spx->StatutBorneSupCourante ); +free( Spx->BorneSupAuxiliaire ); +free( Spx->StatutBorneSupAuxiliaire ); + +free( Spx->CntVarEcartOuArtif ); +free( Spx->XEntree ); +free( Spx->XminEntree ); +free( Spx->XmaxEntree ); +free( Spx->SeuilDeViolationDeBorne ); +free( Spx->SeuilDAmissibiliteDuale1 ); +free( Spx->SeuilDAmissibiliteDuale2 ); +free( Spx->ScaleX ); +free( Spx->CorrespondanceVarEntreeVarSimplexe ); +free( Spx->CorrespondanceVarSimplexeVarEntree ); + +free( Spx->B ); +free( Spx->BAvantTranslationEtApresScaling ); +free( Spx->ScaleB ); +free( Spx->Mdeb ); +free( Spx->NbTerm ); +free( Spx->A ); +free( Spx->Indcol ); +free( Spx->CorrespondanceCntSimplexeCntEntree ); +free( Spx->CorrespondanceCntEntreeCntSimplexe ); + +free( Spx->Cdeb ); +free( Spx->CNbTerm ); +free( Spx->CNbTermSansCoupes ); +free( Spx->CNbTermesDeCoupes ); +free( Spx->ACol ); +free( Spx->Csui ); +free( Spx->NumeroDeContrainte ); +free( Spx->CdebBase ); +free( Spx->NbTermesDesColonnesDeLaBase ); + +free( Spx->EtaDeb ); +free( Spx->EtaNbTerm ); +free( Spx->EtaColonne ); +free( Spx->EtaIndiceLigne ); +free( Spx->EtaMoins1Valeur ); + +free( Spx->T ); + +free( Spx->CntDeABarreSNonNuls ); +free( Spx->ABarreS ); +free( Spx->Bs ); +free( Spx->BBarre ); + +free( Spx->BoundFlip ); + +free( Spx->Pi ); +free( Spx->CBarre ); +free( Spx->PositionDeLaVariable ); +free( Spx->ContrainteDeLaVariableEnBase ); +free( Spx->VariableEnBaseDeLaContrainte ); +free( Spx->NombreDeVariablesHorsBaseDeLaContrainte ); +free( Spx->IndexDansContrainteASurveiller ); +free( Spx->NumerosDesContraintesASurveiller ); +free( Spx->ValeurDeViolationDeBorne ); + +free( Spx->NumerosDesVariablesHorsBase ); +free( Spx->NBarreR ); +free( Spx->IndexDeLaVariableDansLesVariablesHorsBase ); +free( Spx->NumVarNBarreRNonNul ); + +free( Spx->NumeroDesVariableATester ); +free( Spx->CBarreSurNBarreR ); +free( Spx->CBarreSurNBarreRAvecTolerance ); + +free( Spx->IndexTermesNonNulsDeErBMoinsUn ); +free( Spx->ErBMoinsUn ); + +free( Spx->InDualFramework ); +free( Spx->DualPoids ); +free( Spx->Tau ); + +free( Spx->CorrectionDuale ); + +free( Spx->V ); +free( Spx->FaisabiliteDeLaVariable ); + +free( Spx->XSV ); +free( Spx->PositionDeLaVariableSV ); +free( Spx->CBarreSV ); +free( Spx->InDualFrameworkSV ); +free( Spx->ContrainteDeLaVariableEnBaseSV ); + +free( Spx->BBarreSV ); +free( Spx->DualPoidsSV ); +free( Spx->VariableEnBaseDeLaContrainteSV ); +free( Spx->CdebBaseSV ); +free( Spx->NbTermesDesColonnesDeLaBaseSV ); + +free( Spx->PositionHorsBaseReduiteAutorisee ); +free( Spx->OrdreColonneDeLaBaseFactorisee ); +free( Spx->ColonneDeLaBaseFactorisee ); +free( Spx->OrdreLigneDeLaBaseFactorisee ); +free( Spx->LigneDeLaBaseFactorisee ); + +free( Spx->CdebProblemeReduit ); +free( Spx->CNbTermProblemeReduit ); +free( Spx->ValeurDesTermesDesColonnesDuProblemeReduit ); +free( Spx->IndicesDeLigneDesTermesDuProblemeReduit ); +free( Spx->AReduit ); +free( Spx->IndexAReduit ); +free( Spx->Marqueur ); + +free( Spx->IndexDansLaMatriceHorsBase ); +free( Spx->MdebHorsBase ); +free( Spx->NbTermHorsBase ); +free( Spx->AHorsBase ); +free( Spx->IndcolHorsBase ); +free( Spx->InverseIndexDansLaMatriceHorsBase ); + +free( Spx ); + +return; +} + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_appliquer_eta_vecteurs.c b/src/ext/Sirius_Solver/simplexe/spx_appliquer_eta_vecteurs.c new file mode 100644 index 0000000000..ed4a84baf8 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_appliquer_eta_vecteurs.c @@ -0,0 +1,165 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Application des eta vecteurs pour la forme produit de + l'inverse + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +# define CONTROLE_RAZ_DES_VECTEURS NON_SPX + +/*----------------------------------------------------------------------------*/ +/* Reste ADRESSAGE_INDIRECT_LU a pogrammer */ +void SPX_AppliquerLesEtaVecteurs( PROBLEME_SPX * Spx, + double * A, + int * IndexDesTermesNonNuls, + int * NombreDeTermesNonNuls, + char CalculEnHyperCreux, + char TypeDeStockage /* COMPACT_LU + ADRESSAGE_INDIRECT_LU + VECTEUR_LU */ + ) +{ +int k; int Colonne; int il; int ilMax; double S; int * EtaIndiceLigne; int Cnt; +double * EtaMoins1Valeur; int * EtaNbTerm; int * EtaColonne; int j; int NbN; +int * Marqueur; double * W; + +EtaIndiceLigne = Spx->EtaIndiceLigne; +EtaMoins1Valeur = Spx->EtaMoins1Valeur; +EtaNbTerm = Spx->EtaNbTerm; +EtaColonne = Spx->EtaColonne; + +if ( CalculEnHyperCreux == OUI_SPX ) { + if ( TypeDeStockage == COMPACT_LU ) goto HyperCreux; + else if ( TypeDeStockage == ADRESSAGE_INDIRECT_LU ) goto HyperCreux; + else if ( TypeDeStockage != VECTEUR_LU ){ + printf("AppliquerLesEtaVecteurs: type de stockage non gere\n"); + exit(0); + } +} + +k = 0; +il = 0; +while ( k < Spx->NombreDeChangementsDeBase ) { + ilMax = il + EtaNbTerm[k]; + Colonne = EtaColonne[k]; + S = A[Colonne]; + A[Colonne] = 0.; + if ( S != 0.0 ) { + while ( il != ilMax ) { + A[EtaIndiceLigne[il]]+= EtaMoins1Valeur[il] * S; + il++; + } + } + else il = ilMax; + k++; +} + +return; + +HyperCreux: + +# if CONTROLE_RAZ_DES_VECTEURS == OUI_SPX + for ( j = 0 ; j < Spx->NombreDeContraintes ; j++ ) { + if ( Spx->AReduit[j] != 0 ) { + printf("Spx->AReduit[%d] = %e\n",j,Spx->AReduit[j]); + exit(0); + } + if ( Spx->Marqueur[j] != -1 ) { + printf("Spx->Marqueur[%d] = %d\n",j,Spx->Marqueur[j]); + exit(0); + } + } +# endif + +Marqueur = Spx->Marqueur; + +NbN = *NombreDeTermesNonNuls; + +if ( TypeDeStockage == COMPACT_LU ) { + W = Spx->AReduit; + for ( j = 0 ; j < NbN ; j++ ) { + Cnt = IndexDesTermesNonNuls[j]; + W[Cnt] = A[j]; + Marqueur[Cnt] = 1; + } +} +else { + W = A; + for ( j = 0 ; j < NbN ; j++ ) Marqueur[IndexDesTermesNonNuls[j]] = 1; +} + +k = 0; +il = 0; +while ( k < Spx->NombreDeChangementsDeBase ) { + ilMax = il + EtaNbTerm[k]; + Colonne = EtaColonne[k]; + S = W[Colonne]; + W[Colonne] = 0.; + if ( S != 0.0 ) { + while ( il != ilMax ) { + Cnt = EtaIndiceLigne[il]; + W[Cnt] += EtaMoins1Valeur[il] * S; + if ( Marqueur[Cnt] == -1 ) { + Marqueur[Cnt] = 1; + IndexDesTermesNonNuls[NbN] = Cnt; + NbN++; + } + il++; + } + } + else il = ilMax; + k++; +} + +if ( TypeDeStockage == COMPACT_LU ) { + for ( j = 0 ; j < NbN ; j++ ) { + Cnt = IndexDesTermesNonNuls[j]; + /* Ca consomme du temps pour pas grand chose + if ( W[Cnt] == 0 ) { + NbN--; + IndexDesTermesNonNuls[j] = IndexDesTermesNonNuls[NbN]; + Marqueur[Cnt] = -1; + j--; + continue; + } + */ + A[j] = W[Cnt]; + W[Cnt] = 0; + Marqueur[Cnt] = -1; + } +} +else { + for ( j = 0 ; j < NbN ; j++ ) Marqueur[IndexDesTermesNonNuls[j]] = -1; +} + +*NombreDeTermesNonNuls = NbN; + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_appliquer_eta_vecteurs_transposee.c b/src/ext/Sirius_Solver/simplexe/spx_appliquer_eta_vecteurs_transposee.c new file mode 100644 index 0000000000..366bc96c0c --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_appliquer_eta_vecteurs_transposee.c @@ -0,0 +1,158 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Application des eta vecteurs pour la forme produit de + l'inverse dans le calcul d'une resolution de systeme + avec forme produit de l'inverse. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +# define CONTROLE_RAZ_DES_VECTEURS NON_SPX + +/*----------------------------------------------------------------------------*/ +/* Reste ADRESSAGE_INDIRECT_LU a pogrammer */ +void SPX_AppliquerLesEtaVecteursTransposee( PROBLEME_SPX * Spx, + double * U /* Second membre et resultat */, + int * IndexDesTermesNonNuls, + int * NombreDeTermesNonNuls, + char CalculEnHyperCreux, + char TypeDeStockage /* COMPACT_LU + ADRESSAGE_INDIRECT_LU + VECTEUR_LU */ + ) +{ +int k; int il; int ilMax; double S; int * EtaDeb; int * EtaNbTerm; +int * EtaIndiceLigne; int * EtaColonne; double * EtaMoins1Valeur; + +int j; int NbN; int Col; int * Marqueur; double * W; + +EtaDeb = Spx->EtaDeb; +EtaNbTerm = Spx->EtaNbTerm; +EtaIndiceLigne = Spx->EtaIndiceLigne; +EtaColonne = Spx->EtaColonne; +EtaMoins1Valeur = Spx->EtaMoins1Valeur; + +if ( CalculEnHyperCreux == OUI_SPX ) { + if ( TypeDeStockage == COMPACT_LU ) goto HyperCreux; + if ( TypeDeStockage == ADRESSAGE_INDIRECT_LU ) { + printf("Attention TypeDeStockage = ADRESSAGE_INDIRECT_LU pas teste dans SPX_AppliquerLesEtaVecteursTransposee\n"); + goto HyperCreux; + } + else if ( TypeDeStockage != VECTEUR_LU ) { + printf("AppliquerLesEtaVecteursTransposee: type de stockage non gere\n"); + exit(0); + } +} + +k = Spx->NombreDeChangementsDeBase - 1; +while ( k >= 0 ) { + il = EtaDeb[k]; + ilMax = il + EtaNbTerm[k]; + S = 0.; + while ( il < ilMax ) { + S+= EtaMoins1Valeur[il] * U[EtaIndiceLigne[il]]; + il++; + } + /* Colonne egal aussi contrainte pour le terme diagonal */ + U[EtaColonne[k]] = S; + k--; +} +return; + +HyperCreux: + +# if CONTROLE_RAZ_DES_VECTEURS == OUI_SPX + for ( j = 0 ; j < Spx->NombreDeContraintes ; j++ ) { + if ( Spx->AReduit[j] != 0 ) { + printf("AppliquerLesEtaVecteursTransposee: Spx->AReduit[%d] = %e\n",j,Spx->AReduit[j]); + exit(0); + } + if ( Spx->Marqueur[j] != -1 ) { + printf("AppliquerLesEtaVecteursTransposee: Spx->Marqueur[%d] = %d\n",j,Spx->Marqueur[j]); + exit(0); + } + } +# endif + +Marqueur = Spx->Marqueur; + +NbN = *NombreDeTermesNonNuls; + +if ( TypeDeStockage == COMPACT_LU ) { + /* On expand */ + W = Spx->AReduit; + for ( j = 0 ; j < NbN ; j++ ) { + Col = IndexDesTermesNonNuls[j]; + W[Col] = U[j]; + Marqueur[Col] = 1; + } +} +else { + W = U; + for ( j = 0 ; j < NbN ; j++ ) Marqueur[IndexDesTermesNonNuls[j]] = 1; +} + +k = Spx->NombreDeChangementsDeBase - 1; +while ( k >= 0 ) { + il = EtaDeb[k]; + ilMax = il + EtaNbTerm[k]; + S = 0.; + while ( il < ilMax ) { + S+= EtaMoins1Valeur[il] * W[EtaIndiceLigne[il]]; + il++; + } + /* Colonne egal aussi contrainte pour le terme diagonal */ + Col = EtaColonne[k]; + if ( S != 0.0 ) { + W[Col] = S; + if ( Marqueur[Col] == -1 ) { + Marqueur[Col] = 1; + IndexDesTermesNonNuls[NbN] = Col; + NbN++; + } + } + else W[Col] = 0.0; + k--; +} + +if ( TypeDeStockage == COMPACT_LU ) { + /* On recompacte */ + for ( j = 0 ; j < NbN ; j++ ) { + Col = IndexDesTermesNonNuls[j]; + U[j] = W[Col]; + W[Col] = 0; + Marqueur[Col] = -1; + } +} +else { + for ( j = 0 ; j < NbN ; j++ ) Marqueur[IndexDesTermesNonNuls[j]] = -1; +} + +*NombreDeTermesNonNuls = NbN; + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_bruitage_initial_des_couts.c b/src/ext/Sirius_Solver/simplexe/spx_bruitage_initial_des_couts.c new file mode 100644 index 0000000000..35fad079e2 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_bruitage_initial_des_couts.c @@ -0,0 +1,95 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Bruitage intial des couts + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_BruitageInitialDesCouts( PROBLEME_SPX * Spx ) +{ +int Var; double Random; double RandomMax; double RandomMin; double * C; char * TypeDeVariable; +double * SeuilDAmissibiliteDuale; double CoutMoyen; int NbCoutsNonNuls; double RdSup; +double EcartMoyen; double * Xmin; double * Xmax; + +C = Spx->C; +TypeDeVariable = Spx->TypeDeVariable; +Xmin = Spx->Xmin; +Xmax = Spx->Xmax; +CoutMoyen = 0; +EcartMoyen = 0; +NbCoutsNonNuls = 0; +Spx->CoutMoyen = 0; +Spx->EcartDeBornesMoyen = 0; +Spx->PerturbationMax = 10; +/* Calcul du cout moyen sur les couts non nuls */ +for ( Var = 0 ; Var < Spx->NombreDeVariablesNatives ; Var++ ) { + if ( TypeDeVariable[Var] == NON_BORNEE ) continue; + if ( C[Var] != 0 ) { + CoutMoyen += fabs( C[Var] ); + NbCoutsNonNuls++; + if ( TypeDeVariable[Var] == BORNEE ) EcartMoyen += Xmax[Var] - Xmin[Var]; + else EcartMoyen += 1000; + } +} +if ( NbCoutsNonNuls != 0 ) { + CoutMoyen /= NbCoutsNonNuls; + Spx->CoutMoyen = CoutMoyen; + EcartMoyen /= NbCoutsNonNuls; + Spx->EcartDeBornesMoyen = EcartMoyen; + Spx->PerturbationMax = 0.0001 * Spx->CoutMoyen * Spx->EcartDeBornesMoyen; +} + +# if FAIRE_UN_BRUITAGE_INITIAL_DES_COUTS != OUI_SPX + return; +# endif + +SeuilDAmissibiliteDuale = Spx->SeuilDAmissibiliteDuale1; + +Spx->LesCoutsOntEteModifies = OUI_SPX; + +RdSup = SEUIL_ADMISSIBILITE_DUALE_2; + +for ( Var = 0 ; Var < Spx->NombreDeVariablesNatives ; Var++ ) { + if ( C[Var] == 0 ) continue; + if ( TypeDeVariable[Var] == NON_BORNEE ) continue; + Spx->A1 = PNE_Rand( Spx->A1 ); /* Nombre aleatoire entre 0 et 1 */ + + RandomMax = SeuilDAmissibiliteDuale[Var]; + if ( RandomMax > RdSup ) RandomMax = RdSup; + + RandomMin = -RandomMax; + + Random = RandomMin; + Random += Spx->A1 * ( RandomMax - RandomMin ); + + C[Var] += Random; +} + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_calcul_MIR_pour_gomory_et_intersection.c b/src/ext/Sirius_Solver/simplexe/spx_calcul_MIR_pour_gomory_et_intersection.c new file mode 100644 index 0000000000..9ae0f9008e --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calcul_MIR_pour_gomory_et_intersection.c @@ -0,0 +1,400 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul d'une mir sur les donnees preparees pour le calcul + des Gomory et des coupes d'intersection + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_define.h" +# include "pne_fonctions.h" + +# include "lu_define.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +# define AJUSTER_SECOND_MEMBRE OUI_SPX /* Correction du second membre au cas ou on ecrete un coefficient */ +# define NOMBRE_MAX_DE_VARIABLES_DECART_DE_COUPES 10 /* Seuil du nombre de variables d'ecart de coupes au dela duquel on + ne prend pas en compte la coupe qu'on est en train de calculer */ + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculMIRPourCoupeDeGomoryOuIntersection( + PROBLEME_SPX * Spx, + + double RapportMaxDesCoeffs, + double ZeroPourCoeffVariablesDEcart, + double ZeroPourCoeffVariablesNatives, + double RelaxRhsAbs, + double RelaxRhsRel, + + double AlphaI0, + double * B, + /* Pour calculs intermediaires */ + char * T, + double * Coeff, + char * LaVariableSpxEstEntiere, + + /* En retour, la coupe */ + int * NombreDeTermes , /* Nombre de coefficients non nuls dans la coupe */ + double * Coefficient , /* Coefficients de la contrainte */ + int * IndiceDeLaVariable , /* Indices des variables qui interviennent dans la coupe */ + double * SecondMembre, /* Remarque: la coupe est toujours dans le sens <= SecondMembre */ + char * OnAEcrete ) +{ +int VarSpx ; int Var2Spx ; double F0; double F0SurUnMoinsF0; double Fj; double NBarreR; int Cnt; +int il; int ilMax; double Co; double BGomory; double ValeurDuZero; double PlusPetitTerme; +double PlusGrandTerme; double SeuilGrandesBornes; double CoSpx; int * Cdeb; double * ACol; +int * CNbTerm; int * NumeroDeContrainte; char * OrigineDeLaVariable; int NumCoupe; double BG0; +char * PositionDeLaVariable; double * ScaleX; double * XminEntree; double * XmaxEntree; double * Xmax; +double * Xmin; int * Mdeb; int * NbTerm;int * Indcol; double * A; double ScaleSpx; +int * CorrespondanceVarSimplexeVarEntree; char * TypeDeVariable; int NbVarEcartDeCoupes; +int * CorrespondanceCntSimplexeCntEntree; int NombreDeContraintesDuProblemeSansCoupes; +int NbCorrectionsImpossibles; double CumulCorrections; int NN; double PlusPetitTermeDeLaMatrice; +double PlusGrandTermeDeLaMatrice; double RapportCoupe; int i; + +PROBLEME_PNE * Pne; + +*OnAEcrete = NON_SPX; +*NombreDeTermes = 0; + +Pne = NULL; +Pne = (PROBLEME_PNE *) Spx->ProblemePneDeSpx; + +ValeurDuZero = ZERO_TERMES_DU_TABLEAU_POUR_GOMORY; + +NbVarEcartDeCoupes = 0; + +SeuilGrandesBornes = RapportMaxDesCoeffs; + +ACol = Spx->ACol; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +OrigineDeLaVariable = Spx->OrigineDeLaVariable; +PositionDeLaVariable = Spx->PositionDeLaVariable; +TypeDeVariable = Spx->TypeDeVariable; +ScaleX = Spx->ScaleX; +XminEntree = Spx->XminEntree; +XmaxEntree = Spx->XmaxEntree; +Xmax = Spx->Xmax; +Xmin = Spx->Xmin; + +NombreDeContraintesDuProblemeSansCoupes = Spx->NombreDeContraintesDuProblemeSansCoupes; +CorrespondanceCntSimplexeCntEntree = Spx->CorrespondanceCntSimplexeCntEntree; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; +TypeDeVariable = Spx->TypeDeVariable; +CorrespondanceVarSimplexeVarEntree = Spx->CorrespondanceVarSimplexeVarEntree; + +F0 = AlphaI0 - floor( AlphaI0 ); +BGomory = F0; + +/* Test de division par 0 */ +if ( fabs( 1. - F0 ) > ZERO_GOMORY_1_F0 ) { + F0SurUnMoinsF0 = F0 / ( 1. - F0 ); +} +else return; + +/* On applique les regles d'arrondi */ +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + if ( T[VarSpx] == 0 ) continue; + NBarreR = Coeff[VarSpx]; + if ( OrigineDeLaVariable[VarSpx] == ECART ) { + /* C'est une variable d'ecart non connue de l'appelant, on considere qu'elle est reelle. */ + if ( NBarreR > 0. ) Co = NBarreR; + else Co = -NBarreR * F0SurUnMoinsF0; + /* Si le coeff de la variable d'ecart est trop petit, on n'en tient pas compte */ + if ( fabs( Co ) < ZeroPourCoeffVariablesDEcart && 0 ) { + T[VarSpx] = 0; + continue; + } + } + else { + /* C'est une variable connue de l'appelant */ + if ( LaVariableSpxEstEntiere[VarSpx] == OUI_SPX ) { + Fj = NBarreR - floor( NBarreR ); + if ( Fj <= F0 ) Co = Fj; + else Co = F0SurUnMoinsF0 * ( 1. - Fj ); + } + else { /* Cas d'une variable reelle */ + if ( NBarreR > 0. ) Co = NBarreR; + else Co = -NBarreR * F0SurUnMoinsF0; + } + } + /* Si le coeff de la variable native est trop petit, on n'en tient pas compte */ + /* Pour faire ce test on se replace dans le contexte du simplexe apres scaling quand on utilisera a coupe */ + CoSpx = fabs( Co ) * ScaleX[VarSpx]; + if ( CoSpx < ZeroPourCoeffVariablesNatives && 0 ) { + if ( CoSpx > 0.1 * ZeroPourCoeffVariablesNatives ) *OnAEcrete = OUI_SPX; + T[VarSpx] = 0; + # if AJUSTER_SECOND_MEMBRE == OUI_SPX + /* Il faut ajuster le second membre */ + if ( TypeDeVariable[VarSpx] == BORNEE ) { + if ( Xmax[VarSpx] - Xmin[VarSpx] < SeuilGrandesBornes ) { + if ( LaVariableSpxEstEntiere[VarSpx] == OUI_SPX ) { + /* La variable est entiere. Si elle a ete instanciee a 0, l'information HORS_BASE_SUR_BORNE_INF ou + HORS_BASE_SUR_BORNE_SUP ne joue pas. Si elle a ete instanciee a 1 alors c'est comme si elle + etait HORS_BASE_SUR_BORNE_SUP */ + if ( XminEntree[VarSpx] == XmaxEntree[VarSpx] ) { + if ( XminEntree[VarSpx] != 0. ) Co = -Co; + } + } + if ( Co > 0.0 ) BGomory -= Co * ScaleX[VarSpx] * Xmax[VarSpx]; + else BGomory -= Co * ScaleX[VarSpx] * Xmin[VarSpx]; + } + } + # endif + continue; + } + /* Le coeff est pris en compte */ + Coeff[VarSpx] = Co; + if ( LaVariableSpxEstEntiere[VarSpx] == OUI_SPX ) { + /* La variable est entiere. Si elle a ete instanciee a 0, l'information HORS_BASE_SUR_BORNE_INF ou + HORS_BASE_SUR_BORNE_SUP ne joue pas. Si elle a ete instanciee a 1 alors c'est comme si elle + etait HORS_BASE_SUR_BORNE_SUP */ + if ( XminEntree[VarSpx] == XmaxEntree[VarSpx] ) { + /* C'est une variable instanciee */ + if ( XminEntree[VarSpx] == 0. ) continue; + BGomory -= Coeff[VarSpx] * Xmax[VarSpx] * ScaleX[VarSpx]; + Coeff[VarSpx] = -Coeff[VarSpx]; + continue; + } + } + if ( PositionDeLaVariable[VarSpx] == HORS_BASE_SUR_BORNE_SUP ) { + /* Remarque: une variable d'ecart ne peut pas etre HORS_BASE_SUR_BORNE_SUP */ + /* On refait les changements de variables necessaires Xtilde = Xmax - X */ + BGomory -= Coeff[VarSpx] * Xmax[VarSpx] * ScaleX[VarSpx]; + Coeff[VarSpx] = -Coeff[VarSpx]; + } +} + +/* Cas ou le probleme Pne n'est pas sous la forme standard: on trazouille la contrainte pour que si une variable d'ecart etait + dans la contrainte, on la remplace par des variables connues du niveau "pne" */ + +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + if ( T[VarSpx] == 0 ) continue; + if ( OrigineDeLaVariable[VarSpx] != ECART ) continue; + + /* Var est une variable non native et elle fait partie de la coupe de Gomory */ + T[VarSpx] = 0; + Co = Coeff[VarSpx]; + ScaleSpx = ScaleX[VarSpx]; + if ( ScaleSpx != 1. ) { + *NombreDeTermes = 0; + return; + } + /* Contrainte a laquelle appartient la variable d'ecart */ + Cnt = NumeroDeContrainte[Cdeb[VarSpx]]; + /* C'est une coupe ? */ + if ( Cnt >= NombreDeContraintesDuProblemeSansCoupes && Pne != NULL ) { + NumCoupe = CorrespondanceCntSimplexeCntEntree[Cnt] - NombreDeContraintesDuProblemeSansCoupes; + if ( Pne->Coupes.NbTerm[NumCoupe] > 0 ) { + if ( Pne->Coupes.TypeDeCoupe[NumCoupe] == 'G' || Pne->Coupes.TypeDeCoupe[NumCoupe] == 'I' ) { + /* Si c'est une Gomory ou derivee de Gomory, on incremente le compteur */ + NbVarEcartDeCoupes++; + if ( NbVarEcartDeCoupes > NOMBRE_MAX_DE_VARIABLES_DECART_DE_COUPES ) { + *NombreDeTermes = 0; + return; + } + } + } + } + /* Remplacement de la variable d'ecart: la variable d'ecart est toujours la derniere variable */ + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + ilMax--; + while ( il < ilMax ) { + Var2Spx = Indcol[il]; + /* Ici il n'y a pas lieu de tenir compte du fait que la variable serait HORS_BASE_SUR_BORNE_SUP */ + T[Var2Spx] = 1; + Coeff[Var2Spx] -= Co * A[il] * ScaleSpx / ScaleX[Var2Spx]; + il++; + } + /* B est avant translation (sauf pour les variables entieres ou on a remis toujours xmin=0) et apres scaling */ + BGomory -= Co * B[Cnt] * ScaleSpx; +} + +/* Il faut maintenant tenir compte de la translation des bornes */ + +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + if ( T[VarSpx] == 0 ) continue; + /* Translation des bornes */ + if ( TypeDeVariable[VarSpx] == BORNEE || TypeDeVariable[VarSpx] == BORNEE_INFERIEUREMENT ) { + /* Translation des bornes */ + if ( LaVariableSpxEstEntiere[VarSpx] == OUI_SPX ) continue; + BGomory += Coeff[VarSpx] * XminEntree[VarSpx]; + } +} + +/* Decompte du nombre de termes, attribution des numeros de variables connus de la partie pne + et transformation de la contrainte en une contrainte de type < */ + +PlusPetitTerme = LINFINI_SPX; +PlusGrandTerme = -1.; +*NombreDeTermes = 0; + +CumulCorrections = 0.0; +NbCorrectionsImpossibles = 0; +BG0 = BGomory; +NN = 0; + +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + if ( T[VarSpx] == 0 ) continue; + T[VarSpx] = 0; + NN++; + /* Si le coeff de la variable native est trop petit, on n'en tient pas compte */ + /* Pour faire ces test on se replace dans le contexte du simplexe apres scaling quand on utilisera a coupe */ + CoSpx = fabs( Coeff[VarSpx] ) * ScaleX[VarSpx]; + if ( CoSpx < ZeroPourCoeffVariablesNatives ) { + if ( CoSpx > 0.1 * ZeroPourCoeffVariablesNatives ) *OnAEcrete = OUI_SPX; + # if AJUSTER_SECOND_MEMBRE == OUI_SPX + /* Il faut ajuster le second membre */ + if ( TypeDeVariable[VarSpx] == BORNEE ) { + if ( Xmax[VarSpx] - Xmin[VarSpx] < SeuilGrandesBornes ) { + if ( Coeff[VarSpx] > 0.0 ) { + Co = Coeff[VarSpx] * ScaleX[VarSpx] * Xmax[VarSpx]; + /* Il n'est pas clair s'il est interessant ou non de faire une correction */ + BGomory -= Co; + CumulCorrections += fabs( Co ); + } + else { + Co = Coeff[VarSpx] * ScaleX[VarSpx] * Xmin[VarSpx]; + /* Il n'est pas clair s'il est interessant ou non de faire une correction */ + BGomory -= Co; + CumulCorrections += fabs( Co ); + } + } + else { + if ( CoSpx != 0.0 ) NbCorrectionsImpossibles++; + } + } + # else + if ( TypeDeVariable[VarSpx] == BORNEE ) { + if ( Xmax[VarSpx] - Xmin[VarSpx] < SeuilGrandesBornes ) { + if ( Coeff[VarSpx] > 0.0 ) { + Co = Coeff[VarSpx] * ScaleX[VarSpx] * Xmax[VarSpx]; + CumulCorrections += fabs( Co ); + } + else { + Co = Coeff[VarSpx] * ScaleX[VarSpx] * Xmin[VarSpx]; + CumulCorrections += fabs( Co ); + } + } + else { + if ( CoSpx != 0.0 ) NbCorrectionsImpossibles++; + } + } + # endif + continue; + } + if ( CoSpx < PlusPetitTerme ) PlusPetitTerme = CoSpx; + if ( CoSpx > PlusGrandTerme ) PlusGrandTerme = CoSpx; + Coefficient[*NombreDeTermes] = -Coeff[VarSpx]; /* Pour la transformation en une contrainte de type < */ + IndiceDeLaVariable[*NombreDeTermes] = CorrespondanceVarSimplexeVarEntree[VarSpx]; + *NombreDeTermes = *NombreDeTermes + 1; +} + +if ( fabs( BGomory ) > ZERO_TERMES_DU_TABLEAU_POUR_GOMORY ) { + if ( fabs( CumulCorrections / BG0 ) > 1.e-8 ) { + *NombreDeTermes = 0; + } +} +if ( CumulCorrections > 1.e-8 ) { + *NombreDeTermes = 0; +} +if ( NbCorrectionsImpossibles > 0.1 * NN ) { + /* Trop de corrections impossibles */ + *NombreDeTermes = 0; +} + +if ( *NombreDeTermes <= 0 ) return; + +/* Modification du RapportMaxDesCoeffs en fonction du scaling */ +if ( RapportMaxDesCoeffs < Spx->RapportDeScaling ) RapportMaxDesCoeffs = Spx->RapportDeScaling; + +PlusPetitTermeDeLaMatrice = Spx->PlusPetitTermeDeLaMatrice; +PlusGrandTermeDeLaMatrice = Spx->PlusGrandTermeDeLaMatrice; + +if ( PlusGrandTerme/PlusPetitTerme > RapportMaxDesCoeffs ) { + /* + printf("Refus calcul de G car Rapport %e et RapportMaxDesCoeffs = %e NombreDeTermes = %d\n",PlusGrandTerme/PlusPetitTerme, + RapportMaxDesCoeffs,*NombreDeTermes); + */ + *NombreDeTermes = 0; + return; +} + +if ( *OnAEcrete == OUI_SPX ) { + if ( PlusGrandTerme < RapportMaxDesCoeffs * ZeroPourCoeffVariablesNatives ) { + /* + printf("Refus calcul de G car PlusGrandTerme %e OnAEcrete\n",PlusGrandTerme); + */ + *NombreDeTermes = 0; + return; + } +} + +/* On recale la contrainte sur le plus petit et plus grand terme de la matrice */ +RapportCoupe = 1.; +# ifdef ON_COMPILE +if ( PlusGrandTerme > PlusGrandTermeDeLaMatrice ) { + /* On fait une homothetie vers PlusGrandTermeDeLaMatrice */ + RapportCoupe = PlusGrandTermeDeLaMatrice / PlusGrandTerme; +} +else if ( PlusPetitTerme < PlusPetitTermeDeLaMatrice ) { + /* On fait une homothetie vers PlusPetitTermeDeLaMatrice */ + RapportCoupe = PlusPetitTermeDeLaMatrice / PlusPetitTerme; +} +# endif + +if ( PlusGrandTerme > PlusGrandTermeDeLaMatrice ) { + RapportCoupe = PlusGrandTermeDeLaMatrice / PlusGrandTerme; +} + +if ( RapportCoupe != 1. ) { + /*SPX_ArrondiEnPuissanceDe2( &RapportCoupe );*/ + for ( i = 0 ; i < *NombreDeTermes ; i++ ) Coefficient[i] *= RapportCoupe; + BGomory *= RapportCoupe; +} + +/* Pour la transformation en une contrainte de type < on prend -BGomory */ +Co = fabs( BGomory ) * RelaxRhsRel; +if ( Co < RelaxRhsAbs ) { + *SecondMembre = -BGomory + RelaxRhsAbs; +} +else { + *SecondMembre = -BGomory + Co; +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calcul_borne_auxiliaire.c b/src/ext/Sirius_Solver/simplexe/spx_calcul_borne_auxiliaire.c new file mode 100644 index 0000000000..4cf62fec25 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calcul_borne_auxiliaire.c @@ -0,0 +1,143 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul d'une borne auxiliaire pour rendre une variable + duale admissible. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define INF_XMAX 100. + +/*----------------------------------------------------------------------------*/ + +# ifdef UTILISER_BORNES_AUXILIAIRES + +/*----------------------------------------------------------------------------*/ +/* Utilisation de bornes auxilaires pour forcer l'admissibilite duale */ +double SPX_CalculerUneBorneAuxiliaire( PROBLEME_SPX * Spx , int Var ) +{ +double Amoy; int il; int ilMax; int * Cdeb; int * CNbTerm; int Cnt; double Smin; +double Xmax; double * ACol; int * NumeroDeContrainte; double NormeL1deB; int Var1; +double NormeL1deA; double * B; double Xmx1; double Xmx2; char * TypeDeVariable; +int * Indcol; double * A; double * Xi; double * Xs; + +B = Spx->B; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +ACol = Spx->ACol; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +/* On regarde si on dispose d'une borne auxiliaire */ +if ( Spx->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + if ( Spx->StatutBorneSupAuxiliaire[Var] == BORNE_AUXILIAIRE_PRESOLVE ) { + Xmax = Spx->BorneSupAuxiliaire[Var]; + /* Maintenant que la borne auxiliaire a ete utilisee on l'invalide pour ne plus l'utiliser */ + Spx->StatutBorneSupAuxiliaire[Var] = BORNE_AUXILIAIRE_INVALIDE; + return( Xmax ); + } +} + +B = Spx->B; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +ACol = Spx->ACol; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +TypeDeVariable = Spx->TypeDeVariable; + +if ( Spx->OrigineDeLaVariable[Var] == ECART ) goto VariableDEcart; + +il = Cdeb[Var]; +ilMax = il + CNbTerm[Var]; +Amoy = 0.0; +NormeL1deB = 0.0; +NormeL1deA = 0.0; +while ( il < ilMax ) { + NormeL1deB+= fabs( B[NumeroDeContrainte[il]] ); + NormeL1deA+= fabs( ACol[il] ); + Amoy+= fabs( ACol[il] ); + il++; +} +Amoy/= CNbTerm[Var]; +Xmx1 = (1. + Spx->ValeurMoyenneDuSecondMembre ) / ( 1. + Amoy ); +Xmx2 = (1. + NormeL1deB ) / ( 1. + NormeL1deA ); +if ( Xmx1 > Xmx2 ) Xmax = Xmx1; +else Xmax = Xmx2; + +goto Fin; + +VariableDEcart: +/* Variable d'ecart */ +Indcol = Spx->Indcol; +A = Spx->A; +Xi = Spx->Xmin; +Xs = Spx->Xmax; +Cnt = NumeroDeContrainte[Cdeb[Var]]; +il = Spx->Mdeb[Cnt]; +ilMax = il + Spx->NbTerm[Cnt] - 1; +Smin = 0; +while ( il < ilMax ) { + Var1 = Indcol[il]; + if ( A[il] > 0 ) { + /* On place la variable au min */ + if ( TypeDeVariable[Var1] != VARIABLE_NON_BORNEE ) { + Smin += A[il] * Xi[Var1]; + } + else { + Smin += A[il] * (-1.e+6); + } + } + else if ( A[il] < 0 ) { + /* On place la variable au max */ + if ( TypeDeVariable[Var1] != VARIABLE_NON_BORNEE && TypeDeVariable[Var1] != VARIABLE_BORNEE_INFERIEUREMENT ) { + Smin += A[il] * Xs[Var1]; + } + else Smin += A[il] * 1.e+6; + } + il++; +} +Xmax = fabs( B[Cnt] - Smin ); +Xmax += 10.; /* Pour qu'elle soit plutot en base plutot que sur borne sup */ +if ( Xmax > 1.e+7 ) Xmax = 1.e+7; + +Fin: + +if ( TypeDeVariable[Var] == NON_BORNEE ) Xmax *= 2.0; +Xmax *= (double) Spx->CoeffMultiplicateurDesBornesAuxiliaires; + +if ( Xmax < INF_XMAX ) Xmax = INF_XMAX; + +return( Xmax ); + +} + +# endif + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calcul_coupes_dintersection.c b/src/ext/Sirius_Solver/simplexe/spx_calcul_coupes_dintersection.c new file mode 100644 index 0000000000..cd1b90afd3 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calcul_coupes_dintersection.c @@ -0,0 +1,799 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul des coupes d'intersection. + + AUTEUR: R. GONZALEZ + +************************************************************************/ +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_define.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +# define ZERO_DE_NORME_AU_CARRE 1.e-15 /* 1.e-10 c'est a dire (1.e-5 * 1.e-5) */ +# define SEUIL_DE_REDUCTION_AU_CARRE 0.81 /* 0.64 c'est a dire (0.8 * 0.8) */ +# define DELTAOPT_MIN 1.e-6 /*1.e-5 */ +# define DELTAOPT_MAX 1.e+2 /*1.e+2*/ +# define NOMBRE_MAX_DE_CYCLES 10 /*5*/ /*10*/ + +/*----------------------------------------------------------------------------*/ + +void SPX_InitCoupesDIntersection( PROBLEME_SPX * Spx , char * LaVariableSpxEstEntiere , + double * B ) +{ +int VarSpx; int Cnt; +DONNEES_POUR_COUPES_DINTERSECTION * DonneesPourCoupesDIntersection; + +Spx->DonneesPourCoupesDIntersection = (DONNEES_POUR_COUPES_DINTERSECTION *) malloc( sizeof( DONNEES_POUR_COUPES_DINTERSECTION ) ); +if ( Spx->DonneesPourCoupesDIntersection == NULL ) { + Spx->CoupesDintersectionAllouees = NON_SPX; + return; +} + +DonneesPourCoupesDIntersection = Spx->DonneesPourCoupesDIntersection; + +DonneesPourCoupesDIntersection->NombreDeVariables = 0; +DonneesPourCoupesDIntersection->LigneDeProduitScalaire = NULL; +DonneesPourCoupesDIntersection->LigneDeMatrice = NULL; +DonneesPourCoupesDIntersection->NormeAvantReduction = NULL; + +DonneesPourCoupesDIntersection->Vecteur = (double *) malloc( Spx->NombreDeVariables * sizeof( double ) ); +DonneesPourCoupesDIntersection->LaVariableSpxEstEntiere = (char *) malloc( Spx->NombreDeVariables * sizeof( char ) ); +DonneesPourCoupesDIntersection->B = (double *) malloc( Spx->NombreDeContraintes * sizeof( double ) ); +DonneesPourCoupesDIntersection->XmaxSv = (double *) malloc( Spx->NombreDeVariables * sizeof( double ) ); +if ( DonneesPourCoupesDIntersection->Vecteur == NULL || /*DonneesPourCoupesDIntersection->T == NULL ||*/ + DonneesPourCoupesDIntersection->LaVariableSpxEstEntiere == NULL || DonneesPourCoupesDIntersection->B == NULL || + DonneesPourCoupesDIntersection->XmaxSv == NULL ) { + free( DonneesPourCoupesDIntersection->Vecteur ); + free( DonneesPourCoupesDIntersection->LaVariableSpxEstEntiere ); + free( DonneesPourCoupesDIntersection->B ); + free( DonneesPourCoupesDIntersection->XmaxSv ); + Spx->CoupesDintersectionAllouees = NON_SPX; + return; +} + +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + DonneesPourCoupesDIntersection->LaVariableSpxEstEntiere[VarSpx] = LaVariableSpxEstEntiere[VarSpx]; +} + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + DonneesPourCoupesDIntersection->B[Cnt] = B[Cnt]; +} + +DonneesPourCoupesDIntersection->TSpx = (char *) malloc( Spx->NombreDeVariables * sizeof( char ) ); +DonneesPourCoupesDIntersection->CoeffSpx = (double *) malloc( Spx->NombreDeVariables * sizeof( double ) ); +if ( DonneesPourCoupesDIntersection->TSpx == NULL || DonneesPourCoupesDIntersection->CoeffSpx == NULL ) { + free( DonneesPourCoupesDIntersection->Vecteur ); + free( DonneesPourCoupesDIntersection->LaVariableSpxEstEntiere ); + free( DonneesPourCoupesDIntersection->B ); + free( DonneesPourCoupesDIntersection->XmaxSv ); + free( DonneesPourCoupesDIntersection->TSpx ); + free( DonneesPourCoupesDIntersection->CoeffSpx ); + Spx->CoupesDintersectionAllouees = NON_SPX; + return; +} + +Spx->CoupesDintersectionAllouees = OUI_SPX; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_TerminerLeCalculDesCoupesDIntersection( PROBLEME_SPX * Spx ) +{ +int i; int VarSpx; DONNEES_POUR_COUPES_DINTERSECTION * DonneesPourCoupesDIntersection; +LIGNE_DE_MATRICE * LigneDeMatrice; +LIGNE_DE_PRODUITS_SCALAIRES * LigneDeProduitScalaire; + +if ( Spx->CoupesDintersectionAllouees == NON_SPX ) return; + +DonneesPourCoupesDIntersection = Spx->DonneesPourCoupesDIntersection; + +if ( DonneesPourCoupesDIntersection->XmaxSv != NULL ) { + for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + Spx->Xmax[VarSpx] = DonneesPourCoupesDIntersection->XmaxSv[VarSpx]; + } +} + +for ( i = 0 ; i < DonneesPourCoupesDIntersection->NombreDeVariables ; i++ ) { + LigneDeMatrice = DonneesPourCoupesDIntersection->LigneDeMatrice[i]; + free( LigneDeMatrice->NumeroDeVariableSpx ); + free( LigneDeMatrice->Coefficient ); + free( LigneDeMatrice ); + LigneDeProduitScalaire = DonneesPourCoupesDIntersection->LigneDeProduitScalaire[i]; + free( LigneDeProduitScalaire->NumeroDeVariableMatrice ); + free( LigneDeProduitScalaire->ProduitScalaire ); + free( LigneDeProduitScalaire ); +} + +free( DonneesPourCoupesDIntersection->Vecteur ); +free( DonneesPourCoupesDIntersection->LaVariableSpxEstEntiere ); +free( DonneesPourCoupesDIntersection->B ); +free( DonneesPourCoupesDIntersection->LigneDeProduitScalaire ); +free( DonneesPourCoupesDIntersection->LigneDeMatrice ); +free( DonneesPourCoupesDIntersection->NormeAvantReduction ); +free( DonneesPourCoupesDIntersection->XmaxSv ); +free( DonneesPourCoupesDIntersection->TSpx ); +free( DonneesPourCoupesDIntersection->CoeffSpx ); +free( DonneesPourCoupesDIntersection ); + +Spx->CoupesDintersectionAllouees = NON_SPX; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_AllocLignePourCoupesDIntersection( PROBLEME_SPX * Spx ) +{ +int i; DONNEES_POUR_COUPES_DINTERSECTION * DonneesPourCoupesDIntersection; + +if ( Spx->CoupesDintersectionAllouees == NON_SPX ) return; + +DonneesPourCoupesDIntersection = Spx->DonneesPourCoupesDIntersection; + +i = DonneesPourCoupesDIntersection->NombreDeVariables; +if ( i <= 0 ) { + DonneesPourCoupesDIntersection->LigneDeProduitScalaire = (LIGNE_DE_PRODUITS_SCALAIRES **) malloc( (i+1) * sizeof( void * ) ); + DonneesPourCoupesDIntersection->LigneDeMatrice = (LIGNE_DE_MATRICE **) malloc( (i+1) * sizeof( void * ) ); + DonneesPourCoupesDIntersection->NormeAvantReduction = (double *) malloc( (i+1) * sizeof( double ) ); +} +else { + DonneesPourCoupesDIntersection->LigneDeProduitScalaire = + (LIGNE_DE_PRODUITS_SCALAIRES **) realloc( DonneesPourCoupesDIntersection->LigneDeProduitScalaire , (i+1) * sizeof( void * ) ); + DonneesPourCoupesDIntersection->LigneDeMatrice = + (LIGNE_DE_MATRICE **) realloc( DonneesPourCoupesDIntersection->LigneDeMatrice , (i+1) * sizeof( void * ) ); + DonneesPourCoupesDIntersection->NormeAvantReduction = + (double *) realloc( DonneesPourCoupesDIntersection->NormeAvantReduction , (i+1) * sizeof( double ) ); +} +if ( DonneesPourCoupesDIntersection->LigneDeProduitScalaire == NULL || + DonneesPourCoupesDIntersection->LigneDeMatrice == NULL || + DonneesPourCoupesDIntersection->NormeAvantReduction == NULL ) { + free( DonneesPourCoupesDIntersection->LigneDeProduitScalaire ); + free( DonneesPourCoupesDIntersection->LigneDeMatrice ); + free( DonneesPourCoupesDIntersection->NormeAvantReduction ); + Spx->CoupesDintersectionAllouees = NON_SPX; + return; +} + +DonneesPourCoupesDIntersection->LigneDeProduitScalaire[i] = (LIGNE_DE_PRODUITS_SCALAIRES *) malloc( sizeof( LIGNE_DE_PRODUITS_SCALAIRES ) ); +DonneesPourCoupesDIntersection->LigneDeMatrice[i] = (LIGNE_DE_MATRICE *) malloc( sizeof( LIGNE_DE_MATRICE ) ); +if ( DonneesPourCoupesDIntersection->LigneDeProduitScalaire[i] == NULL || DonneesPourCoupesDIntersection->LigneDeMatrice[i] == NULL ) { + free( DonneesPourCoupesDIntersection->LigneDeProduitScalaire[i] ); + free( DonneesPourCoupesDIntersection->LigneDeMatrice[i] ); + Spx->CoupesDintersectionAllouees = NON_SPX; + return; +} + +DonneesPourCoupesDIntersection->LigneDeProduitScalaire[i]->NombreDeTermes = 0; +DonneesPourCoupesDIntersection->LigneDeProduitScalaire[i]->NumeroDeVariableMatrice = NULL; +DonneesPourCoupesDIntersection->LigneDeProduitScalaire[i]->ProduitScalaire = 0; + +DonneesPourCoupesDIntersection->LigneDeMatrice[i]->NombreDeTermes = 0; +DonneesPourCoupesDIntersection->LigneDeMatrice[i]->NumeroDeVariableSpx = NULL; +DonneesPourCoupesDIntersection->LigneDeMatrice[i]->Coefficient = NULL; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_MatriceCoupesDIntersection( PROBLEME_SPX * Spx ) +{ +char * T; double * Coeff; double SecondMembre; int NbVarCont; +int i; int VarSpx; int NbVar; int NbTermes; double X; char OnStocke; +int * NumeroDeVariableSpx; double * Coefficient; +DONNEES_POUR_COUPES_DINTERSECTION * DonneesPourCoupesDIntersection; +LIGNE_DE_MATRICE * LigneDeMatrice; int il; double * Vecteur; +LIGNE_DE_PRODUITS_SCALAIRES * LigneDeProduitScalaire; char * LaVariableSpxEstEntiere; + +if ( Spx->CoupesDintersectionAllouees == NON_SPX ) return; + +DonneesPourCoupesDIntersection = Spx->DonneesPourCoupesDIntersection; + +SecondMembre = DonneesPourCoupesDIntersection->AlphaI0; +/* T et Coeff sont mis a jour par le simplexe */ +T = DonneesPourCoupesDIntersection->TSpx; +Coeff = DonneesPourCoupesDIntersection->CoeffSpx; + +LaVariableSpxEstEntiere = DonneesPourCoupesDIntersection->LaVariableSpxEstEntiere; + +/* Decompte prealable du nombre de termes */ +NbVarCont = 0; +NbTermes = 0; +OnStocke = NON_SPX; +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + if ( T[VarSpx] != 0 ) { + if ( LaVariableSpxEstEntiere[VarSpx] == NON_SPX ) { + OnStocke = OUI_SPX; + NbVarCont++; + } + NbTermes++; + } +} +if ( OnStocke == NON_SPX ) return; +if ( NbVarCont < (int) ceil( 0.01 * NbTermes ) ) return; + +SPX_AllocLignePourCoupesDIntersection( Spx ); +if ( Spx->CoupesDintersectionAllouees == NON_SPX ) return; + +NbVar = DonneesPourCoupesDIntersection->NombreDeVariables; +Vecteur = DonneesPourCoupesDIntersection->Vecteur; +LigneDeMatrice = DonneesPourCoupesDIntersection->LigneDeMatrice[NbVar]; + +memset( (char *) Vecteur, 0, Spx->NombreDeVariables * sizeof( double ) ); + +LigneDeMatrice->SecondMembre = SecondMembre; +LigneDeMatrice->NombreDeTermes = NbTermes; + +LigneDeMatrice->Coefficient = (double *) malloc( LigneDeMatrice->NombreDeTermes * sizeof( double ) ); +LigneDeMatrice->NumeroDeVariableSpx = (int *) malloc( LigneDeMatrice->NombreDeTermes * sizeof( int ) ); +if ( LigneDeMatrice->Coefficient == NULL || LigneDeMatrice->NumeroDeVariableSpx == NULL ) { + free( LigneDeMatrice->Coefficient ); + free( LigneDeMatrice->NumeroDeVariableSpx ); + Spx->CoupesDintersectionAllouees = NON_SPX; + return; +} + +NbTermes = 0; +NumeroDeVariableSpx = LigneDeMatrice->NumeroDeVariableSpx; +Coefficient = LigneDeMatrice->Coefficient; +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + if ( T[VarSpx] != 0 ) { + NumeroDeVariableSpx[NbTermes] = VarSpx; + Coefficient[NbTermes] = Coeff[VarSpx]; + if ( LaVariableSpxEstEntiere[VarSpx] == NON_SPX ) { + Vecteur[VarSpx] = Coeff[VarSpx]; + } + NbTermes++; + } +} + +DonneesPourCoupesDIntersection->NombreDeVariables++; + +/* On fait les produits scalaires (sur les variables continues) avec les lignes qui existent deja */ + +for ( i = 0 ; i < DonneesPourCoupesDIntersection->NombreDeVariables ; i++ ) { + LigneDeMatrice = DonneesPourCoupesDIntersection->LigneDeMatrice[i]; + NumeroDeVariableSpx = LigneDeMatrice->NumeroDeVariableSpx; + Coefficient = LigneDeMatrice->Coefficient; + X = 0.0; + for ( il = 0 ; il < LigneDeMatrice->NombreDeTermes ; il++ ) { + /* remarque: Vecteur[variable entiere] = 0 */ + if ( LaVariableSpxEstEntiere[NumeroDeVariableSpx[il]] == OUI_SPX ) continue; + X+= Coefficient[il] * Vecteur[NumeroDeVariableSpx[il]]; + } + + LigneDeProduitScalaire = DonneesPourCoupesDIntersection->LigneDeProduitScalaire[i]; + + if ( LigneDeProduitScalaire->NombreDeTermes == 0 ) { + LigneDeProduitScalaire->ProduitScalaire = (double *) malloc( (LigneDeProduitScalaire->NombreDeTermes+1) * sizeof( double ) ); + LigneDeProduitScalaire->NumeroDeVariableMatrice = (int *) malloc( (LigneDeProduitScalaire->NombreDeTermes+1) * sizeof( int ) ); + } + else { + LigneDeProduitScalaire->ProduitScalaire = + (double *) realloc( LigneDeProduitScalaire->ProduitScalaire , (LigneDeProduitScalaire->NombreDeTermes+1) * sizeof( double ) ); + LigneDeProduitScalaire->NumeroDeVariableMatrice = + (int *) realloc( LigneDeProduitScalaire->NumeroDeVariableMatrice , (LigneDeProduitScalaire->NombreDeTermes+1) * sizeof( int ) ); + } + if ( LigneDeProduitScalaire->ProduitScalaire == NULL || LigneDeProduitScalaire->NumeroDeVariableMatrice == NULL ) { + free( LigneDeProduitScalaire->ProduitScalaire ); + free( LigneDeProduitScalaire->NumeroDeVariableMatrice ); + Spx->CoupesDintersectionAllouees = NON_SPX; + return; + } + + LigneDeProduitScalaire->ProduitScalaire [LigneDeProduitScalaire->NombreDeTermes] = X; + LigneDeProduitScalaire->NumeroDeVariableMatrice[LigneDeProduitScalaire->NombreDeTermes] = NbVar; + LigneDeProduitScalaire->NombreDeTermes++; + +} + + +i = DonneesPourCoupesDIntersection->NombreDeVariables - 1; +LigneDeProduitScalaire = DonneesPourCoupesDIntersection->LigneDeProduitScalaire[i]; +DonneesPourCoupesDIntersection->NormeAvantReduction[i] = LigneDeProduitScalaire->ProduitScalaire[0]; + +return; +} + +/*----------------------------------------------------------------------------*/ + +double SPX_CalculDeLaNouvelleNorme( LIGNE_DE_PRODUITS_SCALAIRES * LigneDeProduitScalaireDeDk, + LIGNE_DE_PRODUITS_SCALAIRES * LigneDeProduitScalaireDeDl, + int VariableKDansMatrice, int VariableLDansMatrice , + double DeltaOpt ) +{ +double NormeAuCarre; double DkT_Dl; int il; + +/* C'est dk^t dk + Delta dk^t dl */ +/* Recherche du produit dk^t dl */ +DkT_Dl = 0.0; +if ( VariableLDansMatrice >= VariableKDansMatrice ) { + /* Si VariableLDansMatrice >= VariableKDansMatrice on cherche DkT_Dl en balayant LigneDeProduitScalaireDeDk */ + for ( il = 0 ; il < LigneDeProduitScalaireDeDk->NombreDeTermes ; il++ ) { + if ( LigneDeProduitScalaireDeDk->NumeroDeVariableMatrice[il] == VariableLDansMatrice ) { + DkT_Dl = LigneDeProduitScalaireDeDk->ProduitScalaire[il]; + break; + } + } +} +else { + /* Si VariableLDansMatrice < VariableKDansMatrice on cherche DkT_Dl en balayant LigneDeProduitScalaireDeDl */ + for ( il = 0 ; il < LigneDeProduitScalaireDeDl->NombreDeTermes ; il++ ) { + if ( LigneDeProduitScalaireDeDl->NumeroDeVariableMatrice[il] == VariableKDansMatrice ) { + DkT_Dl = LigneDeProduitScalaireDeDl->ProduitScalaire[il]; + break; + } + } +} + +NormeAuCarre = LigneDeProduitScalaireDeDk->ProduitScalaire[0] + ( 2 * DeltaOpt * DkT_Dl ); +NormeAuCarre+= DeltaOpt * DeltaOpt * LigneDeProduitScalaireDeDl->ProduitScalaire[0]; +if ( NormeAuCarre < ZERO_DE_NORME_AU_CARRE ) NormeAuCarre = 0.0; + +return( NormeAuCarre ); +} + +/*----------------------------------------------------------------------------*/ + +void SPX_MajMatricePourCoupesDIntersection( PROBLEME_SPX * Spx, int VariableKDansMatrice, int VariableLDansMatrice, + double DeltaOpt, double NouvelleNormeDeDkAuCarre ) + +{ +int i; int il; int ilDi; double DlT_Di; int VarSpx; int NbFillIn; +LIGNE_DE_PRODUITS_SCALAIRES * LigneDeProduitScalaireDeDi; LIGNE_DE_PRODUITS_SCALAIRES * LigneDeProduitScalaireDeDk; +LIGNE_DE_PRODUITS_SCALAIRES * LigneDeProduitScalaireDeDl; int VariableIDansMatrice; +LIGNE_DE_MATRICE * LigneDeMatriceDk; LIGNE_DE_MATRICE * LigneDeMatriceDl; +DONNEES_POUR_COUPES_DINTERSECTION * DonneesPourCoupesDIntersection; + +LIGNE_DE_PRODUITS_SCALAIRES ** LigneDeProduitScalaire; +char * T; double * Vecteur; + +if ( Spx->CoupesDintersectionAllouees == NON_SPX ) return; + +DonneesPourCoupesDIntersection = Spx->DonneesPourCoupesDIntersection; + +LigneDeProduitScalaire = DonneesPourCoupesDIntersection->LigneDeProduitScalaire; +LigneDeProduitScalaireDeDk = LigneDeProduitScalaire[VariableKDansMatrice]; +LigneDeProduitScalaireDeDl = LigneDeProduitScalaire[VariableLDansMatrice]; + +/* 1- Les produits scalaires */ +/* dkT di = dkT di + DeltaOpt dlT di */ +for ( i = 0 ; i < VariableKDansMatrice ; i++ ) { + LigneDeProduitScalaireDeDi = LigneDeProduitScalaire[i]; + VariableIDansMatrice = i; + DlT_Di = 0.0; + if ( VariableLDansMatrice >= VariableIDansMatrice ) { + /* Si VariableLDansMatrice >= VariableIDansMatrice on cherche DlT_Di en balayant LigneDeProduitScalaireDeDi */ + for ( il = 0 ; il < LigneDeProduitScalaireDeDi->NombreDeTermes ; il++ ) { + if ( LigneDeProduitScalaireDeDi->NumeroDeVariableMatrice[il] == VariableLDansMatrice ) { + DlT_Di = LigneDeProduitScalaireDeDi->ProduitScalaire[il]; + break; + } + } + } + else if ( VariableLDansMatrice < VariableIDansMatrice ) { + /* Si VariableLDansMatrice < VariableIDansMatrice on cherche DlT_Di en balayant LigneDeProduitScalaireDeDl */ + for ( il = 0 ; il < LigneDeProduitScalaireDeDl->NombreDeTermes ; il++ ) { + if ( LigneDeProduitScalaireDeDl->NumeroDeVariableMatrice[il] == VariableIDansMatrice ) { + DlT_Di = LigneDeProduitScalaireDeDl->ProduitScalaire[il]; + break; + } + } + } + for ( il = 0 ; il < LigneDeProduitScalaireDeDi->NombreDeTermes ; il++ ) { + if ( LigneDeProduitScalaireDeDi->NumeroDeVariableMatrice[il] == VariableKDansMatrice ) { + LigneDeProduitScalaireDeDi->ProduitScalaire[il] += DeltaOpt * DlT_Di; + break; + } + } +} + +/* On complete sur la ligne k */ +LigneDeProduitScalaireDeDk->ProduitScalaire[0] = NouvelleNormeDeDkAuCarre; +for ( il = 1 ; il < LigneDeProduitScalaireDeDk->NombreDeTermes ; il++ ) { + VariableIDansMatrice = LigneDeProduitScalaireDeDk->NumeroDeVariableMatrice[il]; + DlT_Di = 0.0; + if ( VariableLDansMatrice >= VariableIDansMatrice ) { + /* Si VariableLDansMatrice > VariableIDansMatrice on cherche DlT_Di en balayant LigneDeProduitScalaireDeDi */ + LigneDeProduitScalaireDeDi = LigneDeProduitScalaire[VariableIDansMatrice]; + for ( ilDi = 0 ; ilDi < LigneDeProduitScalaireDeDi->NombreDeTermes ; ilDi++ ) { + if ( LigneDeProduitScalaireDeDi->NumeroDeVariableMatrice[ilDi] == VariableLDansMatrice ) { + DlT_Di = LigneDeProduitScalaireDeDi->ProduitScalaire[ilDi]; + break; + } + } + } + else { + /* Si VariableLDansMatrice < VariableIDansMatrice on cherche DlT_Di en balayant LigneDeProduitScalaireDeDl */ + for ( i = 0 ; i < LigneDeProduitScalaireDeDl->NombreDeTermes ; i++ ) { + if ( LigneDeProduitScalaireDeDl->NumeroDeVariableMatrice[i] == VariableIDansMatrice ) { + DlT_Di = LigneDeProduitScalaireDeDl->ProduitScalaire[i]; + break; + } + } + } + LigneDeProduitScalaireDeDk->ProduitScalaire[il] += DeltaOpt * DlT_Di; +} + +T = DonneesPourCoupesDIntersection->TSpx; +Vecteur = DonneesPourCoupesDIntersection->Vecteur; +/* On doit faire Dk = Dk + DeltaOpt * Dl */ +memset( (char *) T , 1, Spx->NombreDeVariables * sizeof( char ) ); +memset( (char *) Vecteur, 0, Spx->NombreDeVariables * sizeof( double ) ); + +NbFillIn = 0; +LigneDeMatriceDk = DonneesPourCoupesDIntersection->LigneDeMatrice[VariableKDansMatrice]; +for ( il = 0 ; il < LigneDeMatriceDk->NombreDeTermes ; il++ ) { + VarSpx = LigneDeMatriceDk->NumeroDeVariableSpx[il]; + Vecteur[VarSpx] = LigneDeMatriceDk->Coefficient[il]; + T [VarSpx] = 0; +} + +LigneDeMatriceDl = DonneesPourCoupesDIntersection->LigneDeMatrice[VariableLDansMatrice]; +for ( il = 0 ; il < LigneDeMatriceDl->NombreDeTermes ; il++ ) { + VarSpx = LigneDeMatriceDl->NumeroDeVariableSpx[il]; + Vecteur[VarSpx] += DeltaOpt * LigneDeMatriceDl->Coefficient[il]; + NbFillIn+= T[VarSpx]; + T[VarSpx] = 0; +} + +LigneDeMatriceDk->NombreDeTermes+= NbFillIn; + +LigneDeMatriceDk->SecondMembre += DeltaOpt * LigneDeMatriceDl->SecondMembre; + +if ( NbFillIn > 0 ) { + free( LigneDeMatriceDk->Coefficient ); + free( LigneDeMatriceDk->NumeroDeVariableSpx ); + + LigneDeMatriceDk->Coefficient = (double *) malloc( LigneDeMatriceDk->NombreDeTermes * sizeof( double ) ); + LigneDeMatriceDk->NumeroDeVariableSpx = (int *) malloc( LigneDeMatriceDk->NombreDeTermes * sizeof( int ) ); + if ( LigneDeMatriceDk->Coefficient == NULL || LigneDeMatriceDk->NumeroDeVariableSpx == NULL ) { + free( LigneDeMatriceDk->Coefficient ); + free( LigneDeMatriceDk->NumeroDeVariableSpx ); + Spx->CoupesDintersectionAllouees = NON_SPX; + return; + } +} + +il = 0; +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + if ( T[VarSpx] == 0 ) { + LigneDeMatriceDk->Coefficient [il] = Vecteur[VarSpx]; + LigneDeMatriceDk->NumeroDeVariableSpx[il] = VarSpx; + il++; + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Attention, c'est la routine qui prend le plus de temps et ceci meme avec + un petit nombre de rebouclages */ + +void SPX_ReductionDesNormesPourCoupesDIntersection( PROBLEME_SPX * Spx ) +{ +int i; double X; double DeltaOpt; double * Vecteur; int VarSpx; double NormeDeDkAuCarre; int ilNorme; int VariableLDansMatrice; +double NouvelleNormeAuCarre; double NormeDeDlAuCarre; double PlusGrandeReductionDeNorme; double DeltaOptChoisi; +char OnReboucle;int NbFois; int j; int VariableDansMatrice; +int VariableKDansMatriceChoisie;int VariableLDansMatriceChoisie; double ValeurDuProduitScalaireDeDl; + +int VariableKDansMatrice; double NouvelleNormeDeDkAuCarre; +LIGNE_DE_PRODUITS_SCALAIRES * LigneDeProduitScalaireDeDl; +LIGNE_DE_PRODUITS_SCALAIRES * LigneDeProduitScalaireDeDk; +char * LaVariableSpxEstEntiere; +DONNEES_POUR_COUPES_DINTERSECTION * DonneesPourCoupesDIntersection; + +if ( Spx->CoupesDintersectionAllouees == NON_SPX ) return; + +DonneesPourCoupesDIntersection = Spx->DonneesPourCoupesDIntersection; + +/* Reinitialisation des Xmax: on se remet dans le contexte des Gomory */ +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + DonneesPourCoupesDIntersection->XmaxSv[VarSpx] = Spx->Xmax[VarSpx]; + /* Le calcul de BBarre fait intervenir Xmax, il faut dont le corriger pour simuler l'absence d'instanciation */ + if ( DonneesPourCoupesDIntersection->LaVariableSpxEstEntiere[VarSpx] == NON_SPX ) continue; + /* C'est une variable entiere */ + /* La valeur 1. indique bien que ca ne marche que pour des variables binaires */ + Spx->Xmax[VarSpx] = 1. / Spx->ScaleX[VarSpx]; +} + +Vecteur = DonneesPourCoupesDIntersection->Vecteur; +memset( (char *) Vecteur, 0, Spx->NombreDeVariables * sizeof( double ) ); + +LaVariableSpxEstEntiere = DonneesPourCoupesDIntersection->LaVariableSpxEstEntiere; + +OnReboucle = OUI_SPX; + +NbFois = 0; + +/* Pour eviter les warning de compilation */ +NouvelleNormeDeDkAuCarre = 0.0; +DeltaOptChoisi = 0.0; + +while ( OnReboucle == OUI_SPX && NbFois < NOMBRE_MAX_DE_CYCLES ) { +OnReboucle = NON_SPX; + +for ( i = 0 ; i < DonneesPourCoupesDIntersection->NombreDeVariables ; i++ ) { + /* On est sur la ligne des produits scalaires Dl */ + VariableLDansMatrice = i; + LigneDeProduitScalaireDeDl = DonneesPourCoupesDIntersection->LigneDeProduitScalaire[i]; + NormeDeDlAuCarre = LigneDeProduitScalaireDeDl->ProduitScalaire[0]; + if ( NormeDeDlAuCarre < ZERO_DE_NORME_AU_CARRE ) continue; + + PlusGrandeReductionDeNorme = -LINFINI_SPX; + VariableKDansMatriceChoisie = -1; + VariableLDansMatriceChoisie = -1; + + for ( ilNorme = 1 ; ilNorme < LigneDeProduitScalaireDeDl->NombreDeTermes ; ilNorme++ ) { + + VariableKDansMatrice = LigneDeProduitScalaireDeDl->NumeroDeVariableMatrice[ilNorme]; + + LigneDeProduitScalaireDeDk = DonneesPourCoupesDIntersection->LigneDeProduitScalaire[VariableKDansMatrice]; + NormeDeDkAuCarre = LigneDeProduitScalaireDeDk->ProduitScalaire[0]; + if ( NormeDeDkAuCarre < ZERO_DE_NORME_AU_CARRE ) continue; + + /* Calcul de la norme au carre de Dk + DeltaOpt * Dl */ + DeltaOpt = floor( -LigneDeProduitScalaireDeDl->ProduitScalaire[ilNorme] / NormeDeDlAuCarre ); + if ( fabs( DeltaOpt ) > DELTAOPT_MIN && fabs( DeltaOpt ) < DELTAOPT_MAX ) { + NouvelleNormeAuCarre = SPX_CalculDeLaNouvelleNorme( LigneDeProduitScalaireDeDk, LigneDeProduitScalaireDeDl, + VariableKDansMatrice, VariableLDansMatrice, DeltaOpt ); + if ( NouvelleNormeAuCarre/NormeDeDkAuCarre < SEUIL_DE_REDUCTION_AU_CARRE ) { + if ( NouvelleNormeAuCarre == 0.0 ) X = LINFINI_SPX; + else X = NormeDeDkAuCarre / ( NouvelleNormeAuCarre + 1.e-20 ); /* Pour eviter les divisions par 0 */ + if ( X > PlusGrandeReductionDeNorme ) { + PlusGrandeReductionDeNorme = X; + VariableKDansMatriceChoisie = VariableKDansMatrice; + VariableLDansMatriceChoisie = VariableLDansMatrice; + DeltaOptChoisi = DeltaOpt; + NouvelleNormeDeDkAuCarre = NouvelleNormeAuCarre; + if ( PlusGrandeReductionDeNorme == LINFINI_SPX ) break; + } + } + } + + /* Calcul de la norme au carre de Dk + DeltaOpt * Dl */ + DeltaOpt = ceil( -LigneDeProduitScalaireDeDl->ProduitScalaire[ilNorme] / NormeDeDlAuCarre ); + if ( fabs( DeltaOpt ) > DELTAOPT_MIN && fabs( DeltaOpt ) < DELTAOPT_MAX ) { + NouvelleNormeAuCarre = SPX_CalculDeLaNouvelleNorme( LigneDeProduitScalaireDeDk, LigneDeProduitScalaireDeDl, + VariableKDansMatrice, VariableLDansMatrice, DeltaOpt ); + if ( NouvelleNormeAuCarre/NormeDeDkAuCarre < SEUIL_DE_REDUCTION_AU_CARRE ) { + if ( NouvelleNormeAuCarre == 0.0 ) X = LINFINI_SPX; + else X = NormeDeDkAuCarre / ( NouvelleNormeAuCarre + 1.e-20 ); /* Pour eviter les divisions par 0 */ + if ( X > PlusGrandeReductionDeNorme ) { + PlusGrandeReductionDeNorme = X; + VariableKDansMatriceChoisie = VariableKDansMatrice; + VariableLDansMatriceChoisie = VariableLDansMatrice; + DeltaOptChoisi = DeltaOpt; + NouvelleNormeDeDkAuCarre = NouvelleNormeAuCarre; + if ( PlusGrandeReductionDeNorme == LINFINI_SPX ) break; + } + } + } + + } + + /* Examen de la partie non representee dans la matrice et qui correspond a ce qui se trouve a + gauche de la diagonale */ + goto FinPartieSuperieure; /* <- inhibition car ca prend du temps et ca n'améliore pas franchement */ + for ( j = 0 ; j < VariableLDansMatrice ; j++ ) { + VariableKDansMatrice = j; + LigneDeProduitScalaireDeDk = DonneesPourCoupesDIntersection->LigneDeProduitScalaire[VariableKDansMatrice]; + NormeDeDkAuCarre = LigneDeProduitScalaireDeDk->ProduitScalaire[0]; + if ( NormeDeDkAuCarre < ZERO_DE_NORME_AU_CARRE ) continue; + for ( ilNorme = 1 ; ilNorme < LigneDeProduitScalaireDeDk->NombreDeTermes ; ilNorme++ ) { + VariableDansMatrice = LigneDeProduitScalaireDeDk->NumeroDeVariableMatrice[ilNorme]; + if ( VariableDansMatrice > VariableLDansMatrice ) break; + if ( VariableDansMatrice == VariableLDansMatrice ) { + ValeurDuProduitScalaireDeDl = LigneDeProduitScalaireDeDk->ProduitScalaire[ilNorme]; + /* Calcul de la norme au carre de Dk + DeltaOpt * Dl */ + DeltaOpt = floor( -ValeurDuProduitScalaireDeDl / NormeDeDlAuCarre ); + if ( fabs( DeltaOpt ) > DELTAOPT_MIN && fabs( DeltaOpt ) < DELTAOPT_MAX ) { + NouvelleNormeAuCarre = SPX_CalculDeLaNouvelleNorme( LigneDeProduitScalaireDeDk, LigneDeProduitScalaireDeDl, + VariableKDansMatrice, VariableLDansMatrice, DeltaOpt ); + if ( NouvelleNormeAuCarre/NormeDeDkAuCarre < SEUIL_DE_REDUCTION_AU_CARRE ) { + if ( NouvelleNormeAuCarre == 0.0 ) X = LINFINI_SPX; + else X = NormeDeDkAuCarre / ( NouvelleNormeAuCarre + 1.e-20 ); /* Pour eviter les divisions par 0 */ + if ( X > PlusGrandeReductionDeNorme ) { + PlusGrandeReductionDeNorme = X; + VariableKDansMatriceChoisie = VariableKDansMatrice; + VariableLDansMatriceChoisie = VariableLDansMatrice; + DeltaOptChoisi = DeltaOpt; + NouvelleNormeDeDkAuCarre = NouvelleNormeAuCarre; + if ( PlusGrandeReductionDeNorme == LINFINI_SPX ) break; + } + } + } + /* Calcul de la norme au carre de Dk + DeltaOpt * Dl */ + DeltaOpt = ceil( -ValeurDuProduitScalaireDeDl / NormeDeDlAuCarre ); + if ( fabs( DeltaOpt ) > DELTAOPT_MIN && fabs( DeltaOpt ) < DELTAOPT_MAX ) { + NouvelleNormeAuCarre = SPX_CalculDeLaNouvelleNorme( LigneDeProduitScalaireDeDk, LigneDeProduitScalaireDeDl, + VariableKDansMatrice, VariableLDansMatrice, DeltaOpt ); + if ( NouvelleNormeAuCarre/NormeDeDkAuCarre < SEUIL_DE_REDUCTION_AU_CARRE ) { + if ( NouvelleNormeAuCarre == 0.0 ) X = LINFINI_SPX; + else X = NormeDeDkAuCarre / ( NouvelleNormeAuCarre + 1.e-20 ); /* Pour eviter les divisions par 0 */ + if ( X > PlusGrandeReductionDeNorme ) { + PlusGrandeReductionDeNorme = X; + VariableKDansMatriceChoisie = VariableKDansMatrice; + VariableLDansMatriceChoisie = VariableLDansMatrice; + DeltaOptChoisi = DeltaOpt; + NouvelleNormeDeDkAuCarre = NouvelleNormeAuCarre; + if ( PlusGrandeReductionDeNorme == LINFINI_SPX ) break; + } + } + } + break; + } + } + } + FinPartieSuperieure: + + if ( VariableKDansMatriceChoisie >= 0 ) { + OnReboucle = OUI_SPX; + SPX_MajMatricePourCoupesDIntersection( Spx, VariableKDansMatriceChoisie, VariableLDansMatriceChoisie, DeltaOptChoisi, + NouvelleNormeDeDkAuCarre ); + } + +} + +if ( OnReboucle == OUI_SPX ) NbFois++; + +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +int SPX_NombrePotentielDeCoupesDIntersection( PROBLEME_SPX * Spx ) +{ +DONNEES_POUR_COUPES_DINTERSECTION * DonneesPourCoupesDIntersection; +if ( Spx->CoupesDintersectionAllouees == NON_SPX ) return( 0 ); +DonneesPourCoupesDIntersection = Spx->DonneesPourCoupesDIntersection; + +return( DonneesPourCoupesDIntersection->NombreDeVariables); +} + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerUneCoupeDIntersection( PROBLEME_SPX * Spx, + int i, + + double RapportMaxDesCoeffs, + double ZeroPourCoeffVariablesDEcart, + double ZeroPourCoeffVariablesNatives, + double RelaxRhsAbs, + double RelaxRhsRel, + + int * NombreDeTermes, + double * Coefficient, + int * IndiceDeLaVariable, + double * SecondMembre, + char * OnAEcrete ) +{ +int il; int VarSpx; double NormeAuCarre; DONNEES_POUR_COUPES_DINTERSECTION * DonneesPourCoupesDIntersection; +LIGNE_DE_PRODUITS_SCALAIRES * LigneDeProduitScalaire; double EpsilonDePiEtPi0; +LIGNE_DE_MATRICE * LigneDeMatrice; char * LaVariableSpxEstEntiere; double X; double DeltaOpt; +double * Coeff; char * T; double AlphaI0; double * B; char OnRenforce; double ValeurDuZero; + +*OnAEcrete = NON_SPX; +*NombreDeTermes = 0; + +ValeurDuZero = ZERO_TERMES_DU_TABLEAU_POUR_GOMORY; + +if ( Spx->CoupesDintersectionAllouees == NON_SPX ) return; + +DonneesPourCoupesDIntersection = Spx->DonneesPourCoupesDIntersection; +LaVariableSpxEstEntiere = DonneesPourCoupesDIntersection->LaVariableSpxEstEntiere; + +if ( DonneesPourCoupesDIntersection->NormeAvantReduction[i] < ZERO_DE_NORME_AU_CARRE /*1.e-9*/ ) { + return; +} + +LigneDeProduitScalaire = DonneesPourCoupesDIntersection->LigneDeProduitScalaire[i]; +NormeAuCarre = LigneDeProduitScalaire->ProduitScalaire[0]; +if ( NormeAuCarre / DonneesPourCoupesDIntersection->NormeAvantReduction[i] > SEUIL_DE_REDUCTION_AU_CARRE /*0.9*/ ) { + return; +} + +LigneDeMatrice = DonneesPourCoupesDIntersection->LigneDeMatrice[i]; +/*1- On recupere la split disjuction */ +EpsilonDePiEtPi0 = LigneDeMatrice->SecondMembre - floor( LigneDeMatrice->SecondMembre ); + +/* EpsilonDePiEtPi0 doit etre compris entre 0 et 1 */ +if ( EpsilonDePiEtPi0 < 1.e-9 || EpsilonDePiEtPi0 > 0.999999999) return; + +/* Les rayons extreme c'est -NBarreR ? */ +/* +for ( il = 0 ; il < LigneDeMatrice->NombreDeTermes ; il++ ) { + LigneDeMatrice->Coefficient[il] *= -1.0; +} +*/ +/*2- On renforce la split disjunction */ +OnRenforce = OUI_SPX; /* NON_SPX */ +if ( OnRenforce == OUI_SPX ) { + for ( il = 0 ; il < LigneDeMatrice->NombreDeTermes ; il++ ) { + VarSpx = LigneDeMatrice->NumeroDeVariableSpx[il]; + /* On choisi une variable entiere k hors base */ + if ( LaVariableSpxEstEntiere[VarSpx] != OUI_SPX ) continue; + /* On dispose directement du coefficient du coefficient pi^t rk car il est mis a jour en cours de reduction des normes */ + X = LigneDeMatrice->Coefficient[il]; + if ( ceil( X ) - X > EpsilonDePiEtPi0 ) DeltaOpt = -floor( X ); + else DeltaOpt = -ceil( X ); + /* On ajoute la variable dans la split cut */ + /* Cela se traduit par une modification de Coefficient (et non de Pi) */ + LigneDeMatrice->Coefficient[il] += DeltaOpt; + } +} +/* +for ( il = 0 ; il < LigneDeMatrice->NombreDeTermes ; il++ ) { + LigneDeMatrice->Coefficient[il] *= -1.0; +} +*/ + +AlphaI0 = LigneDeMatrice->SecondMembre; + +Coeff = DonneesPourCoupesDIntersection->Vecteur; +T = DonneesPourCoupesDIntersection->TSpx; +B = DonneesPourCoupesDIntersection->B; + +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + T [VarSpx] = 0; + Coeff[VarSpx] = 0.; +} + +for ( il = 0 ; il < LigneDeMatrice->NombreDeTermes ; il++ ){ + VarSpx = LigneDeMatrice->NumeroDeVariableSpx[il]; + Coeff[VarSpx] = LigneDeMatrice->Coefficient[il]; + T [VarSpx] = 1; + /* Nettoyage des tres petites valeurs */ + if ( fabs( Coeff[VarSpx] ) < ValeurDuZero ) { + T[VarSpx] = 0; + Coeff[VarSpx] = 0.; + } +} + +/* Calcul de la MIR */ +SPX_CalculMIRPourCoupeDeGomoryOuIntersection( Spx, RapportMaxDesCoeffs, ZeroPourCoeffVariablesDEcart, + ZeroPourCoeffVariablesNatives, RelaxRhsAbs, RelaxRhsRel, + AlphaI0, B, T, Coeff, LaVariableSpxEstEntiere, + NombreDeTermes, Coefficient, IndiceDeLaVariable, SecondMembre, + OnAEcrete ); + +return; +} + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calcul_couts_reduits.c b/src/ext/Sirius_Solver/simplexe/spx_calcul_couts_reduits.c new file mode 100644 index 0000000000..5642eae477 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calcul_couts_reduits.c @@ -0,0 +1,114 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul des couts reduits des variables hors base + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerLesCoutsReduits( PROBLEME_SPX * Spx ) +{ +int Var; int il; int ilMax; double S; int i; int * NumerosDesVariablesHorsBase; +int * Cdeb; int * CNbTerm; int * NumeroDeContrainte; double * Pi; double * ACol; +double * C; double * CBarre; + +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +Pi = Spx->Pi; +ACol = Spx->ACol; +CBarre = Spx->CBarre; +C = Spx->C; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +/* Boucle sur les variables hors base */ + +for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + /* Utilisation du chainage de la transposee de la matrice + des contraintes */ + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + S = 0.; + while ( il < ilMax ) { + S += Pi[NumeroDeContrainte[il]] * ACol[il]; + il++; + } + CBarre[Var] = C[Var] - S; +} + +Spx->CBarreAEteCalculeParMiseAJour = NON_SPX; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Cas de la mise a jour de CBarre */ + +void SPX_MettreAJourLesCoutsReduits( PROBLEME_SPX * Spx ) +{ +double X; int i; double * CBarre; double * NBarreR; int * NumVarNBarreRNonNul; +int * NumerosDesVariablesHorsBase; int VariableEntrante; int VariableSortante; +int Var; + +CBarre = Spx->CBarre; +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +NBarreR = Spx->NBarreR; + +VariableEntrante = Spx->VariableEntrante; +VariableSortante = Spx->VariableSortante; + +/* Pour etre coherent il vaut mieux prendre NBarreR car c'est ce qui a servi au test du ratio */ +X = -CBarre[VariableEntrante] / NBarreR[VariableEntrante]; + +if ( X == 0.0 ) goto FinMajCoutsReduits; + +/* Boucle sur les variables hors base */ +if ( Spx->TypeDeStockageDeNBarreR == ADRESSAGE_INDIRECT_SPX ) { + NumVarNBarreRNonNul = Spx->NumVarNBarreRNonNul; + for ( i = 0 ; i < Spx->NombreDeValeursNonNullesDeNBarreR ; i++ ) { + Var = NumVarNBarreRNonNul[i]; + CBarre[Var]+= X * NBarreR[Var]; + } +} +else { + for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + if ( NBarreR[Var] != 0.0 ) { + CBarre[Var]+= X * NBarreR[Var]; + } + } +} + +FinMajCoutsReduits: + +CBarre[VariableSortante] = X; +CBarre[VariableEntrante] = 0.; + +Spx->CBarreAEteCalculeParMiseAJour = OUI_SPX; + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_calcul_couts_reduits_avec_base_complete.c b/src/ext/Sirius_Solver/simplexe/spx_calcul_couts_reduits_avec_base_complete.c new file mode 100644 index 0000000000..60158b29e9 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calcul_couts_reduits_avec_base_complete.c @@ -0,0 +1,68 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul des couts reduits des variables hors base + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerLesCoutsReduitsAvecBaseComplete( PROBLEME_SPX * Spx ) +{ +int Var; int il; int ilMax; double S; int i; int * NumerosDesVariablesHorsBase; +int * Cdeb; int * CNbTerm; int * NumeroDeContrainte; double * Pi; double * ACol; +double * C; double * CBarre; + +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +Pi = Spx->Pi; +ACol = Spx->ACol; +CBarre = Spx->CBarre; +C = Spx->C; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +/* Boucle sur les variables hors base */ + +for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + /* Utilisation du chainage de la transposee de la matrice + des contraintes */ + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + S = 0.; + while ( il < ilMax ) { + S += Pi[NumeroDeContrainte[il]] * ACol[il]; + il++; + } + CBarre[Var] = C[Var] - S; +} + +Spx->CBarreAEteCalculeParMiseAJour = NON_SPX; + +return; +} + +/*----------------------------------------------------------------------------*/ diff --git a/src/ext/Sirius_Solver/simplexe/spx_calcul_couts_reduits_avec_base_reduite.c b/src/ext/Sirius_Solver/simplexe/spx_calcul_couts_reduits_avec_base_reduite.c new file mode 100644 index 0000000000..6c249a6cda --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calcul_couts_reduits_avec_base_reduite.c @@ -0,0 +1,71 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul des couts reduits des variables hors base + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerLesCoutsReduitsAvecBaseReduite( PROBLEME_SPX * Spx ) +{ +int Var; int il; int ilMax; double S; int i; int * NumerosDesVariablesHorsBase; +int * Cdeb; int * CNbTerm; int * NumeroDeContrainte; double * Pi; double * ACol; +double * C; double * CBarre; int * LigneDeLaBaseFactorisee; int * IndicesDeLigneDesTermesDuProblemeReduit; + +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +Cdeb = Spx->CdebProblemeReduit; +CNbTerm = Spx->CNbTermProblemeReduit; +IndicesDeLigneDesTermesDuProblemeReduit = Spx->IndicesDeLigneDesTermesDuProblemeReduit; +ACol = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; +LigneDeLaBaseFactorisee = Spx->LigneDeLaBaseFactorisee; + +Pi = Spx->Pi; +CBarre = Spx->CBarre; +C = Spx->C; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +/* Boucle sur les variables hors base */ + +for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + /* Utilisation du chainage de la transposee de la matrice + des contraintes */ + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + S = 0.; + while ( il < ilMax ) { + S += Pi[LigneDeLaBaseFactorisee[IndicesDeLigneDesTermesDuProblemeReduit[il]]] * ACol[il]; + il++; + } + CBarre[Var] = C[Var] - S; +} + +Spx->CBarreAEteCalculeParMiseAJour = NON_SPX; + +return; +} + +/*----------------------------------------------------------------------------*/ diff --git a/src/ext/Sirius_Solver/simplexe/spx_calcul_du_cout.c b/src/ext/Sirius_Solver/simplexe/spx_calcul_du_cout.c new file mode 100644 index 0000000000..34f9129132 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calcul_du_cout.c @@ -0,0 +1,125 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Utilisable surtout dans un contexte de Branch and Bound. + On calcule le cout de la solution primale et on le compare + au seuil fourni en entrée (qui dans un contexte de + Branch and Bound est le cout de la meilleure solution + entiere deja trouvee). Si le cout calculé est superieur + au seuil fourni en entree, on arrete les calculs et on + sort avec le verdict: pas de solution. En effet le cout + courant est un minorant du cout optimal. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "pne_define.h" + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculDuCout( PROBLEME_SPX * Spx ) +{ +int i; double Cout; double * C; double * X; PROBLEME_PNE * Pne; +# if TRACES == 1 + double * Csv; double VraiCout; double Erreur; +# endif + +SPX_FixerXEnFonctionDeSaPosition( Spx ); +C = Spx->C; + +# if TRACES == 1 + Csv = Spx->Csv; +# endif + +X = Spx->X; +Cout = 0.0; + +# if TRACES == 1 + VraiCout = 0; +# endif + +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + Cout += C[i] * X[i]; + # if TRACES == 1 + VraiCout += Csv[i] * X[i]; + # endif +} + +Cout /= Spx->ScaleLigneDesCouts; +Cout += Spx->PartieFixeDuCout; + +# if TRACES == 1 + VraiCout /= Spx->ScaleLigneDesCouts; + VraiCout += Spx->PartieFixeDuCout; + Erreur = fabs( VraiCout - Cout ); + printf("Erreur due au bruitage des couts %e Cout sans bruitage %e\n",Erreur,VraiCout); +# endif + +Spx->Cout = Cout; + +Pne = (PROBLEME_PNE *) Spx->ProblemePneDeSpx; +if ( Pne != NULL ) { + Spx->Cout += Pne->Z0; +} + +#if VERBOSE_SPX + if ( Spx->StrongBranchingEnCours != OUI_SPX ) { + if ( Spx->UtiliserCoutMax == OUI_SPX ) { + printf("Iteration %5d Cout %20.6lf Infaisabilites primales %20.6lf PartieFixeDuCout %20.6lf CoutMax %20.6lf\n", + Spx->Iteration,Spx->Cout,Spx->SommeDesInfaisabilitesPrimales,Spx->PartieFixeDuCout,Spx->CoutMax); + } + else { + printf("Iteration %5d Cout %20.6lf Infaisabilites primales %20.6lf PartieFixeDuCout %20.6lf\n", + Spx->Iteration,Spx->Cout,Spx->SommeDesInfaisabilitesPrimales,Spx->PartieFixeDuCout); + } + } +#else + /* Cas non verbose */ + if ( Spx->LaBaseDeDepartEstFournie == NON_SPX && Spx->AffichageDesTraces == OUI_SPX ) { /* Premier simplexe */ + if ( Spx->EcrireLegendePhase2 == OUI_SPX ) { + Spx->EcrireLegendePhase1 = OUI_SPX; + Spx->EcrireLegendePhase2 = NON_SPX; + printf(" "); + printf(" | Phase |"); + printf(" Iteration |"); + printf(" Objective |"); + printf(" Primal infeas. |"); + printf(" Primal infeas. count |"); + printf("\n"); + } + printf(" "); + printf(" | II |"); + printf(" %6d |",Spx->Iteration); + printf(" %16.9e |",Spx->Cout); + printf(" %15.8e |",Spx->SommeDesInfaisabilitesPrimales); + printf(" %10d |",Spx->NombreDeContraintesASurveiller); + printf("\n"); + } +#endif + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calcul_du_cout_simplifie.c b/src/ext/Sirius_Solver/simplexe/spx_calcul_du_cout_simplifie.c new file mode 100644 index 0000000000..5b462c8483 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calcul_du_cout_simplifie.c @@ -0,0 +1,103 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul simplifie du cout: on ne fixe pas toutes les + variable en fonction de le position pour calculer le cout + mais seulement celles dont le cout est non nul. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# include "pne_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculDuCoutSimplifie( PROBLEME_SPX * Spx ) +{ +int * NumeroDesVariablesACoutNonNul; char Position; int * ContrainteDeLaVariableEnBase; +double * Xmax; double * BBarre; int Var; double Cout; char * PositionDeLaVariable; +double * C; int i; char * StatutBorneSupCourante; PROBLEME_PNE * Pne; + +NumeroDesVariablesACoutNonNul = Spx->NumeroDesVariablesACoutNonNul; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +C = Spx->C; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +BBarre = Spx->BBarre; +PositionDeLaVariable = Spx->PositionDeLaVariable; +Xmax = Spx->Xmax; +Cout = 0.0; +if ( Spx->NombreDeBornesAuxiliairesUtilisees == 0 ) { + for ( i = 0 ; i < Spx->NombreDeVariablesACoutNonNul ; i++ ) { + Var = NumeroDesVariablesACoutNonNul[i]; + Position = PositionDeLaVariable[Var]; + if ( Position == EN_BASE_LIBRE ) { + /* La variable est en base */ + Cout += C[Var] * BBarre[ContrainteDeLaVariableEnBase[Var]]; + } + else if ( Position == HORS_BASE_SUR_BORNE_SUP ) { + Cout += C[Var] * Xmax[Var]; + } + } +} +else { + for ( i = 0 ; i < Spx->NombreDeVariablesACoutNonNul ; i++ ) { + /* Remarque il se peut qu'a cause de la degenerescence on ait bruite des couts */ + Var = NumeroDesVariablesACoutNonNul[i]; + Position = PositionDeLaVariable[Var]; + if ( Position == EN_BASE_LIBRE ) { + /* La variable est en base */ + Cout += C[Var] * BBarre[ContrainteDeLaVariableEnBase[Var]]; + } + else if ( Position == HORS_BASE_SUR_BORNE_SUP ) { + Cout += C[Var] * Xmax[Var]; + } + else { + /* La variable est HORS_BASE_A_ZERO ou HORS_BASE_SUR_BORNE_INF */ + if ( Position == HORS_BASE_SUR_BORNE_INF ) { + if ( StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) { + /* La variable est hors base sur borne inf mais qu'elle a une borne avec un StatutBorneSupCourante egal a + BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE alors elle est a -Xmax[Var] */ + Cout -= C[Var] * Xmax[Var]; + } + } + } + } +} +Cout/= Spx->ScaleLigneDesCouts; +Cout+= Spx->PartieFixeDuCout; +Spx->Cout = Cout; + +Pne = (PROBLEME_PNE *) Spx->ProblemePneDeSpx; +if ( Pne != NULL ) { + Spx->Cout += Pne->Z0; +} + +return; + +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_a_barre_s.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_a_barre_s.c new file mode 100644 index 0000000000..99d49be78e --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_a_barre_s.c @@ -0,0 +1,154 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de A_BARRE_S = B-1 * AS + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ +void SPX_TenterRestaurationCalculABarreSEnHyperCreux( PROBLEME_SPX * Spx ) +{ +double * ABarreS; int Count; int iMx; int i; + +if ( Spx->CountEchecsABarreS == 0 ) { + if ( Spx->Iteration % CYCLE_TENTATIVE_HYPER_CREUX == 0 ) { + Spx->NbEchecsABarreS = SEUIL_REUSSITE_CREUX; + Spx->CountEchecsABarreS = SEUIL_REUSSITE_CREUX + 2; + } +} +if ( Spx->CountEchecsABarreS == 0 ) return; + +Spx->CountEchecsABarreS--; +/* On compte le nombre de termes non nuls du resultat */ +ABarreS = Spx->ABarreS; +Count = 0; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + iMx = Spx->RangDeLaMatriceFactorisee; +} +else { + iMx = Spx->NombreDeContraintes; +} + +for ( i = 0 ; i < iMx ; i++ ) if ( ABarreS[i] != 0.0 ) Count++; + +if ( Count < 0.1 * iMx ) Spx->NbEchecsABarreS--; +if ( Spx->NbEchecsABarreS <= 0 ) { + # if VERBOSE_SPX + printf("Remise en service de l'hyper creux pour le calcul de ABarreS, iteration %d\n",Spx->Iteration); + # endif + Spx->AvertissementsEchecsABarreS = 0; + Spx->CountEchecsABarreS = 0; + Spx->CalculABarreSEnHyperCreux = OUI_SPX; +} +else if ( Spx->CountEchecsABarreS <= 0 ) { + Spx->CountEchecsABarreS = 0; + if ( Spx->CalculABarreSEnHyperCreux == NON_SPX ) Spx->AvertissementsEchecsABarreS ++; + if ( Spx->AvertissementsEchecsABarreS >= SEUIL_ABANDON_HYPER_CREUX ) { + # if VERBOSE_SPX + printf("Arret prolonge de l'hyper creux pour le calcul de ABarreS, iteration %d\n",Spx->Iteration); + # endif + Spx->CalculABarreSEnHyperCreuxPossible = NON_SPX; + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerABarreS( PROBLEME_SPX * Spx ) +{ +double * ABarreS; char OK; int IndexBase; int * CntDeABarreSNonNuls; int i; char TypeDEntree; +char TypeDeSortie; char CalculEnHyperCreux; char HyperCreuxInitial; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + SPX_CalculerABarreSAvecBaseReduite( Spx, &HyperCreuxInitial, &CalculEnHyperCreux, &TypeDEntree, &TypeDeSortie ); +} +else { + SPX_CalculerABarreSAvecBaseComplete( Spx, &HyperCreuxInitial, &CalculEnHyperCreux, &TypeDEntree, &TypeDeSortie ); +} + +ABarreS = Spx->ABarreS; +CntDeABarreSNonNuls = Spx->CntDeABarreSNonNuls; + +if ( CalculEnHyperCreux == OUI_SPX ) { + if ( TypeDeSortie != COMPACT_LU ) { + CalculEnHyperCreux = NON_SPX; + /* Ca s'est pas bien passe et on s'est forcement retrouve en VECTEUR_LU */ + Spx->NbEchecsABarreS++; + /*printf("Echec hyper creux ABarreS iteration %d\n",Spx->Iteration);*/ + if ( Spx->NbEchecsABarreS >= SEUIL_ECHEC_CREUX ) { + # if VERBOSE_SPX + printf("Arret de l'hyper creux pour le calcul de ABarreS, iteration %d\n",Spx->Iteration); + # endif + Spx->CalculABarreSEnHyperCreux = NON_SPX; + Spx->CountEchecsABarreS = 0; + } + } + else Spx->NbEchecsABarreS = 0; +} + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + IndexBase = Spx->OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]]; +} +else { + IndexBase = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; +} + +if ( CalculEnHyperCreux == OUI_SPX ) { + Spx->TypeDeStockageDeABarreS = COMPACT_SPX; + OK = NON_SPX; + for ( i = 0 ; i < Spx->NbABarreSNonNuls ; i++ ) { + if ( CntDeABarreSNonNuls[i] == IndexBase ) { + Spx->ABarreSCntBase = ABarreS[i]; + OK = OUI_SPX; + break; + } + } + if ( OK == NON_SPX ) { + /* Pb d'epsilon, on prend la aleur de NBarreR */ + Spx->ABarreSCntBase = Spx->NBarreR[Spx->VariableEntrante]; /* Valable que l'on soit en base reduite ou non */ + } +} +else { + Spx->TypeDeStockageDeABarreS = VECTEUR_SPX; + Spx->ABarreSCntBase = ABarreS[IndexBase]; + /* Si on est pas en hyper creux, on essaie d'y revenir */ + if ( HyperCreuxInitial == NON_SPX ) { + if ( Spx->CalculABarreSEnHyperCreux == NON_SPX ) { + if ( Spx->CalculABarreSEnHyperCreuxPossible == OUI_SPX ) { + SPX_TenterRestaurationCalculABarreSEnHyperCreux( Spx ); + } + } + } + +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_a_barre_s_avec_base_complete.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_a_barre_s_avec_base_complete.c new file mode 100644 index 0000000000..ed9cd5f810 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_a_barre_s_avec_base_complete.c @@ -0,0 +1,100 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de A_BARRE_S = B-1 * AS + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerABarreSAvecBaseComplete( PROBLEME_SPX * Spx, char * HyperCreuxInitial, + char * CalculEnHyperCreux, char * TypeDEntree, + char * TypeDeSortie ) +{ +int il; int ilMax; char Save; char SecondMembreCreux; double * ABarreS; int * Cdeb; int i; +int * CNbTerm; int * NumeroDeContrainte ; double * ACol; int NbTermesNonNuls; int * CntDeABarreSNonNuls; + +ABarreS = Spx->ABarreS; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; +ACol = Spx->ACol; + +CntDeABarreSNonNuls = NULL; + +*CalculEnHyperCreux = NON_SPX; +*HyperCreuxInitial = NON_SPX; +if ( Spx->TypeDeCreuxDeLaBase == BASE_HYPER_CREUSE && Spx->CalculABarreSEnHyperCreux == OUI_SPX && + Spx->FaireDuRaffinementIteratif <= 0 ) { + if ( CNbTerm[Spx->VariableEntrante] < TAUX_DE_REMPLISSAGE_POUR_VECTEUR_HYPER_CREUX * Spx->NombreDeContraintes ) { + *CalculEnHyperCreux = OUI_SPX; + *HyperCreuxInitial = OUI_SPX; + } +} + +if ( *CalculEnHyperCreux == OUI_SPX ) { + + CntDeABarreSNonNuls = Spx->CntDeABarreSNonNuls; + NbTermesNonNuls = 0; + il = Cdeb[Spx->VariableEntrante]; + ilMax = il + CNbTerm[Spx->VariableEntrante]; + while ( il < ilMax ) { + ABarreS [NbTermesNonNuls] = ACol[il]; + CntDeABarreSNonNuls[NbTermesNonNuls] = NumeroDeContrainte[il]; + NbTermesNonNuls++; + il++; + } + *TypeDEntree = COMPACT_LU; + *TypeDeSortie = COMPACT_LU; + +} +else { + + for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) ABarreS[i] = 0; + + il = Cdeb[Spx->VariableEntrante]; + ilMax = il + CNbTerm[Spx->VariableEntrante]; + while ( il < ilMax ) { + ABarreS[NumeroDeContrainte[il]] = ACol[il]; + il++; + } + *TypeDEntree = VECTEUR_LU; + *TypeDeSortie = VECTEUR_LU; + +} + +/* Resolution du systeme */ +Save = OUI_LU; /* Mis a NON_LU si pas de LU update */ +SecondMembreCreux = OUI_LU; +SPX_ResoudreBYegalA( Spx, *TypeDEntree, ABarreS, CntDeABarreSNonNuls, &NbTermesNonNuls, + TypeDeSortie, *CalculEnHyperCreux, Save, SecondMembreCreux ); + +Spx->NbABarreSNonNuls = NbTermesNonNuls; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_a_barre_s_avec_base_reduite.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_a_barre_s_avec_base_reduite.c new file mode 100644 index 0000000000..1cbaf50a46 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_a_barre_s_avec_base_reduite.c @@ -0,0 +1,195 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de A_BARRE_S = B-1 * AS + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +# define DEBUG NON_SPX + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerABarreSAvecBaseReduite( PROBLEME_SPX * Spx, char * HyperCreuxInitial, + char * CalculEnHyperCreux, char * TypeDEntree, + char * TypeDeSortie ) +{ +int il; int ilMax; char Save; char SecondMembreCreux; double * ABarreS; int * CdebProblemeReduit; +int * CNbTermProblemeReduit; int * IndicesDeLigneDesTermesDuProblemeReduit; int i; +double * ValeurDesTermesDesColonnesDuProblemeReduit; int NbTermesNonNuls; int * CntDeABarreSNonNuls; +int RangDeLaMatriceFactorisee; + +ABarreS = Spx->ABarreS; +CntDeABarreSNonNuls = Spx->CntDeABarreSNonNuls; + +CdebProblemeReduit = Spx->CdebProblemeReduit; +CNbTermProblemeReduit = Spx->CNbTermProblemeReduit; +IndicesDeLigneDesTermesDuProblemeReduit = Spx->IndicesDeLigneDesTermesDuProblemeReduit; +ValeurDesTermesDesColonnesDuProblemeReduit = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; + +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; + +*CalculEnHyperCreux = NON_SPX; +*HyperCreuxInitial = NON_SPX; +if ( Spx->TypeDeCreuxDeLaBase == BASE_HYPER_CREUSE && Spx->CalculABarreSEnHyperCreux == OUI_SPX && + Spx->FaireDuRaffinementIteratif <= 0 ) { + if ( CNbTermProblemeReduit[Spx->VariableEntrante] < TAUX_DE_REMPLISSAGE_POUR_VECTEUR_HYPER_CREUX * RangDeLaMatriceFactorisee ) { + *CalculEnHyperCreux = OUI_SPX; + *HyperCreuxInitial = OUI_SPX; + } +} + +NbTermesNonNuls = 0; + +if ( *CalculEnHyperCreux == OUI_SPX ) { + il = CdebProblemeReduit[Spx->VariableEntrante]; + ilMax = il + CNbTermProblemeReduit[Spx->VariableEntrante]; + while ( il < ilMax ) { + ABarreS[NbTermesNonNuls] = ValeurDesTermesDesColonnesDuProblemeReduit[il]; /* On evite ainsi la raz qui serait necessaire de tout le vecteur ABarreS */ + CntDeABarreSNonNuls[NbTermesNonNuls] = IndicesDeLigneDesTermesDuProblemeReduit[il]; + NbTermesNonNuls++; + il++; + } + *TypeDEntree = COMPACT_LU; + *TypeDeSortie = COMPACT_LU; +} +else { + for ( i = 0 ; i < RangDeLaMatriceFactorisee ; i++ ) ABarreS[i] = 0; + + il = CdebProblemeReduit[Spx->VariableEntrante]; + ilMax = il + CNbTermProblemeReduit[Spx->VariableEntrante]; + while ( il < ilMax ) { + ABarreS[IndicesDeLigneDesTermesDuProblemeReduit[il]] = ValeurDesTermesDesColonnesDuProblemeReduit[il]; + il++; + } + *TypeDEntree = VECTEUR_LU; + *TypeDeSortie = VECTEUR_LU; +} + +/* Resolution du systeme */ +Save = OUI_LU; /* Mis a NON_LU si pas de LU update */ +SecondMembreCreux = OUI_LU; + +SPX_ResolutionDeSysteme( Spx, *TypeDEntree, ABarreS, CntDeABarreSNonNuls, &NbTermesNonNuls, + TypeDeSortie, *CalculEnHyperCreux, Save, SecondMembreCreux ); + + +/* +printf("---------------- CalculerABarreS Spx->NombreDeChangementsDeBase %d -------------\n",Spx->NombreDeChangementsDeBase); +if ( *TypeDEntree == VECTEUR_LU ) printf("apres resolution TypeDEntree = VECTEUR_LU\n"); +if ( *TypeDEntree == COMPACT_LU ) printf("apres resolution TypeDEntree = COMPACT_LU\n"); +if ( *TypeDEntree == ADRESSAGE_INDIRECT_LU ) printf("apres resolution TypeDEntree = ADRESSAGE_INDIRECT_LU\n"); +if ( *TypeDeSortie == VECTEUR_LU ) printf("apres resolution TypeDeSortie = VECTEUR_LU\n"); +if ( *TypeDeSortie == COMPACT_LU ) printf("apres resolution TypeDeSortie = COMPACT_LU\n"); +*/ + +/* Eventuellement forme produit de l'inverse */ +if ( Spx->UtiliserLaLuUpdate == NON_SPX ) { + printf("CalculerBBarre AppliquerLesEtaVecteurs pas operationnel \n"); + exit(0); + SPX_AppliquerLesEtaVecteurs( Spx, ABarreS, CntDeABarreSNonNuls, &NbTermesNonNuls, *CalculEnHyperCreux, *TypeDeSortie ); +} + +Spx->NbABarreSNonNuls = NbTermesNonNuls; + +# if VERIFICATION_ABARRES == OUI_SPX +printf("---------------- CalculerABarreS Spx->NombreDeChangementsDeBase %d -------------\n",Spx->NombreDeChangementsDeBase); +if ( *TypeDEntree == VECTEUR_LU ) printf("apres resolution TypeDEntree = VECTEUR_LU\n"); +if ( *TypeDEntree == COMPACT_LU ) printf("apres resolution TypeDEntree = COMPACT_LU\n"); +if ( *TypeDeSortie == VECTEUR_LU ) printf("apres resolution TypeDeSortie = VECTEUR_LU\n"); +if ( *TypeDeSortie == COMPACT_LU ) printf("apres resolution TypeDeSortie = COMPACT_LU\n"); +{ +double * Buff; int i; int Var; int ic; int icMx; double * Sortie; char Arret; +int * VariableEnBaseDeLaContrainte; int rr; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +Buff = (double *) malloc( RangDeLaMatriceFactorisee * sizeof( double ) ); +Sortie = (double *) malloc( RangDeLaMatriceFactorisee * sizeof( double ) ); +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) Sortie[r]= 0; +if ( *TypeDeSortie == COMPACT_LU ) { + for ( i = 0 ; i < NbTermesNonNuls ; i++ ) { + Sortie[CntDeABarreSNonNuls[i]] = ABarreS[i]; + } +} +else { + for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) Sortie[r] = ABarreS[r]; +} +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) Buff[r]= 0; +Var = Spx->VariableEntrante; +ic = Cdeb[Var]; +icMx = ic + CNbTerm[Var]; +while ( ic < icMx ) { + Cnt = NumeroDeContrainte[ic]; + r = OrdreLigneDeLaBaseFactorisee[Cnt]; + if ( r < RangDeLaMatriceFactorisee ) { + Buff[r] = ACol[ic]; + } + ic++; +} + +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + if ( Sortie[r] == 0 ) continue; + Var = Spx->VariableEnBaseDeLaContrainte[Spx->ColonneDeLaBaseFactorisee[r]]; + ic = Spx->Cdeb[Var]; + icMx = ic + Spx->CNbTerm[Var]; + while ( ic < icMx ) { + Cnt = NumeroDeContrainte[ic]; + rr = OrdreLigneDeLaBaseFactorisee[Cnt]; + if ( rr < RangDeLaMatriceFactorisee ) { + Buff[rr] -= ACol[ic] * Sortie[r]; + } + ic++; + } +} +Arret = NON_SPX; +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + if ( fabs( Buff[r] ) > 1.e-7 ) { + printf("r = %d ecart %e\n",r,Buff[r]); + Var = Spx->VariableEnBaseDeLaContrainte[Spx->ColonneDeLaBaseFactorisee[r]]; + if ( Spx->OrigineDeLaVariable[Var] != NATIVE ) printf(" variable non native\n"); + else printf(" variable native\n"); + Arret = OUI_SPX; + } +} +if ( Arret == OUI_SPX ) { + printf("Verif ABarreS not OK\n"); + exit(0); +} +printf("Fin verif ABarreS OK\n"); +free( Buff ); +free( Sortie ); + +} + +SPX_VerifierLesVecteursDeTravail( Spx ); + +# endif + +return; +} + +/*----------------------------------------------------------------------------*/ + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_b_barre.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_b_barre.c new file mode 100644 index 0000000000..b21763d93a --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_b_barre.c @@ -0,0 +1,51 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de BBarre = B^{-1} * b + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerBBarre( PROBLEME_SPX * Spx ) +{ + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + SPX_CalculerBBarreAvecBaseReduite( Spx ); +} +else { + SPX_CalculerBBarreAvecBaseComplete( Spx ); +} + +Spx->BBarreAEteCalculeParMiseAJour = NON_SPX; + +SPX_InitialiserLesVariablesEnBaseAControler( Spx ); + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_b_barre_avec_base_complete.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_b_barre_avec_base_complete.c new file mode 100644 index 0000000000..57c4537c58 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_b_barre_avec_base_complete.c @@ -0,0 +1,121 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de BBarre = B^{-1} * b + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerBBarreAvecBaseComplete( PROBLEME_SPX * Spx ) +{ +int Var; int il; int ilMax; char Save; char SecondMembreCreux; double * BBarre; +double * B; char * PositionDeLaVariable; int * NumeroDeContrainte; double * ACol; +int * Cdeb; int * CNbTerm; double * Xmax; double XmaxDeVar; +int NombreDeBornesAuxiliairesUtilisees; char * StatutBorneSupCourante; +char TypeDEntree; char TypeDeSortie; char CalculEnHyperCreux; + +BBarre = Spx->BBarre; +B = Spx->B; +memcpy( (char *) BBarre , ( char *) B , Spx->NombreDeContraintes * sizeof( double ) ); + +PositionDeLaVariable = Spx->PositionDeLaVariable; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +ACol = Spx->ACol; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; + +Xmax = Spx->Xmax; + +NombreDeBornesAuxiliairesUtilisees = Spx->NombreDeBornesAuxiliairesUtilisees; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; + +/* On calcule B^{-1} * N * Xmax pour les variables hors base sur borne sup */ +/* Ne pas utiliser la liste des variables hors base car elle evolue */ +if ( NombreDeBornesAuxiliairesUtilisees == 0 ) { + /* Seules les variables natives peuvent se trouver sur borne sup. Certes + les variables aditionnelles de contraintes d'egalite aussi mais leur + borne sup est nulle de toutes facons */ + for ( Var = 0 ; Var < Spx->NombreDeVariablesNatives ; Var++ ) { + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + if ( Xmax[Var] == 0.0 ) continue; + XmaxDeVar = Xmax[Var]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + BBarre[NumeroDeContrainte[il]] -= ACol[il] * XmaxDeVar; + il++; + } + continue; + } + } +} +else { + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + if ( Xmax[Var] == 0.0 ) continue; + XmaxDeVar = Xmax[Var]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + BBarre[NumeroDeContrainte[il]] -= ACol[il] * XmaxDeVar; + il++; + } + continue; + } + else if ( StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) { + /* Prise en compte des bornes inf auxiliaires sur les variables non bornees */ + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + /* Car on simule le fait qu'on a cree une borne inf egale a -Xmax */ + XmaxDeVar = -Xmax[Var]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + BBarre[NumeroDeContrainte[il]] -= ACol[il] * XmaxDeVar; + il++; + } + } + } + } +} + +/* Resoudre BBarre = B^{-1} * b */ + +TypeDEntree = VECTEUR_LU; +TypeDeSortie = VECTEUR_LU; +CalculEnHyperCreux = NON_SPX; + +Save = NON_LU; +SecondMembreCreux = NON_LU; +SPX_ResoudreBYegalA( Spx, TypeDEntree, BBarre, NULL, NULL, &TypeDeSortie, + CalculEnHyperCreux, Save, SecondMembreCreux ); + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_b_barre_avec_base_reduite.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_b_barre_avec_base_reduite.c new file mode 100644 index 0000000000..3d43a29936 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_b_barre_avec_base_reduite.c @@ -0,0 +1,225 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de BBarre = B^{-1} * b + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +# define DEBUG NON_SPX + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerBBarreAvecBaseReduite( PROBLEME_SPX * Spx ) +{ +int Var; int il; int ilMax; char Save; char SecondMembreCreux; double * BBarre; +double * B; char * PositionDeLaVariable; int * IndicesDeLigneDesTermesDuProblemeReduit; +double * ValeurDesTermesDesColonnesDuProblemeReduit; int * CdebProblemeReduit; +int * CNbTermProblemeReduit; double * Xmax; double XmaxDeVar; int NombreDeBornesAuxiliairesUtilisees; +char * StatutBorneSupCourante; char TypeDEntree; char TypeDeSortie; char CalculEnHyperCreux; +int r; int RangDeLaMatriceFactorisee; int * LigneDeLaBaseFactorisee; + +BBarre = Spx->BBarre; +B = Spx->B; + +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; +LigneDeLaBaseFactorisee = Spx->LigneDeLaBaseFactorisee; + +CdebProblemeReduit = Spx->CdebProblemeReduit; +CNbTermProblemeReduit = Spx->CNbTermProblemeReduit; +IndicesDeLigneDesTermesDuProblemeReduit = Spx->IndicesDeLigneDesTermesDuProblemeReduit; +ValeurDesTermesDesColonnesDuProblemeReduit = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; + +Xmax = Spx->Xmax; + +PositionDeLaVariable = Spx->PositionDeLaVariable; + +NombreDeBornesAuxiliairesUtilisees = Spx->NombreDeBornesAuxiliairesUtilisees; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; + +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + BBarre[r] = B[LigneDeLaBaseFactorisee[r]]; +} + +/* On calcule B^{-1} * N * Xmax pour les variables hors base sur borne sup */ +/* Ne pas utiliser la liste des variables hors base car elle evolue */ +if ( NombreDeBornesAuxiliairesUtilisees == 0 ) { + /* Seules les variables natives peuvent se trouver sur borne sup. Certes + les variables aditionnelles de contraintes d'egalite aussi mais leur + borne sup est nulle de toutes facons */ + for ( Var = 0 ; Var < Spx->NombreDeVariablesNatives ; Var++ ) { + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + if ( Xmax[Var] == 0.0 ) continue; + XmaxDeVar = Xmax[Var]; + il = CdebProblemeReduit[Var]; + ilMax = il + CNbTermProblemeReduit[Var]; + while ( il < ilMax ) { + BBarre[IndicesDeLigneDesTermesDuProblemeReduit[il]] -= ValeurDesTermesDesColonnesDuProblemeReduit[il] * XmaxDeVar; + il++; + } + continue; + } + } +} +else { + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + if ( Xmax[Var] == 0.0 ) continue; + XmaxDeVar = Xmax[Var]; + il = CdebProblemeReduit[Var]; + ilMax = il + CNbTermProblemeReduit[Var]; + while ( il < ilMax ) { + BBarre[IndicesDeLigneDesTermesDuProblemeReduit[il]] -= ValeurDesTermesDesColonnesDuProblemeReduit[il] * XmaxDeVar; + il++; + } + continue; + } + else if ( StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) { + /* Prise en compte des bornes inf auxiliaires sur les variables non bornees */ + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + /* Car on simule le fait qu'on a cree une borne inf egale a -Xmax */ + XmaxDeVar = -Xmax[Var]; + il = CdebProblemeReduit[Var]; + ilMax = il + CNbTermProblemeReduit[Var]; + while ( il < ilMax ) { + BBarre[IndicesDeLigneDesTermesDuProblemeReduit[il]] -= ValeurDesTermesDesColonnesDuProblemeReduit[il] * XmaxDeVar; + il++; + } + } + } + } +} + +/* Resoudre BBarre = B^{-1} * b */ + +TypeDEntree = VECTEUR_LU; +TypeDeSortie = VECTEUR_LU; +CalculEnHyperCreux = NON_SPX; + +Save = NON_LU; +SecondMembreCreux = NON_LU; + +SPX_ResolutionDeSysteme( Spx, TypeDEntree, BBarre, NULL, NULL, &TypeDeSortie, + CalculEnHyperCreux, Save, SecondMembreCreux ); + +/* Eventuellement forme produit de l'inverse */ +if ( Spx->UtiliserLaLuUpdate == NON_SPX ) { + printf("CalculerBBarre AppliquerLesEtaVecteurs pas operationnel \n"); + exit(0); + SPX_AppliquerLesEtaVecteurs( Spx, BBarre, NULL, NULL, CalculEnHyperCreux, TypeDeSortie ); +} + +# if VERIFICATION_BBARRE == OUI_SPX +printf("----------- CalculerBBarre Iteration %d ---------------- \n",Spx->Iteration); +{ +double * Buff; int i; int Var; int ic; int icMx; double * Sortie; char Arret; +Buff = (double *) malloc( Spx->NombreDeContraintes * sizeof( double ) ); +Sortie = (double *) malloc( Spx->NombreDeContraintes * sizeof( double ) ); +memcpy( (char *) Buff, ( char *) Spx->B, Spx->NombreDeContraintes * sizeof( double ) ); +if ( NombreDeBornesAuxiliairesUtilisees == 0 ) { + /* Seules les variables natives peuvent se trouver sur borne sup. Certes + les variables aditionnelles de contraintes d'egalite aussi mais leur + borne sup est nulle de toutes facons */ + for ( Var = 0 ; Var < Spx->NombreDeVariablesNatives ; Var++ ) { + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + if ( Xmax[Var] == 0.0 ) continue; + XmaxDeVar = Xmax[Var]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + Buff[NumeroDeContrainte[il]] -= ACol[il] * XmaxDeVar; + il++; + } + continue; + } + } +} +else { + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + if ( Xmax[Var] == 0.0 ) continue; + XmaxDeVar = Xmax[Var]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + Buff[NumeroDeContrainte[il]] -= ACol[il] * XmaxDeVar; + il++; + } + continue; + } + else if ( StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) { + /* Prise en compte des bornes inf auxiliaires sur les variables non bornees */ + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + /* Car on simule le fait qu'on a cree une borne inf egale a -Xmax */ + XmaxDeVar = -Xmax[Var]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + Buff[NumeroDeContrainte[il]] -= ACol[il] * XmaxDeVar; + il++; + } + } + } + } +} + +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) Sortie[i] = BBarre[i]; +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + Var = Spx->VariableEnBaseDeLaContrainte[i]; + ic = Spx->Cdeb[Var]; + icMx = ic + Spx->CNbTerm[Var]; + while ( ic < icMx ) { + Buff[NumeroDeContrainte[ic]] -= ACol[ic] * Sortie[i]; + ic++; + } +} +Arret = NON_SPX; +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + if ( fabs( Buff[i] ) > 1.e-7 ) { + printf("i = %d ecart %e VariableEnBaseDeLaContrainte %d\n",i,Buff[i],Spx->VariableEnBaseDeLaContrainte[i]); + Var = Spx->VariableEnBaseDeLaContrainte[i]; + if ( Spx->OrigineDeLaVariable[Var] != NATIVE ) printf(" variable non native\n"); + else printf(" variable native\n"); + Arret = OUI_SPX; + } +} +if ( Arret == OUI_SPX ) { + printf("Verif Bbarre not OK\n"); + exit(0); +} +printf("Fin verif Bbarre OK\n"); +free( Buff ); +free( Sortie ); + +SPX_VerifierLesVecteursDeTravail( Spx ); + +} +# endif + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_bbarre_hors_base_reduite.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_bbarre_hors_base_reduite.c new file mode 100644 index 0000000000..b57f72199c --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_bbarre_hors_base_reduite.c @@ -0,0 +1,143 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de BBarre = B^{-1} * b pour les contraintes/variables + hors base reduite. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +# define DEBUG NON_SPX + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerBBarreAHorsReduite( PROBLEME_SPX * Spx ) +{ +int il; int ilMax; double * BBarre; double * B; char * PositionDeLaVariable; +double * Xmax; int NombreDeBornesAuxiliairesUtilisees; char * StatutBorneSupCourante; +int Cnt; int Var1; int r; double * A; int * Mdeb; int * NbTerm; double ValBBarre; +int * ContrainteDeLaVariableEnBase; int * Indcol; int RangDeLaMatriceFactorisee; +int * LigneDeLaBaseFactorisee; char Position; double * Bs; int * ColonneDeLaBaseFactorisee; +int Var; double Coeff; + +if ( Spx->UtiliserLaBaseReduite == NON_SPX ) return; + +BBarre = Spx->BBarre; +B = Spx->B; +Bs = Spx->Bs; + +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; +LigneDeLaBaseFactorisee = Spx->LigneDeLaBaseFactorisee; +ColonneDeLaBaseFactorisee = Spx->ColonneDeLaBaseFactorisee; + +Xmax = Spx->Xmax; + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; +PositionDeLaVariable = Spx->PositionDeLaVariable; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; + +NombreDeBornesAuxiliairesUtilisees = Spx->NombreDeBornesAuxiliairesUtilisees; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; + +/* A ce stade les valeurs de BBarre dans la base reduite sont classes de 0 a RangDeLaMatriceFactorisee. + On les reclasse par mesure de precaution */ +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + Bs[ColonneDeLaBaseFactorisee[r]] = BBarre[r]; /* Il faut les sauvegarder dans Bs */ +} +/* Puis on les remet dans BBarre */ +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + Cnt = ColonneDeLaBaseFactorisee[r]; + BBarre[Cnt] = Bs[Cnt]; + Bs[Cnt] = 0; +} + +if ( NombreDeBornesAuxiliairesUtilisees == 0 ) { + for ( r = RangDeLaMatriceFactorisee ; r < Spx->NombreDeContraintes ; r++ ) { + Cnt = LigneDeLaBaseFactorisee[r]; + Var = Spx->VariableEnBaseDeLaContrainte[ColonneDeLaBaseFactorisee[r]]; + ValBBarre = B[Cnt]; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + Coeff = 1; + while ( il < ilMax ) { + Var1 = Indcol[il]; + if ( Var1 == Var ) { + Coeff = A[il]; + goto NextIl_0; + } + Position = PositionDeLaVariable[Var1]; + if ( Position == EN_BASE_LIBRE ) { + ValBBarre -= A[il] * BBarre[ContrainteDeLaVariableEnBase[Var1]]; + } + else if ( Position == HORS_BASE_SUR_BORNE_SUP ) { + ValBBarre -= A[il] * Xmax[Var1]; + } + NextIl_0: + il++; + } + BBarre[ContrainteDeLaVariableEnBase[Var]] = ValBBarre/Coeff; /* C'est la variable non native */ + } +} +else { + for ( r = RangDeLaMatriceFactorisee ; r < Spx->NombreDeContraintes ; r++ ) { + Cnt = LigneDeLaBaseFactorisee[r]; + Var = Spx->VariableEnBaseDeLaContrainte[ColonneDeLaBaseFactorisee[r]]; + ValBBarre = B[Cnt]; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + Coeff = 1; + while ( il < ilMax ) { + Var1 = Indcol[il]; + if ( Var1 == Var ) { + Coeff = A[il]; + goto NextIl_1; + } + Position = PositionDeLaVariable[Var1]; + if ( Position == EN_BASE_LIBRE ) { + ValBBarre -= A[il] * BBarre[ContrainteDeLaVariableEnBase[Var1]]; + } + else if ( Position == HORS_BASE_SUR_BORNE_SUP ) { + ValBBarre -= A[il] * Xmax[Var1]; + } + else if ( Position == HORS_BASE_SUR_BORNE_INF ) { + if ( StatutBorneSupCourante[Var1] == BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) { + printf("CalculerBBarreAHorsReduite variable non bornee sur borne inf fictive %d\n",Var1); + ValBBarre += A[il] * Xmax[Var1]; + } + } + NextIl_1: + il++; + } + BBarre[ContrainteDeLaVariableEnBase[Var]] = ValBBarre/Coeff; /* C'est la variable non native */ + } +} + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_erbmoins1.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_erbmoins1.c new file mode 100644 index 0000000000..05f3fbe099 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_erbmoins1.c @@ -0,0 +1,46 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution du systeme transpose pour obtenir une ligne + de l'inverse de la base + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ +/* Calcul de la ligne de B^{-1} de la variable sortante */ +void SPX_CalculerErBMoins1( PROBLEME_SPX * Spx, char CalculEnHyperCreux ) +{ + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + SPX_CalculerErBMoins1AvecBaseReduite( Spx, CalculEnHyperCreux ); +} +else { + SPX_CalculerErBMoins1AvecBaseComplete( Spx, CalculEnHyperCreux ); +} + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_erbmoins1_avec_base_complete.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_erbmoins1_avec_base_complete.c new file mode 100644 index 0000000000..9a94e87f22 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_erbmoins1_avec_base_complete.c @@ -0,0 +1,79 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution du systeme transpose pour obtenir une ligne + de l'inverse de la base + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ +/* Calcul de la ligne de B^{-1} de la variable sortante */ +void SPX_CalculerErBMoins1AvecBaseComplete( PROBLEME_SPX * Spx, char CalculEnHyperCreux ) +{ +char TypeDEntree; char TypeDeSortie; int i; double * ErBMoinsUn; + +if ( CalculEnHyperCreux != OUI_SPX ) { + TypeDEntree = VECTEUR_LU; + TypeDeSortie = VECTEUR_LU; + /*memset( (char *) Spx->ErBMoinsUn , 0 , Spx->NombreDeContraintes * sizeof( double ) );*/ + ErBMoinsUn = Spx->ErBMoinsUn; + for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) ErBMoinsUn[i] = 0.0; + + Spx->ErBMoinsUn[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]] = 1.; +} +else { + TypeDEntree = COMPACT_LU; + TypeDeSortie = COMPACT_LU; + Spx->ErBMoinsUn[0] = 1; + Spx->IndexTermesNonNulsDeErBMoinsUn[0] = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; + Spx->NbTermesNonNulsDeErBMoinsUn = 1; +} + +SPX_ResoudreUBEgalC( Spx, TypeDEntree, Spx->ErBMoinsUn, Spx->IndexTermesNonNulsDeErBMoinsUn, + &(Spx->NbTermesNonNulsDeErBMoinsUn), &TypeDeSortie, CalculEnHyperCreux ); + +if ( CalculEnHyperCreux == OUI_SPX ) { + if ( TypeDeSortie != TypeDEntree ) { + /* Ca s'est pas bien passe et on s'est forcement retrouve en VECTEUR_LU */ + Spx->TypeDeStockageDeErBMoinsUn = VECTEUR_SPX; + Spx->NbEchecsErBMoins++; + /* + printf("SPX_CalculerErBMoins1 echec hyper creux ErBMoins1 iteration %d\n",Spx->Iteration); + */ + if ( Spx->NbEchecsErBMoins >= SEUIL_ECHEC_CREUX ) { + # if VERBOSE_SPX + printf("Arret de l'hyper creux pour le calcul de la ligne pivot, iteration %d\n",Spx->Iteration); + # endif + Spx->CalculErBMoinsUnEnHyperCreux = NON_SPX; + Spx->CountEchecsErBMoins = 0; + } + } + else Spx->NbEchecsErBMoins = 0; +} + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_erbmoins1_avec_base_reduite.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_erbmoins1_avec_base_reduite.c new file mode 100644 index 0000000000..06f4001e8e --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_erbmoins1_avec_base_reduite.c @@ -0,0 +1,211 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution du systeme transpose pour obtenir une ligne + de l'inverse de la base + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +# define DEBUG NON_SPX + +/*----------------------------------------------------------------------------*/ +/* Calcul de la ligne de B^{-1} de la variable sortante */ +void SPX_CalculerErBMoins1AvecBaseReduite( PROBLEME_SPX * Spx, char CalculEnHyperCreux ) +{ +double * ErBMoinsUn; int * IndexTermesNonNulsDeErBMoinsUn; int i; int Cnt; +char TypeDEntree; char ResoudreLeSystemeReduit; char TypeDeSortie; char SecondMembreCreux; +char * PositionDeLaVariable; double * AReduit; int * IndexAReduit; +int RangDeLaMatriceFactorisee; int NombreDeTermesNonNulsDuVecteurReduit; +int * OrdreColonneDeLaBaseFactorisee; int * Mdeb; int * NbTerm; int * Indcol; +double * A; int r; int CntVarSor; int * ContrainteDeLaVariableEnBase; +int NbTermesNonNulsDeErBMoinsUn; int * LigneDeLaBaseFactorisee; + +ErBMoinsUn = Spx->ErBMoinsUn; +IndexTermesNonNulsDeErBMoinsUn = Spx->IndexTermesNonNulsDeErBMoinsUn; +NbTermesNonNulsDeErBMoinsUn = 0; + +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +PositionDeLaVariable = Spx->PositionDeLaVariable; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; + +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; +AReduit = Spx->AReduit; +IndexAReduit = Spx->IndexAReduit; +OrdreColonneDeLaBaseFactorisee = Spx->OrdreColonneDeLaBaseFactorisee; +LigneDeLaBaseFactorisee = Spx->LigneDeLaBaseFactorisee; + +CntVarSor = ContrainteDeLaVariableEnBase[Spx->VariableSortante]; +ResoudreLeSystemeReduit = NON_SPX; + +/* Remarque: a ce stade toutes les AReduit composantes de sont nulles */ + +if ( CalculEnHyperCreux != OUI_SPX ) { + TypeDEntree = VECTEUR_LU; + TypeDeSortie = VECTEUR_LU; + SecondMembreCreux = NON_SPX; + + r = OrdreColonneDeLaBaseFactorisee[CntVarSor]; + if ( r < RangDeLaMatriceFactorisee ) { + ResoudreLeSystemeReduit = OUI_SPX; + AReduit[r] = 1; + } + else { + /* Ca ne peut pas arriver */ + printf("CalculerErBMoins1AvecBaseReduite bug: variable sortante hors base reduite impossible\n"); + exit(0); + } +} +else { + TypeDEntree = COMPACT_LU; + TypeDeSortie = COMPACT_LU; + SecondMembreCreux = OUI_SPX; + NombreDeTermesNonNulsDuVecteurReduit = 0; + + r = OrdreColonneDeLaBaseFactorisee[CntVarSor]; + if ( r < RangDeLaMatriceFactorisee ) { + ResoudreLeSystemeReduit = OUI_SPX; + AReduit[NombreDeTermesNonNulsDuVecteurReduit] = 1; + IndexAReduit[NombreDeTermesNonNulsDuVecteurReduit] = r; + NombreDeTermesNonNulsDuVecteurReduit++; + } + else { + /* Ca ne peut pas arriver */ + printf("CalculerErBMoins1AvecBaseReduite bug: variable sortante hors base reduite impossible\n"); + exit(0); + } +} + +/* Eventuellement les Eta vecteurs */ +/* Attention il faut pas faire comme ca mais resoudre tout le systeme avec les eta */ +/* +if ( Spx->UtiliserLaLuUpdate == NON_SPX ) { + SPX_AppliquerLesEtaVecteursTransposee( Spx, Pi, IndexDesTermesNonNuls, NombreDeTermesNonNuls, + CalculEnHyperCreux, TypeDEntree ); +} +*/ + +SPX_ResolutionDeSystemeTransposee( Spx, TypeDEntree, AReduit, IndexAReduit, &NombreDeTermesNonNulsDuVecteurReduit, + &TypeDeSortie, CalculEnHyperCreux, SecondMembreCreux ); + +if ( TypeDeSortie == VECTEUR_LU ) { + for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) ErBMoinsUn[Cnt] = 0.0; + /* On complete avec la partie de la base reduite */ + for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + ErBMoinsUn[LigneDeLaBaseFactorisee[r]] = AReduit[r]; + AReduit[r] = 0; + } +} +else { + /* TypeDeSortie = COMPACT_LU */ + /* Le type d'entree est forcement COMPACT_LU */ + for ( i = 0 ; i < NombreDeTermesNonNulsDuVecteurReduit ; i++ ) { + ErBMoinsUn[NbTermesNonNulsDeErBMoinsUn] = AReduit[i]; + AReduit[i] = 0; + IndexTermesNonNulsDeErBMoinsUn[NbTermesNonNulsDeErBMoinsUn] = LigneDeLaBaseFactorisee[IndexAReduit[i]]; + NbTermesNonNulsDeErBMoinsUn++; + } + Spx->NbTermesNonNulsDeErBMoinsUn = NbTermesNonNulsDeErBMoinsUn; +} + +if ( CalculEnHyperCreux == OUI_SPX ) { + if ( TypeDeSortie != TypeDEntree ) { + /* Ca s'est pas bien passe et on s'est forcement retrouve en VECTEUR_LU */ + Spx->TypeDeStockageDeErBMoinsUn = VECTEUR_SPX; + Spx->NbEchecsErBMoins++; + /* + printf("SPX_CalculerErBMoins1 echec hyper creux ErBMoins1 iteration %d\n",Spx->Iteration); + */ + if ( Spx->NbEchecsErBMoins >= SEUIL_ECHEC_CREUX ) { + # if VERBOSE_SPX + printf("Arret de l'hyper creux pour le calcul de la ligne pivot, iteration %d\n",Spx->Iteration); + # endif + Spx->CalculErBMoinsUnEnHyperCreux = NON_SPX; + Spx->CountEchecsErBMoins = 0; + } + } + else Spx->NbEchecsErBMoins = 0; +} + +# if VERIFICATION_ERBMOINS1 == OUI_SPX +printf("------------- CalculerErBMoins1 Spx->NombreDeChangementsDeBase %d Iteration %d ---\n",Spx->NombreDeChangementsDeBase,Spx->Iteration); +if ( TypeDEntree == VECTEUR_LU ) printf("TypeDEntree = VECTEUR_LU\n"); +if ( TypeDEntree == COMPACT_LU ) printf("TypeDEntree = COMPACT_LU\n"); +if ( TypeDeSortie == VECTEUR_LU ) printf("TypeDeSortie = VECTEUR_LU\n"); +if ( TypeDeSortie == COMPACT_LU ) printf("TypeDeSortie = COMPACT_LU\n"); +{ +double * Buff; int i; int Var; int ic; int icMx; double S; double * Sortie; char Arret; +Buff = (double *) malloc( Spx->NombreDeContraintes * sizeof( double ) ); +Sortie = (double *) malloc( Spx->NombreDeContraintes * sizeof( double ) ); +if ( TypeDeSortie == COMPACT_LU ) { + for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) Sortie[i] = 0; + for ( i = 0 ; i < NbTermesNonNulsDeErBMoinsUn ; i++ ) Sortie[IndexTermesNonNulsDeErBMoinsUn[i]] = ErBMoinsUn[i]; +} +else { + for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) Sortie[i] = Spx->ErBMoinsUn[i]; +} +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) Buff[i] = 0; +Buff[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]] = 1.; +Arret = NON_SPX; +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + Var = Spx->VariableEnBaseDeLaContrainte[i]; + ic = Spx->Cdeb[Var]; + icMx = ic + Spx->CNbTerm[Var]; + S = 0; + while ( ic < icMx ) { + S += Spx->ACol[ic] * Sortie[Spx->NumeroDeContrainte[ic]]; + ic++; + } + if ( fabs( S - Buff[i] ) > 1.e-7 ) { + printf("i = %d S %e Buff %e ecart %e\n",i,S,Buff[i],fabs( S - Buff[i] )); + printf("Var = %d\n",Var); + ic = Spx->Cdeb[Var]; + icMx = ic + Spx->CNbTerm[Var]; + while ( ic < icMx ) { + printf("NumeroDeContrainte[%d] = %d Sortie = %e ACol = %e\n",ic,Spx->NumeroDeContrainte[ic],Sortie[Spx->NumeroDeContrainte[ic]],Spx->ACol[ic]); + ic++; + } + Arret = OUI_SPX; + } +} +if ( Arret == OUI_SPX ) { + printf("RangDeLaMatriceFactorisee %d NombreDeContraintes %d\n",Spx->RangDeLaMatriceFactorisee,Spx->NombreDeContraintes); + exit(0); +} +printf("Fin verif erbmoins1 OK\n"); +free( Buff ); +free( Sortie ); + +SPX_VerifierLesVecteursDeTravail( Spx ); + +} +# endif + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_pi.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_pi.c new file mode 100644 index 0000000000..90b3f5d7f9 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_pi.c @@ -0,0 +1,56 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de Pi = c_B * B^{-1} c'est a dire + resolution de u B = c + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerPi( PROBLEME_SPX * Spx ) +{ + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + SPX_CalculerPiAvecBaseReduite( Spx ); +} +else { + SPX_CalculerPiAvecBaseComplete( Spx ); +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Mise a jour de Pi */ + +void SPX_MettreAJourPi( /* PROBLEME_SPX * Spx */ ) +{ +/* A faire dans le futur car cela n'a pas grand interet */ + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_pi_avec_base_complete.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_pi_avec_base_complete.c new file mode 100644 index 0000000000..86082cb665 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_pi_avec_base_complete.c @@ -0,0 +1,58 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de Pi = c_B * B^{-1} c'est a dire + resolution de u B = c + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerPiAvecBaseComplete( PROBLEME_SPX * Spx ) +{ +int Cnt; double * Pi; double * C; int * VariableEnBaseDeLaContrainte; +char TypeDEntree; char TypeDeSortie; char CalculEnHyperCreux; + +Pi = Spx->Pi; +C = Spx->C; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + +/* Boucle sur les variables en base */ +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + Pi[Cnt] = C[VariableEnBaseDeLaContrainte[Cnt]]; +} + +TypeDEntree = VECTEUR_LU; +TypeDeSortie = VECTEUR_LU; +CalculEnHyperCreux = NON_SPX; +SPX_ResoudreUBEgalC( Spx, TypeDEntree, Pi, NULL, NULL, NULL, CalculEnHyperCreux ); + +return; +} + +/*----------------------------------------------------------------------------*/ + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_pi_avec_base_reduite.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_pi_avec_base_reduite.c new file mode 100644 index 0000000000..2405e00111 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_pi_avec_base_reduite.c @@ -0,0 +1,119 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de Pi = c_B * B^{-1} c'est a dire + resolution de u B = c + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerPiAvecBaseReduite( PROBLEME_SPX * Spx ) +{ +int Cnt; double * Pi; double * C; int * VariableEnBaseDeLaContrainte; char TypeDEntree; +char TypeDeSortie; char CalculEnHyperCreux; char SecondMembreCreux; double * AReduit; +int * IndexAReduit; int RangDeLaMatriceFactorisee; int NombreDeTermesNonNulsDuVecteurReduit; +int * OrdreColonneDeLaBaseFactorisee; int * LigneDeLaBaseFactorisee; int r; + +Pi = Spx->Pi; +C = Spx->C; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; +AReduit = Spx->AReduit; +IndexAReduit = Spx->IndexAReduit; +OrdreColonneDeLaBaseFactorisee = Spx->OrdreColonneDeLaBaseFactorisee; +LigneDeLaBaseFactorisee = Spx->LigneDeLaBaseFactorisee; + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + r = OrdreColonneDeLaBaseFactorisee[Cnt]; + if ( r < RangDeLaMatriceFactorisee ) { + AReduit[r] += C[VariableEnBaseDeLaContrainte[Cnt]]; /* Car AReduit peut avoir ete initialise grace + a la partie hors base reduite */ + } + else { + /* Si on neglige les variables d'ecart basique il faut considerer que Pi = 0 */ + Pi[LigneDeLaBaseFactorisee[r]] = 0; + } +} + +TypeDEntree = VECTEUR_LU; +TypeDeSortie = VECTEUR_LU; +CalculEnHyperCreux = NON_SPX; +SecondMembreCreux = NON_SPX; + +/* Eventuellement les Eta vecteurs */ +/* Attention il faut âs faire comme ca mais resoudre tout le systeme avec les eta */ +/* +if ( Spx->UtiliserLaLuUpdate == NON_SPX ) { + SPX_AppliquerLesEtaVecteursTransposee( Spx, Pi, IndexDesTermesNonNuls, NombreDeTermesNonNuls, + CalculEnHyperCreux, TypeDEntree ); +} +*/ + +SPX_ResolutionDeSystemeTransposee( Spx, TypeDEntree, AReduit, IndexAReduit, &NombreDeTermesNonNulsDuVecteurReduit, + &TypeDeSortie, CalculEnHyperCreux, SecondMembreCreux ); + +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + Pi[LigneDeLaBaseFactorisee[r]] = AReduit[r]; + AReduit[r] = 0; +} + +# if VERIFICATION_PI == OUI_SPX +printf("------------- CalculerPi Spx->NombreDeChangementsDeBase %d -------------\n",Spx->NombreDeChangementsDeBase); +{ +double * Buff; int i; int Var; int ic; int icMx; double S; double * Sortie; +Buff = (double *) malloc( Spx->NombreDeContraintes * sizeof( double ) ); +Sortie = (double *) malloc( Spx->NombreDeContraintes * sizeof( double ) ); +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) Buff[Cnt] = C[VariableEnBaseDeLaContrainte[Cnt]]; +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) Sortie[i] = Pi[i]; +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + Var = Spx->VariableEnBaseDeLaContrainte[i]; + ic = Spx->Cdeb[Var]; + icMx = ic + Spx->CNbTerm[Var]; + S = 0; + while ( ic < icMx ) { + S += Spx->ACol[ic] * Sortie[Spx->NumeroDeContrainte[ic]]; + ic++; + } + if ( fabs( S - Buff[i] ) > 1.e-7 ) { + printf("i = %d S %e Buff %e ecart %e\n",i,S,Buff[i],fabs( S - Buff[i] )); + exit(0); + } +} +printf("Fin verif CalculerPi OK\n"); +free( Buff ); +free( Sortie ); + +SPX_VerifierLesVecteursDeTravail( Spx ); + +} +# endif + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_calculer_une_gomory.c b/src/ext/Sirius_Solver/simplexe/spx_calculer_une_gomory.c new file mode 100644 index 0000000000..11b54db8b2 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_calculer_une_gomory.c @@ -0,0 +1,425 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul d'une coupe de Gomory sur le probleme en cours. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_define.h" +# include "pne_fonctions.h" + +# include "lu_define.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ +/* Retourne 0 si ca s'est mal passe */ + +int SPX_PreparerLeCalculDesGomory( PROBLEME_SPX * Spx , + int NombreDeVariables , int * TypeDeVariable ) +{ +int VarSpx; int Cnt; int VarE; double S; int il; int ilMax; char Save; +char SecondMembreCreux; char TypeDEntree; char TypeDeSortie; char CalculEnHyperCreux; +DONNEES_POUR_COUPES_DE_GOMORY * DonneesPourCoupesDeGomory; + +Spx->DonneesPourCoupesDeGomory = (DONNEES_POUR_COUPES_DE_GOMORY *) malloc( sizeof( DONNEES_POUR_COUPES_DE_GOMORY ) ); +if ( Spx->DonneesPourCoupesDeGomory == NULL) return( 0 ); + +DonneesPourCoupesDeGomory = Spx->DonneesPourCoupesDeGomory; + +DonneesPourCoupesDeGomory->T = (char *) malloc( Spx->NombreDeVariables * sizeof( char ) ); +DonneesPourCoupesDeGomory->Coeff = (double *) malloc( Spx->NombreDeVariables * sizeof( double ) ); +DonneesPourCoupesDeGomory->B = (double *) malloc( Spx->NombreDeContraintes * sizeof( double ) ); +DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere = (char *) malloc( Spx->NombreDeVariables * sizeof( char ) ); +DonneesPourCoupesDeGomory->XmaxSv = (double *) malloc( Spx->NombreDeVariables * sizeof( double ) ); +if ( DonneesPourCoupesDeGomory->T == NULL || DonneesPourCoupesDeGomory->Coeff == NULL || + DonneesPourCoupesDeGomory->B == NULL || DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere == NULL || + DonneesPourCoupesDeGomory->XmaxSv == NULL ) { + free( DonneesPourCoupesDeGomory->T ); free( DonneesPourCoupesDeGomory->Coeff ); free( DonneesPourCoupesDeGomory->B ); + free( DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere ); free( DonneesPourCoupesDeGomory->XmaxSv ); + return( 0 ); +} + +/* Recuperation des resultats du simplexe */ +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + Spx->X [VarSpx] = Spx->XSV[VarSpx]; + Spx->PositionDeLaVariable [VarSpx] = Spx->PositionDeLaVariableSV[VarSpx]; + Spx->ContrainteDeLaVariableEnBase[VarSpx] = Spx->ContrainteDeLaVariableEnBaseSV[VarSpx]; + + DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere[VarSpx] = NON_SPX; + VarE = Spx->CorrespondanceVarSimplexeVarEntree[VarSpx]; + if ( VarE >= 0 && VarE < NombreDeVariables ) { + if ( TypeDeVariable[VarE] == ENTIER ) DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere[VarSpx] = OUI_SPX; + } + + DonneesPourCoupesDeGomory->XmaxSv[VarSpx] = Spx->Xmax[VarSpx]; + + /* Le calcul de BBarre fait intervenir Xmax, il faut dont le corriger pour simuler l'absence d'instanciation */ + if ( DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere[VarSpx] == NON_SPX ) continue; + /* C'est une variable entiere */ + /* La valeur 1. indique bien que ca ne marche que pour des variables binaires */ + Spx->Xmax[VarSpx] = 1. / Spx->ScaleX[VarSpx]; + if ( Spx->XminEntree[VarSpx] == 1. ) { + /* C'est qu'on a instancie la variable a 1 donc comme */ + Spx->X[VarSpx] = Spx->Xmax[VarSpx]; + } + +} + +SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); + +/*Spx->NombreDeChangementsDeBase = 0;*/ + +/* Calcul de B^-1 b */ + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + Spx->BBarre[Cnt] = Spx->BAvantTranslationEtApresScaling[Cnt]; + il = Spx->Mdeb[Cnt]; + ilMax = il + Spx->NbTerm[Cnt]; + S = 0.; + while ( il < ilMax ) { + VarSpx = Spx->Indcol[il]; + if ( Spx->TypeDeVariable[VarSpx] != NON_BORNEE ) { + /* Pour les variable entieres on simule l'absence d'instanciation */ + if ( DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere[VarSpx] == NON_SPX ) { + S+= Spx->A[il] * Spx->XminEntree[VarSpx] / Spx->ScaleX[VarSpx]; + } + } + il++; + } + Spx->BBarre [Cnt]-=S; + DonneesPourCoupesDeGomory->B[Cnt] = Spx->BBarre[Cnt]; +} + +TypeDEntree = VECTEUR_LU; +TypeDeSortie = VECTEUR_LU; +CalculEnHyperCreux = NON_SPX; +Save = NON_LU; +SecondMembreCreux = NON_LU; + +SPX_ResoudreBYegalA( Spx, TypeDEntree, Spx->BBarre, NULL, NULL, &TypeDeSortie, + CalculEnHyperCreux, Save, SecondMembreCreux ); + +/*printf("pas d'appel a SPX_InitCoupesDIntersection \n");*/ + +SPX_InitCoupesDIntersection( Spx , DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere , + DonneesPourCoupesDeGomory->B ); + + +return( 1 ); +} + +/*----------------------------------------------------------------------------*/ + +void SPX_TerminerLeCalculDesGomory( PROBLEME_SPX * Spx ) +{ +int VarSpx; +DONNEES_POUR_COUPES_DE_GOMORY * DonneesPourCoupesDeGomory; + +DonneesPourCoupesDeGomory = Spx->DonneesPourCoupesDeGomory; + +if ( DonneesPourCoupesDeGomory->XmaxSv != NULL ) { + for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + Spx->Xmax[VarSpx] = DonneesPourCoupesDeGomory->XmaxSv[VarSpx]; + } +} + +free( DonneesPourCoupesDeGomory->T ); +free( DonneesPourCoupesDeGomory->Coeff ); +free( DonneesPourCoupesDeGomory->B ); +free( DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere ); +free( DonneesPourCoupesDeGomory->XmaxSv ); +free( DonneesPourCoupesDeGomory ); + +/* Reactiver potentiellement l'hyper creux pour le strong branching */ +SPX_InitialiserLesIndicateursHyperCreux( Spx ); + +return; +} + +/*----------------------------------------------------------------------------*/ +/* + En argument, le sous-programme recoit le numero de la variable sur + laquelle il faut calculer la coupe. +*/ + +void SPX_CalculerUneCoupeDeGomory( + PROBLEME_SPX * Spx, + int VariableFractionnaire, /* Numero de la variable sur laquelle il + faut calculer la coupe */ + + double RapportMaxDesCoeffs, + double ZeroPourCoeffVariablesDEcart, + double ZeroPourCoeffVariablesNatives, + double RelaxRhsAbs, + double RelaxRhsRel, + + /* En retour, la coupe */ + int * NombreDeTermes , /* Nombre de coefficients non nuls dans la coupe */ + double * Coefficient , /* Coefficients de la contrainte */ + int * IndiceDeLaVariable , /* Indices des variables qui interviennent dans la coupe */ + double * SecondMembre, /* Remarque: la coupe est toujours dans le sens <= SecondMembre */ + char * OnAEcrete ) +{ +int VarSpx ; double NBarreR; double AlphaI0; int Cnt; int il ; int ilMax; double NormeL1; +int VariableFractionnaireSpx; double Scale; double S; double ScaleXFoisSupDesXmax; +DONNEES_POUR_COUPES_DE_GOMORY * DonneesPourCoupesDeGomory; double ValeurDuZero; +DONNEES_POUR_COUPES_DINTERSECTION * DonneesPourCoupesDIntersection; +char * T; double * Coeff; double * B; char * LaVariableSpxEstEntiere; int * VariableEnBaseDeLaContrainte; +double * ErBMoinsUn; int * Cdeb; double * ACol; int * CNbTerm; int * NumeroDeContrainte; +char * OrigineDeLaVariable; char * PositionDeLaVariable; double * ScaleX; double * NBarreRVecteur; +double * XminEntree; double * XmaxEntree; double * Xmax; double * Bs; int NbColonnesDeTest; int NbFois; +int * IndexTermesNonNulsDeErBMoinsUn; int * NumVarNBarreRNonNul; char ControlerAdmissibiliteDuale; + +*OnAEcrete = NON_SPX; +*NombreDeTermes = 0; + +ValeurDuZero = ZERO_TERMES_DU_TABLEAU_POUR_GOMORY; + +DonneesPourCoupesDeGomory = Spx->DonneesPourCoupesDeGomory; +T = DonneesPourCoupesDeGomory->T; +Coeff = DonneesPourCoupesDeGomory->Coeff; +B = DonneesPourCoupesDeGomory->B; +LaVariableSpxEstEntiere = DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere; + +/* Le numero fourni ne peut pas etre dans la numerotation interne au simplexe car l'appelant n'y a + pas acces */ +VariableFractionnaireSpx = Spx->CorrespondanceVarEntreeVarSimplexe[VariableFractionnaire]; + +Scale = Spx->ScaleX[VariableFractionnaireSpx]; +AlphaI0 = Spx->BBarre[Spx->ContrainteDeLaVariableEnBase[VariableFractionnaireSpx]] * Scale; + +/* Calcul de la ligne de B^{-1} qui correspond a la variable de base fractionnaire. On utilise pour cela + le module de l'algorithme dual */ +/* Il est preferable de ne pas faire le calcul des gomory en hyper creux. De toutes façons une gomory est + rarement hyper creuse. */ +Spx->CalculErBMoinsUnEnHyperCreux = NON_SPX; +Spx->CalculErBMoinsEnHyperCreuxPossible = NON_SPX; +Spx->CalculABarreSEnHyperCreux = NON_SPX; +Spx->CalculABarreSEnHyperCreuxPossible = NON_SPX; + +Spx->VariableSortante = VariableFractionnaireSpx; /* Info utilisee dans le calcul de la ligne de B^{-1} */ + +/* Attention, DualCalculerNBarreR calcule ErBmoins1 */ +SPX_DualCalculerNBarreR( Spx, NON_SPX, &ControlerAdmissibiliteDuale ); /* En sortie on recupere la ligne dans le vecteur Spx->NBarreR, les + emplacements utiles etant ceux qui correspondent aux variables hors base */ + +/* Verification */ + +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +ErBMoinsUn = Spx->ErBMoinsUn; + +ACol = Spx->ACol; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +/* Si le stockage de ErBMoinsUn est COMPACT_SPX on en fait un VECTEUR_SPX */ +if ( Spx->TypeDeStockageDeErBMoinsUn == COMPACT_SPX ) { + Bs = Spx->Bs; + memset( (char *) Bs, 0, Spx->NombreDeContraintes * sizeof( double ) ); + IndexTermesNonNulsDeErBMoinsUn = Spx->IndexTermesNonNulsDeErBMoinsUn; + for ( il = 0 ; il < Spx->NbTermesNonNulsDeErBMoinsUn ; il++ ) Bs[IndexTermesNonNulsDeErBMoinsUn[il]] = ErBMoinsUn[il]; + memcpy( (char *) ErBMoinsUn, (char *) Bs, Spx->NombreDeContraintes * sizeof( double ) ); + Spx->TypeDeStockageDeErBMoinsUn = VECTEUR_SPX; +} +else if ( Spx->TypeDeStockageDeErBMoinsUn != VECTEUR_SPX ) { + printf("Calcul des gomory, attention le mode de stockage de ErBMoinsUn est incorrect\n"); +} + +goto AAA; +NormeL1 = 0.0; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + VarSpx = VariableEnBaseDeLaContrainte[Cnt]; + /* Verification */ + S = 0.; + if ( VarSpx == Spx->VariableSortante ) S = -1.; + il = Cdeb[VarSpx]; + ilMax = il + CNbTerm[VarSpx]; + while ( il < ilMax ) { + S+= ACol[il] * ErBMoinsUn[NumeroDeContrainte[il]]; + il++; + } + NormeL1+= fabs( S ); +} + +if ( NormeL1 > SEUIL_DE_VERIFICATION_DE_NBarreR_GOMORY ) { + #if VERBOSE_SPX + printf("Erreur de resolution sur ErBMoinsUn: %e, Gomory refusee\n",fabs( NormeL1 )); + #endif + Spx->FactoriserLaBase = NON_SPX; + return; +} +goto BBB; +AAA: +/* Calcul moins consommateur. De plus un test sur la norme L1 peut amener a supprimer trop de coupes */ +/* Test sur la colonne de la variable sortante */ +NormeL1 = 0.0; +VarSpx = Spx->VariableSortante; +S = -1.; +il = Cdeb[VarSpx]; +ilMax = il + CNbTerm[VarSpx]; +while ( il < ilMax ) { + S+= ACol[il] * ErBMoinsUn[NumeroDeContrainte[il]]; + il++; +} +NormeL1 += fabs( S ); +if ( NormeL1 > SEUIL_DE_VERIFICATION_DE_NBarreR_GOMORY ) { + #if VERBOSE_SPX + printf("Erreur de resolution sur ErBMoinsUn: %e, Gomory refusee\n",fabs( NormeL1 )); + #endif + Spx->FactoriserLaBase = NON_SPX; + return; +} +/* Test sur quelques colonnes autres que celle de la variable sortante */ +NbColonnesDeTest = (int) ceil( 0.05 * Spx->NombreDeContraintes ); +if ( NbColonnesDeTest < 10 ) NbColonnesDeTest = 10; +NbFois = 0; +while ( NbFois < NbColonnesDeTest ) { +break; + # if UTILISER_PNE_RAND == OUI_SPX + Spx->A1 = PNE_Rand( Spx->A1 ); + S = Spx->A1 * (Spx->NombreDeContraintes - 1); + # else + S = rand() * Spx->UnSurRAND_MAX * (Spx->NombreDeContraintes - 1); + # endif + Cnt = (int) S; + if ( Cnt >= Spx->NombreDeContraintes ) Cnt = Spx->NombreDeContraintes - 1; + NormeL1 = 0.0; + VarSpx = VariableEnBaseDeLaContrainte[Cnt]; + /* Verification */ + S = 0.; + if ( VarSpx == Spx->VariableSortante ) S = -1.; + il = Cdeb[VarSpx]; + ilMax = il + CNbTerm[VarSpx]; + while ( il < ilMax ) { + S+= ACol[il] * ErBMoinsUn[NumeroDeContrainte[il]]; + il++; + } + NormeL1 += fabs( S ); + if ( NormeL1 > SEUIL_DE_VERIFICATION_DE_NBarreR_GOMORY ) { + #if VERBOSE_SPX + printf("Erreur de resolution sur ErBMoinsUn: %e, Gomory refusee\n",fabs( NormeL1 )); + #endif + Spx->FactoriserLaBase = NON_SPX; + return; + } + NbFois++; +} +BBB: + +/* Constitution de la contrainte avant application des regles d'arrondi */ +/* On ne veut pas de variables artificielles dans les coupes. Comme elles valent 0 on peut s'en passer */ +OrigineDeLaVariable = Spx->OrigineDeLaVariable; +PositionDeLaVariable = Spx->PositionDeLaVariable; +ScaleX = Spx->ScaleX; +NBarreRVecteur = Spx->NBarreR; +XminEntree = Spx->XminEntree; +XmaxEntree = Spx->XmaxEntree; +Xmax = Spx->Xmax; + +/* Si le stockage de NBarreR est ADRESSAGE_INDIRECT_SPX on en fait un VECTEUR_SPX */ +if ( Spx->TypeDeStockageDeNBarreR == ADRESSAGE_INDIRECT_SPX ) { + memset( (char *) T, 0, Spx->NombreDeVariables * sizeof( char ) ); + NumVarNBarreRNonNul = Spx->NumVarNBarreRNonNul; + for ( il = 0 ; il < Spx->NombreDeValeursNonNullesDeNBarreR ; il++ ) T[NumVarNBarreRNonNul[il]] = 1; + for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + if ( T[VarSpx] == 0 ) NBarreRVecteur[VarSpx] = 0.0; + else T[VarSpx] = 0; + } + Spx->TypeDeStockageDeNBarreR = VECTEUR_SPX; +} +else if ( Spx->TypeDeStockageDeNBarreR != VECTEUR_SPX ) { + printf("Calcul des gomory, le mode de stockage de NBarreR est incorrect\n"); +} + +/* Constitution du vecteur sur lequel on fera la MIR */ +/* Remarque: les variables non bornees x = x+ - x- avec x+ >= 0 et x- >= 0 sont hors base a 0 + c'est ŕ dire x+ et x- sont nuls. Comme il y a une difference la variable n'intervient pas. */ +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + + T [VarSpx] = 0; + Coeff[VarSpx] = 0.; + + if ( OrigineDeLaVariable[VarSpx] == BASIQUE_ARTIFICIELLE ) continue; + + if ( PositionDeLaVariable[VarSpx] != HORS_BASE_SUR_BORNE_INF && + PositionDeLaVariable[VarSpx] != HORS_BASE_SUR_BORNE_SUP ) continue; + + /* Nettoyage des tres petites valeurs car le vecteur va passer dans les coupes d'intersection. + Si on conserve trop de termes, le calcul des coupes d'intersection sera long. */ + if ( fabs( NBarreRVecteur[VarSpx] ) < ValeurDuZero ) { + NBarreRVecteur[VarSpx] = 0.0; + continue; + } + + ScaleXFoisSupDesXmax = ScaleX[VarSpx]; + NBarreR = NBarreRVecteur[VarSpx] * Scale / ScaleXFoisSupDesXmax; + + if ( LaVariableSpxEstEntiere[VarSpx] == OUI_SPX ) { + /* La variable est entiere. Si elle a ete instanciee a 0, l'information HORS_BASE_SUR_BORNE_INF ou + HORS_BASE_SUR_BORNE_SUP ne joue pas. Si elle a ete instanciee a 1 alors c'est comme si elle + etait HORS_BASE_SUR_BORNE_SUP */ + if ( XminEntree[VarSpx] == XmaxEntree[VarSpx] ) { + /* C'est une variable instanciee */ + if ( XminEntree[VarSpx] == 0. ) goto MajT; + AlphaI0-= NBarreR * Xmax[VarSpx] * ScaleXFoisSupDesXmax; + NBarreR = -NBarreR; + goto MajT; + } + } + + if ( PositionDeLaVariable[VarSpx] == HORS_BASE_SUR_BORNE_SUP ) { + /* On fait le changement de variable X = Xmax - Xtilde => Xtilde est hors base et vaut 0 */ + AlphaI0-= NBarreR * Xmax[VarSpx] * ScaleXFoisSupDesXmax; + NBarreR = -NBarreR; + } + + MajT: + T [VarSpx] = 1; + Coeff[VarSpx] = NBarreR; +} + +/* On differe le stockage car si la gomory est rejetee plus tard alors on veut aussi rejeter la + coupe d'intersection */ +/* SPX_MatriceCoupesDIntersection( Spx, VariableFractionnaireSpx, T, Coeff, AlphaI0 ); */ +DonneesPourCoupesDIntersection = Spx->DonneesPourCoupesDIntersection; +DonneesPourCoupesDIntersection->AlphaI0 = AlphaI0; +memcpy( (char *) DonneesPourCoupesDIntersection->TSpx , (char *) T , Spx->NombreDeVariables * sizeof( char ) ); +memcpy( (char *) DonneesPourCoupesDIntersection->CoeffSpx, (char *) Coeff, Spx->NombreDeVariables * sizeof( double) ); + +/* Calcul de la MIR */ +SPX_CalculMIRPourCoupeDeGomoryOuIntersection( Spx, RapportMaxDesCoeffs, ZeroPourCoeffVariablesDEcart, + ZeroPourCoeffVariablesNatives, RelaxRhsAbs, RelaxRhsRel, + AlphaI0, B, T, Coeff, LaVariableSpxEstEntiere, + NombreDeTermes, Coefficient, IndiceDeLaVariable, SecondMembre, + OnAEcrete ); + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_chainage_matrice_hors_base.c b/src/ext/Sirius_Solver/simplexe/spx_chainage_matrice_hors_base.c new file mode 100644 index 0000000000..4fb08bee16 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_chainage_matrice_hors_base.c @@ -0,0 +1,158 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + FONCTION: Chainage de la metrice des contrainte avec uniquement les + variables hors base. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_MettreAJourLaMatriceHorsBase( PROBLEME_SPX * Spx ) +{ +int Var; int ic; int icMx; int Cnt; int ilHorsBase; int ilHorsBaseMax; int ic1; +int * Cdeb; int * CNbTerm; int * NumeroDeContrainte; int * IndexDansLaMatriceHorsBase; +int * MdebHorsBase; int * NbTermHorsBase; int * IndcolHorsBase; int * InverseIndexDansLaMatriceHorsBase; +double * AHorsBase; double * ACol; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; +ACol = Spx->ACol; +IndexDansLaMatriceHorsBase = Spx->IndexDansLaMatriceHorsBase; +MdebHorsBase = Spx->MdebHorsBase; +NbTermHorsBase = Spx->NbTermHorsBase; +AHorsBase = Spx->AHorsBase; +IndcolHorsBase = Spx->IndcolHorsBase; +InverseIndexDansLaMatriceHorsBase = Spx->InverseIndexDansLaMatriceHorsBase; + +/* On enleve la variable entrante */ +Var = Spx->VariableEntrante; +ic = Cdeb[Var]; +icMx = ic + CNbTerm[Var]; +while ( ic < icMx ) { + Cnt = NumeroDeContrainte[ic]; + ilHorsBase = IndexDansLaMatriceHorsBase[ic]; + /* On doit enlever le terme qui se trouve a cet emplacement */ + ilHorsBaseMax = MdebHorsBase[Cnt] + NbTermHorsBase[Cnt] - 1; + + AHorsBase[ilHorsBase] = AHorsBase[ilHorsBaseMax]; + IndcolHorsBase[ilHorsBase] = IndcolHorsBase[ilHorsBaseMax]; + + ic1 = InverseIndexDansLaMatriceHorsBase[ilHorsBaseMax]; + IndexDansLaMatriceHorsBase[ic1] = ilHorsBase; + InverseIndexDansLaMatriceHorsBase[ilHorsBase] = ic1; + + NbTermHorsBase[Cnt]--; /* MdebHorsBase ne change jamais */ + + ic++; +} + +/* On ajoute la variable sortante */ +Var = Spx->VariableSortante; +ic = Cdeb[Var]; +icMx = ic + CNbTerm[Var]; +while ( ic < icMx ) { + Cnt = NumeroDeContrainte[ic]; + + /* On ajoute a la fin */ + ilHorsBase = MdebHorsBase[Cnt] + NbTermHorsBase[Cnt] - 1; + + AHorsBase[ilHorsBase] = ACol[ic]; + IndcolHorsBase[ilHorsBase] = Spx->VariableSortante; + + IndexDansLaMatriceHorsBase[ic] = ilHorsBase; + InverseIndexDansLaMatriceHorsBase[ilHorsBase] = ic; + + NbTermHorsBase[Cnt]++; /* MdebHorsBase ne change jamais */ + + ic++; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_InitMatriceHorsBase( PROBLEME_SPX * Spx ) +{ +int NombreDeContraintes; int NombreDeVariables; char * PositionDeLaVariable; int Var; +int ic; int icMx; int Cnt; int ilHorsBase; int * Cdeb; int * CNbTerm; int * NumeroDeContrainte; +int * IndexDansLaMatriceHorsBase; int * MdebHorsBase; int * NbTermHorsBase; +int * IndcolHorsBase; int * InverseIndexDansLaMatriceHorsBase; int * Mdeb; +double * AHorsBase; double * ACol; + +if ( Spx->MdebHorsBase == NULL ) { + Spx->IndexDansLaMatriceHorsBase = (int *) malloc( Spx->NbTermesAlloues * sizeof( int ) ); + Spx->MdebHorsBase = (int *) malloc( Spx->NombreDeContraintesAllouees * sizeof( int ) ); + Spx->NbTermHorsBase = (int *) malloc( Spx->NombreDeContraintesAllouees * sizeof( int ) ); + Spx->AHorsBase = (double *) malloc( Spx->NbTermesAlloues * sizeof( double ) ); + Spx->IndcolHorsBase = (int *) malloc( Spx->NbTermesAlloues * sizeof( int ) ); + Spx->InverseIndexDansLaMatriceHorsBase = (int *) malloc( Spx->NbTermesAlloues * sizeof( int ) ); +} + +NombreDeContraintes = Spx->NombreDeContraintes; +NombreDeVariables = Spx->NombreDeVariables; +PositionDeLaVariable = Spx->PositionDeLaVariable; + +Mdeb = Spx->Mdeb; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; +ACol = Spx->ACol; + +IndexDansLaMatriceHorsBase = Spx->IndexDansLaMatriceHorsBase; +MdebHorsBase = Spx->MdebHorsBase; +NbTermHorsBase = Spx->NbTermHorsBase; +AHorsBase = Spx->AHorsBase; +IndcolHorsBase = Spx->IndcolHorsBase; +InverseIndexDansLaMatriceHorsBase = Spx->InverseIndexDansLaMatriceHorsBase; + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + MdebHorsBase[Cnt] = Mdeb[Cnt]; + NbTermHorsBase[Cnt] = 0; +} + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( PositionDeLaVariable[Var] == EN_BASE_LIBRE ) continue; + ic = Cdeb[Var]; + icMx = ic + CNbTerm[Var]; + while ( ic < icMx ) { + Cnt = NumeroDeContrainte[ic]; + ilHorsBase = MdebHorsBase[Cnt] + NbTermHorsBase[Cnt]; + AHorsBase[ilHorsBase] = ACol[ic]; + IndcolHorsBase[ilHorsBase] = Var; + + IndexDansLaMatriceHorsBase[ic] = ilHorsBase; + InverseIndexDansLaMatriceHorsBase[ilHorsBase] = ic; + + NbTermHorsBase[Cnt]++; + + ic++; + } +} + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_chainage_transposee.c b/src/ext/Sirius_Solver/simplexe/spx_chainage_transposee.c new file mode 100644 index 0000000000..b7c7cacfad --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_chainage_transposee.c @@ -0,0 +1,111 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul du chainage de la transposee de la matrice des + contraintes + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void SPX_ChainageDeLaTransposee( PROBLEME_SPX * Spx, int TypeChainage ) +{ +int i; int il; int ilMax; int Var ; int ilC ; int * Csui ; +int * NumeroDeContrainte ; int * Mdeb; int * NbTerm ; int * Indcol ; +int * Cdeb; double * ACol ; double * A ; int * CNbTerm; int * IndexCourant; +int NombreDeVariables ; int NombreDeContraintes ; int ilk ; + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +Cdeb = Spx->Cdeb; +ACol = Spx->ACol; +A = Spx->A; +CNbTerm = Spx->CNbTerm; +Csui = Spx->Csui; +NumeroDeContrainte = Spx->NumeroDeContrainte; +NombreDeVariables = Spx->NombreDeVariables; +NombreDeContraintes = Spx->NombreDeContraintes; + +if ( TypeChainage == COMPACT ) { + + IndexCourant = (int *) Spx->CBarreSurNBarreR; + memset( (char *) CNbTerm , 0 , NombreDeVariables * sizeof( int ) ); + + for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + CNbTerm[Indcol[il]]++; + il++; + } + } + for ( ilC = 0 , Var = 0 ; Var < NombreDeVariables ; Var++ ) { + Cdeb[Var] = ilC; + IndexCourant[Var] = ilC; + ilC+= CNbTerm[Var]; + } + for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + ilC = IndexCourant[Indcol[il]]; + IndexCourant[Indcol[il]]++; + ACol[ilC] = A[il]; + NumeroDeContrainte[ilC] = i; + il++; + } + } + if ( Spx->StockageParColonneSauvegarde == NON_SPX ) { + memcpy( (char *) Spx->CNbTermSansCoupes, (char *) CNbTerm , NombreDeVariables * sizeof( int ) ); + Spx->StockageParColonneSauvegarde = OUI_SPX; + } + + memset( (char *) Spx->CBarreSurNBarreR , 0 , NombreDeVariables * sizeof( double ) ); + +} +else { + for ( i = 0 ; i < NombreDeVariables ; i++ ) Cdeb[i] = -1; + for ( i = NombreDeContraintes - 1 ; i >= 0 ; i-- ) { + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + Var = Indcol[il]; + ilk = Cdeb[Var]; + Cdeb[Var] = il; + NumeroDeContrainte[il] = i; + Csui[il] = ilk; + il++; + } + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_choix_variable_a_instancier_exploration_rapide_profondeur.c b/src/ext/Sirius_Solver/simplexe/spx_choix_variable_a_instancier_exploration_rapide_profondeur.c new file mode 100644 index 0000000000..daa8db8472 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_choix_variable_a_instancier_exploration_rapide_profondeur.c @@ -0,0 +1,222 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: En exploration rapide (pilotee par le branch and bound), + choix de la variable a instancier. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +#include "pne_define.h" + +#include "bb_define.h" +#include "bb_fonctions.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void SPX_ChoisirLaVariableAInstancier( PROBLEME_SPX * Spx, + void * BbProb, + int * VariablePneAInstancier, + int * SortSurXmaxOuSurXmin ) + +{ +int Cnt; int i ; double X ; int TypeDeSortie ; double Seuil_0; +double S; double Y; int VarSpx; int VariableSpxAInstancier; double Seuil_1; +int NbVarFractionnaires ; double NormeInfaisabilite ; +double PlusGrandeVariation ; +double * Fractionalite; int * NumVarFrac; /*char OnInverse; int VSpx;*/ + +double * BBarre; int * VariableEnBaseDeLaContrainte; char * PositionDeLaVariable; int VarPne; +double * ScaleX; int * ContrainteDeLaVariableEnBase; +double * Xmax ; double * DualPoids ; int * CorrespondanceVarEntreeVarSimplexe ; +int NombreDeVariablesBinairesPne ; int * NumeroDesVariablesBinairesPne ; +double PlusPetiteVariation; double Poids; double S1; double S2; +BB * Bb; + +Bb = (BB *) BbProb; + +/************************************************************************/ + +*VariablePneAInstancier = -1; +*SortSurXmaxOuSurXmin = SORT_PAS; + +if ( Spx->YaUneSolution == NON_SPX ) return; + +SPX_CalculDuCout( Spx ); +if ( Spx->Cout > Spx->CoutMax ) { + printf("Fin par coutmax dans choix var a instancier\n"); + Spx->YaUneSolution = NON_SPX; + return; +} + +/* +printf("Cout de la solution relaxee %e\n",Spx->Cout); +*/ + +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +BBarre = Spx->BBarre; +PositionDeLaVariable = Spx->PositionDeLaVariable; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +ScaleX = Spx->ScaleX; +Xmax = Spx->Xmax; +DualPoids = Spx->DualPoids; + + +CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; + +NombreDeVariablesBinairesPne = Bb->NombreDeVariablesEntieresDuProbleme; +NumeroDesVariablesBinairesPne = Bb->NumerosDesVariablesEntieresDuProbleme; + +VariableSpxAInstancier = -1; +TypeDeSortie = SORT_PAS; + +PlusGrandeVariation = -LINFINI_SPX; +PlusPetiteVariation = LINFINI_SPX; + +Seuil_0 = 5.e-7; +Seuil_1 = 1. - Seuil_0; + +NbVarFractionnaires = 0; +NormeInfaisabilite = 0.0; + +Fractionalite = (double *) malloc( Spx->NombreDeVariables * sizeof( double ) ); +NumVarFrac = (int *) malloc( Spx->NombreDeVariables * sizeof( int ) ); + +/* Decompte du nombre de variables fractionnaires */ +for ( i = 0 ; i < NombreDeVariablesBinairesPne ; i++ ) { + VarPne = NumeroDesVariablesBinairesPne[i]; + VarSpx = CorrespondanceVarEntreeVarSimplexe[VarPne]; + if ( VarSpx < 0 || VarSpx >= Spx->NombreDeVariables ) continue; + if ( Spx->Xmin[VarSpx] == Spx->Xmax[VarSpx] ) continue; + if ( PositionDeLaVariable[VarSpx] != EN_BASE_LIBRE ) continue; + Cnt = ContrainteDeLaVariableEnBase[VarSpx]; + X = BBarre[Cnt]; + Y = X * ScaleX[VarSpx]; + if ( Y < Seuil_0 || Y > Seuil_1 ) continue; + Fractionalite[NbVarFractionnaires] = fabs( Y - 0.5 ); + NumVarFrac[NbVarFractionnaires] = VarSpx; + NormeInfaisabilite+= fabs( Y - floor( Y + 0.5 ) ); + NbVarFractionnaires++; +} + +/* +printf("NbVarFractionnaires %d NormeInfaisabilite %e\n",NbVarFractionnaires,NormeInfaisabilite); +*/ + +if ( NbVarFractionnaires <= 0 ) return; + +/* Classement par fractionalite croissante */ +/* +OnInverse = OUI_SPX; +while ( OnInverse == OUI_SPX ) { + OnInverse = NON_SPX; + for ( i = 0 ; i < NbVarFractionnaires - 1 ; i++ ) { + if ( Bb->NombreDeSolutionsEntieresTrouvees == 0 ) { + if ( Fractionalite[i] < Fractionalite[i+1] ) { + OnInverse = OUI_SPX; + VSpx = NumVarFrac[i]; + NumVarFrac[i] = NumVarFrac[i+1]; + NumVarFrac[i+1] = VSpx; + X = Fractionalite[i]; + Fractionalite[i] = Fractionalite[i+1]; + Fractionalite[i+1] = X; + } + } + else { + if ( Fractionalite[i] > Fractionalite[i+1] ) { + OnInverse = OUI_SPX; + VSpx = NumVarFrac[i]; + NumVarFrac[i] = NumVarFrac[i+1]; + NumVarFrac[i+1] = VSpx; + X = Fractionalite[i]; + Fractionalite[i] = Fractionalite[i+1]; + Fractionalite[i+1] = X; + } + } + } +} +*/ + +for ( i = 0 ; i < NbVarFractionnaires ; i++ ) { + VarSpx = NumVarFrac[i]; + if ( PositionDeLaVariable[VarSpx] != EN_BASE_LIBRE ) continue; + Cnt = ContrainteDeLaVariableEnBase[VarSpx]; + X = BBarre[Cnt]; + Y = X * ScaleX[VarSpx]; + if ( Y < Seuil_0 || Y > Seuil_1 ) continue; + + Poids = DualPoids[Cnt]; + + S1 = ( X * X ) / Poids; + S2 = ( (Xmax[VarSpx] - X) * (Xmax[VarSpx] - X) ) / Poids; + S = S1 + S2; + if ( Bb->NombreDeSolutionsEntieresTrouvees != 0 ) { + if ( S > PlusGrandeVariation ) { + VariableSpxAInstancier = VarSpx; + if ( S2 > S1 ) TypeDeSortie = SORT_SUR_XMAX; + else TypeDeSortie = SORT_SUR_XMIN; + PlusGrandeVariation = S; + } + } + else { + if ( S < PlusPetiteVariation ) { + VariableSpxAInstancier = VarSpx; + if ( S2 > S1 ) TypeDeSortie = SORT_SUR_XMIN; + else TypeDeSortie = SORT_SUR_XMAX; + PlusPetiteVariation = S; + } + } + +} + +free( Fractionalite ); +free( NumVarFrac ); + +if ( VariableSpxAInstancier >= 0 ) { + /* + VarSpx = VariableSpxAInstancier; + Cnt = ContrainteDeLaVariableEnBase[VarSpx]; + X = BBarre[Cnt]; + Y = X * ScaleX[VarSpx]; + printf("Var a instancier valeur %e poids %e cout sol %e delta cout si Xmin %e si Xmax %e coutmax %e\n", + Y, DualPoids[Cnt] , + Spx->Cout, + sqrt( ( X * X ) / DualPoids[Cnt] ), + sqrt( ( (Xmax[VarSpx] - X) * (Xmax[VarSpx] - X) ) / DualPoids[Cnt] ), + Spx->CoutMax ); + */ + *VariablePneAInstancier = Spx->CorrespondanceVarSimplexeVarEntree[VariableSpxAInstancier]; + *SortSurXmaxOuSurXmin = TypeDeSortie; +} + +return; + +} + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_constantes_externes.h b/src/ext/Sirius_Solver/simplexe/spx_constantes_externes.h new file mode 100644 index 0000000000..befb3bfe69 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_constantes_externes.h @@ -0,0 +1,83 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef CONSTANTES_EXTERNES_SIMPLEXE_DEJA_DEFINIES +/*******************************************************************************************/ +/* + Definition des constantes symboliques a utiliser par le module appelant le simplexe +*/ + +# define SPX_ERREUR_INTERNE 2 +# define SPX_MATRICE_DE_BASE_SINGULIERE 3 +/* Constantes symboliques du OUI et du NON */ +# define OUI_SPX 1 +# define NON_SPX 0 +/* */ + +# define PRICING_DANTZIG 1 +# define PRICING_STEEPEST_EDGE 0 + +# define UTILISER_LA_BASE_DU_PROBLEME_SPX 2 + +# define AGRESSIF 1 +# define PEU_AGRESSIF 2 + +/* Type de borne des variables fournies en entree */ +# define VARIABLE_FIXE 1 +# define VARIABLE_BORNEE_DES_DEUX_COTES 2 +# define VARIABLE_BORNEE_INFERIEUREMENT 3 +# define VARIABLE_BORNEE_SUPERIEUREMENT 4 +# define VARIABLE_NON_BORNEE 5 + +/* Contexte d'utilisation du simplexe */ +# define BRANCH_AND_BOUND_OU_CUT 1 /* Branch and Bound ou Branch and Cut avec reinitialisation du probleme */ +# define BRANCH_AND_BOUND_OU_CUT_NOEUD 2 /* Branch and Bound ou Branch and Cut en un noeud particulier (i.e. sans reinitialisation du probleme) */ +# define SIMPLEXE_SEUL 3 + +/* Pour choisir l'algorithme */ +# define SPX_PRIMAL 1 +# define SPX_DUAL 2 + +/* */ +# ifndef CREUX + # define CREUX 1 +# endif +# ifndef COMPACT + # define COMPACT 2 +# endif + +# define PHASE_1 1 +# define PHASE_2 2 + +/* Origine des variables du simplexe */ +# define NATIVE 1 /* Variable native (elle correspond a une variable du probleme d'entree */ +# define ECART 2 /* Variable d'ecart creee pour mettre une contrainte d'inegalite sous la forme standard */ +# define BASIQUE_ARTIFICIELLE 3 /* Variable basique de depart creee si necessaire pour construire la + premiere base inversible */ + +/* Position des variables */ +# define EN_BASE 0 +# define EN_BASE_LIBRE 1 +# define EN_BASE_SUR_BORNE_INF 2 +# define EN_BASE_SUR_BORNE_SUP 3 +# define HORS_BASE_SUR_BORNE_INF 4 +# define HORS_BASE_SUR_BORNE_SUP 5 +# define HORS_BASE_A_ZERO 6 /* Pour les variables non bornees qui restent hors base */ + +/*******************************************************************************************/ +# define CONSTANTES_EXTERNES_SIMPLEXE_DEJA_DEFINIES +# endif + diff --git a/src/ext/Sirius_Solver/simplexe/spx_constantes_internes.h b/src/ext/Sirius_Solver/simplexe/spx_constantes_internes.h new file mode 100644 index 0000000000..158f617a0e --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_constantes_internes.h @@ -0,0 +1,208 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef DEFINITIONS_CONSTANTES_INTERNES_SPX_FAITE +/*******************************************************************************************/ + +# define VERBOSE_SPX 0 +# if VERBOSE_SPX == 0 + # define VERBOSE_SPX_SCALING 0 /* mettre 0 si on ne veut tout de meme pas les traces */ +# else + # define VERBOSE_SPX_SCALING VERBOSE_SPX +# endif + +# define SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE +# undef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + +/* */ +# ifndef CREUX + # define CREUX 1 +# endif +# ifndef COMPACT + # define COMPACT 2 +# endif + +# define PHASE_1 1 +# define PHASE_2 2 + +# define BORNEE VARIABLE_BORNEE_DES_DEUX_COTES /* La variable est bornee des deux cotes */ +# define BORNEE_INFERIEUREMENT VARIABLE_BORNEE_INFERIEUREMENT /* La variable n'est bornee qu'inferieurement */ +# define BORNEE_SUPERIEUREMENT VARIABLE_BORNEE_SUPERIEUREMENT /* La variable n'est bornee que superieurement. + Rq: en entree un traitement supplémentaire la transforme en bornee inferieurement + de telle sorte qu'en cours d'algorithme il n'y a plus que des variables + bornees inferieurement */ +# define NON_BORNEE VARIABLE_NON_BORNEE /* La variable n'est ni inferieurement ni superieurement bornee */ + +/* Origine des variables du simplexe */ +# define NATIVE 1 /* Variable native (elle correspond a une variable du probleme d'entree) */ +# define ECART 2 /* Variable d'ecart creee pour mettre une contrainte d'inegalite sous la forme standard */ +# define BASIQUE_ARTIFICIELLE 3 /* Variable basique de depart creee si necessaire pour construire la + premiere base inversible */ + +# define SORT_SUR_XMIN 1 +# define SORT_SUR_XMAX 2 +# define SORT_PAS 3 + +# define COEFFICIENT_A_BASE_INITIALE_PHASE_1 1. + +# define NOMBRE_MAX_DITERATIONS 100000 + +# define LINFINI_SPX 1.e+80 + +# define SEUIL_DADMISSIBILITE 1.e-6 /* 1.e-6 */ + +/* Seuil qui s'applique aux variables natives */ +# define SEUIL_DE_VIOLATION_DE_BORNE 1.e-7 /* 1.e-7 Seuil de violation de borne pour l'algorithme dual, c'est le seuil de + convergence de l'algorithme dual */ +# define SEUIL_MIN_DE_VIOLATION_DE_BORNE ( 0.01 /*valeur au 17/4/2015 : 0.001*/ * SEUIL_DE_VIOLATION_DE_BORNE ) +# define SEUIL_MAX_DE_VIOLATION_DE_BORNE ( 1000 /*2.0*/ * SEUIL_DE_VIOLATION_DE_BORNE ) + +/* Seuil qui s'applique aux variables d'ecart et artificielles de base */ +# define SEUIL_DE_VIOLATION_DE_BORNE_NON_NATIVE 1.e-7 /* 1.e-7 */ +# define SEUIL_MIN_DE_VIOLATION_DE_BORNE_NON_NATIVE ( 0.01 /*valeur au 17/4/2015 : 0.001*/ * SEUIL_DE_VIOLATION_DE_BORNE_NON_NATIVE ) +# define SEUIL_MAX_DE_VIOLATION_DE_BORNE_NON_NATIVE ( 1000 /*2.0*/* SEUIL_DE_VIOLATION_DE_BORNE_NON_NATIVE ) + +/* seuil qui s'applique aux variables d'ecart de coupes */ +# define SEUIL_DE_VIOLATION_DE_BORNE_VARIABLES_ECART_COUPES 1.e-7 /*1.e-7*/ + +# define LINFINI_POUR_LE_COUT 1.e+80 +# define LINFINI_POUR_X 1.e+80 + +# define SEUIL_DE_DEGENERESCENCE 1.e-7 /*1.e-7*/ +# define VALEUR_DE_PIVOT_ACCEPTABLE 1.e-7 /*1.e-6*/ /* Diviseur acceptable pour un test de ratio */ + +# define COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE 10.0 /*5.0*/ +# define DIVISEUR_VALEUR_DE_PIVOT_ACCEPTABLE 1.1 + +# define CYCLE_DE_REFACTORISATION_DUAL 50 /*50*/ /* Mettre 0 pour factoriser a chaque iteration */ + +# define CYCLE_DE_REFACTORISATION CYCLE_DE_REFACTORISATION_DUAL + +# define SEUIL_DE_DEGENERESCENCE_DUAL 1.e-9 /* 1.e-9 */ + +# define NOMBRE_MAX_DE_CONTROLES_FINAUX 10 /* 20 */ +# define SEUIL_POUR_RECONSTRUCTION_BASE 9 /* Doit toujours etre plus petit que NOMBRE_MAX_DE_CONTROLES_FINAUX */ + +# define SEUIL_ADMISSIBILITE_DUALE_1 1.e-8 /* 1.e-8 */ +# define SEUIL_ADMISSIBILITE_DUALE_2 2.e-8 /* 2.e-8*/ /*1.75e-8*/ /* Doit toujours etre superieur ŕ SEUIL_ADMISSIBILITE_DUALE_1 */ +/*# define SEUIL_ADMISSIBILITE_DUALE_3 1.1e-8*/ /*1.1e-8*/ /*2.e-8*/ /*1.75e-8*/ /* Pour les variables non bornees */ +# define COEFF_MIN_SEUIL_DUAL 0.01 /*valeur au 21/4/2015 : 0.001*/ +# define COEFF_MAX_SEUIL_DUAL 1000 /*1000*/ + +# define SEUIL_POUR_MODIFICATION_DE_COUT (10*SEUIL_ADMISSIBILITE_DUALE_1) /*(10*SEUIL_ADMISSIBILITE_DUALE_1)*/ /* Anti degenrescence */ +# define COEFF_SEUIL_POUR_MODIFICATION_DE_COUT 10 /* 10 S'applique au seuil d'admissibilite duale */ + +# define NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT 1 /*1*/ +# define VALEUR_PERTURBATION_COUT_A_POSTERIORI (100*SEUIL_POUR_MODIFICATION_DE_COUT) /*(100.*SEUIL_POUR_MODIFICATION_DE_COUT)*/ +# define COEFF_VALEUR_PERTURBATION_COUT_A_POSTERIORI 100 + +# define COEFF_TOLERANCE_POUR_LE_TEST_DE_HARRIS 0.1 /* 0.5 S'applique au seuil d'admissibilite */ + +# define CYCLE_DE_VERIF_ADMISSIBILITE_DUALE 150 /* 150 */ + +# define DUALE_FAISABLE 0 +# define DUALE_INFAISABLE_PAR_COUT_REDUIT_NEGATIF 1 +# define DUALE_INFAISABLE_PAR_COUT_REDUIT_POSITIF 2 + +# define MAX_BOUND_FLIP 1000 /*100*/ + +# define NOMBRE_DITERATIONS_DE_STRONG_BRANCHING 5 + +# define CYCLE_DE_CONTROLE_DE_DEGENERESCENCE_AGRESSIF 0 +# define CYCLE_DE_CONTROLE_DE_DEGENERESCENCE_PEU_AGRESSIF 5 + +# define INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_VARIABLES_SPX 256 /* 256 variables */ +# define INCREMENT_DALLOCATION_POUR_LE_NOMBRE_DE_CONTRAINTES_SPX 256 /* 256 contraintes */ +# define INCREMENT_DALLOCATION_POUR_LA_MATRICE_DES_CONTRAINTES_SPX 4096 /* 4096 termes */ + +/* Pour les coupes de Gomory */ +# define SEUIL_DE_VERIFICATION_DE_NBarreR_GOMORY 1.e-7 +# define ZERO_GOMORY_1_F0 1.e-7 /*1.e-7*/ /* Pour eviter les divisions par 0 sur 1-F0 */ +# define ZERO_TERMES_DU_TABLEAU_POUR_GOMORY 1.e-14 /*15*/ + +# define BORNE_NATIVE 1 +# define BORNE_AUXILIAIRE_DE_VARIABLE_BORNEE_INFERIEUREMENT 2 +# define BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE 3 + +# define BORNE_AUXILIAIRE_PRESOLVE 4 +# define BORNE_AUXILIAIRE_FICTIVE 5 +# define BORNE_AUXILIAIRE_INVALIDE 6 + +/* Pour les bornes auxiliaires */ +# define UTILISER_BORNES_AUXILIAIRES + /*# undef UTILISER_BORNES_AUXILIAIRES*/ +# define ITERATION_POUR_BORNES_AUXILIAIRES 0 /*1*/ /*100*/ + +# define CYCLE_POUR_SUPPRESSION_DES_BORNES_AUXILIAIRES 100 /*10*/ + +/* Pour l'hyper creux */ +/* 3 valeurs qui servent a decrire le stockage d'un vecteur */ +# define COMPACT_SPX 1 /* Les valeurs non nulles sont compactees au debut du vecteur */ +# define ADRESSAGE_INDIRECT_SPX 2 /* Adressage indirect des valeurs non nulles */ +# define VECTEUR_SPX 3 /* Pas d'adressage particulier */ + +# define TAUX_DE_REMPLISSAGE_POUR_BASE_HYPER_CREUSE 0.03 /*0.03*/ +# define TAUX_DE_REMPLISSAGE_POUR_VECTEUR_HYPER_CREUX 0.04 /*0.03*/ + +# define BASE_HYPER_CREUSE 1 +# define BASE_CREUSE 2 +# define BASE_PLEINE 3 + +# define SEUIL_ECHEC_CREUX 10 /* C'est le nombre de fois ou le resultat doit etre plein + pour passer en plein */ +# define SEUIL_ECHEC_CREUX_STEEPEST 20 /* C'est SEUIL_ECHEC_CREUX pour le steepest edge */ +# define SEUIL_REUSSITE_CREUX 3 /*3*/ /* C'est le nombre de fois ou le resultat doit etre creux + avant de repasser en hyper creux ou l'inverse */ +# define CYCLE_TENTATIVE_HYPER_CREUX 4 /*4*/ /* Cycle pour la tentative de repassage en mode hyper creux */ +# define SEUIL_ABANDON_HYPER_CREUX 4 /*4*/ /* C'est le nombre max de tentative infructueuses a partir + duquel on essai plus de revenir en hyper creux */ + +# define SPX_ACTIVATION_SUPPRESSION_PETITS_TERMES NON_PNE /*OUI_SPX*/ + +# define UTILISER_PNE_RAND OUI_SPX + +/* Pour la base reduite */ +# define VERIFICATION_PI NON_SPX +# define VERIFICATION_BBARRE NON_SPX +# define VERIFICATION_ERBMOINS1 NON_SPX +# define VERIFICATION_ABARRES NON_SPX +# define VERIFICATION_STEEPEST NON_SPX +# define VERIFICATION_MAJ_BBARRE NON_SPX + +# define NB_MAX_DE_REACTIVATIONS_DE_LA_BASE_REDUITE 3 +# define NB_DE_BASE_REDUITE_SUCCESSIVES_SANS_PRISE_EN_COMPTE_DES__VIOLATIONS 20 +# define NB_DE_BASES_COMPLETES_SUCCESSIVES 5 + +# define OUI_1_FOIS 1 +# define NON_1_FOIS 2 +# define OUI_2_FOIS 3 +# define NON_2_FOIS 4 + +# define POIDS_DANS_VALEUR_DE_VIOLATION OUI_SPX /* Pour le choix des variables sortantes */ + +# define PRICING_AVEC_VIOLATIONS_STRICTES NON_SPX /* OUI_SPX: on considere que les tolerance de violation sont nullles dans la liste + des variables basiques a surveiller */ + +# define FAIRE_UN_BRUITAGE_INITIAL_DES_COUTS OUI_SPX + +/*******************************************************************************************/ +# define DEFINITIONS_CONSTANTES_INTERNES_SPX_FAITE +# endif + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_construction_matrice_reduite.c b/src/ext/Sirius_Solver/simplexe/spx_construction_matrice_reduite.c new file mode 100644 index 0000000000..81926c35ae --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_construction_matrice_reduite.c @@ -0,0 +1,264 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Construction du stockage de la matrice reduite par colonne + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define TRACES 0 + +/*----------------------------------------------------------------------------*/ + +void SPX_ConstructionDeLaMatriceReduite( PROBLEME_SPX * Spx ) +{ +int Var; int NbTrmCol; int * Cdeb; int * CNbTerm; int rr; int * NumeroDeContrainte; +double * ACol; int ic; int icMx; int icNew; int * OrdreLigneDeLaBaseFactorisee; +int RangDeLaMatriceFactorisee; int NbTermesTotal; int * CdebProblemeReduit; +int * CNbTermProblemeReduit; int * IndicesDeLigneDesTermesDuProblemeReduit; +double * ValeurDesTermesDesColonnesDuProblemeReduit; int NbH; int NbRaz; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; +ACol = Spx->ACol; + +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; + +OrdreLigneDeLaBaseFactorisee = Spx->OrdreLigneDeLaBaseFactorisee; + +CdebProblemeReduit = Spx->CdebProblemeReduit; +CNbTermProblemeReduit = Spx->CNbTermProblemeReduit; +ValeurDesTermesDesColonnesDuProblemeReduit = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; +IndicesDeLigneDesTermesDuProblemeReduit = Spx->IndicesDeLigneDesTermesDuProblemeReduit; + +/* Construction de la matrice du probleme reduit stockee par colonne */ +icNew = 0; +NbTermesTotal = 0; +NbH = 0; +NbRaz = 0; +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + CdebProblemeReduit[Var] = icNew; + NbTrmCol = 0; + ic = Cdeb[Var]; + icMx = ic + CNbTerm[Var]; + if ( NbTermesTotal + CNbTerm[Var] >= Spx->NbElementsAllouesPourLeProblemeReduit ) { + Spx->NbElementsAllouesPourLeProblemeReduit += CNbTerm[Var] * 10; + Spx->ValeurDesTermesDesColonnesDuProblemeReduit = (double *) realloc( Spx->ValeurDesTermesDesColonnesDuProblemeReduit, Spx->NbElementsAllouesPourLeProblemeReduit * sizeof( double ) ); + Spx->IndicesDeLigneDesTermesDuProblemeReduit = (int *) realloc( Spx->IndicesDeLigneDesTermesDuProblemeReduit, Spx->NbElementsAllouesPourLeProblemeReduit * sizeof( int ) ); + if ( Spx->ValeurDesTermesDesColonnesDuProblemeReduit == NULL || Spx->IndicesDeLigneDesTermesDuProblemeReduit == NULL ) { + printf("Simplexe, sous-programme SPX_FactoriserLaBase: \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); + } + ValeurDesTermesDesColonnesDuProblemeReduit = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; + IndicesDeLigneDesTermesDuProblemeReduit = Spx->IndicesDeLigneDesTermesDuProblemeReduit; + } + + while ( ic < icMx ) { + rr = OrdreLigneDeLaBaseFactorisee[NumeroDeContrainte[ic]]; + if ( rr < RangDeLaMatriceFactorisee ) { + ValeurDesTermesDesColonnesDuProblemeReduit[icNew] = ACol[ic]; + IndicesDeLigneDesTermesDuProblemeReduit[icNew] = rr; + NbTrmCol++; + icNew++; + } + ic++; + } + CNbTermProblemeReduit[Var] = NbTrmCol; + + /* Pour la partie hors systeme reduit, on remet tous les couts a leur valeur d'origine */ + if ( NbTrmCol == 0 && 0 ) { + if ( Spx->C[Var] != Spx->Csv[Var] ) NbRaz++; + Spx->C[Var] = Spx->Csv[Var]; + Spx->CorrectionDuale[Var] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + NbH++; + } + + NbTermesTotal += NbTrmCol; + +} + +# if TRACES == 1 + printf("\n Nombre de variables hors du probleme reduit %d sur %d restent %d / nombre de couts remis a zero: %d\n", + NbH,Spx->NombreDeVariables,Spx->NombreDeVariables-NbH,NbRaz); + printf("\n Nombre de termes de la matrice reduite des contraintes %d\n",NbTermesTotal); +# endif + +return; + +# ifdef COMPILER_LA_SUITE + +/* Test: on regarde si on peut fixer des variables */ +char * SensContrainte; int Cnt; int il; char Signe; int NbFix; int NbIneg; double * XminSv; double * XmaxSv; int NbRlx; double Smin; double Smax; int ilMax; int NbForcing; char Rebouclage; +SensContrainte = (char *) malloc( Spx->NombreDeContraintes * sizeof( char ) ); +XminSv = (double *) malloc( Spx->NombreDeVariables * sizeof( double ) ); +XmaxSv = (double *) malloc( Spx->NombreDeVariables * sizeof( double ) ); +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + XminSv[Var] = Spx->Xmin[Var]; + XmaxSv[Var] = Spx->Xmax[Var]; +} + +NbIneg = 0; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + il = Spx->Mdeb[Cnt] + Spx->NbTerm[Cnt] - 1; + Var = Spx->Indcol[il]; + if ( Spx->OrigineDeLaVariable[Var] == ECART ) { SensContrainte[Cnt] = '<'; NbIneg++; } + else SensContrainte[Cnt] = '='; +} + +NbFix = 0; +for ( Var = 0 ; Var < Spx->NombreDeVariablesNatives ; Var++ ) { + + if ( Spx->C[Var] > 0 ) Signe = '+'; + else if ( Spx->C[Var] < 0 ) Signe = '-'; + else Signe = '0'; + + ic = CdebProblemeReduit[Var]; + icMx = ic + CNbTermProblemeReduit[Var]; + while ( ic < icMx ) { + rr = IndicesDeLigneDesTermesDuProblemeReduit[ic]; + Cnt = Spx->LigneDeLaBaseFactorisee[rr]; + if ( SensContrainte[Cnt] == '=' ) { Signe = '!'; break; } + else { + if ( ValeurDesTermesDesColonnesDuProblemeReduit[ic] > 0 ) { + if ( Signe == '-' ) { Signe = '!'; break; } + else if ( Signe == '0' ) Signe = '+'; + } + else if ( ValeurDesTermesDesColonnesDuProblemeReduit[ic] < 0 ) { + if ( Signe == '+' ) { Signe = '!'; break; } + else if ( Signe == '0' ) Signe = '-'; + } + } + ic++; + } + if ( Signe == '!' ) continue; + else if ( Signe == '+' ) { + Spx->Xmax[Var] = Spx->Xmin[Var]; + } + else if ( Signe == '-' ){ + Spx->Xmin[Var] = Spx->Xmax[Var]; + } + else { + Spx->Xmax[Var] = Spx->Xmin[Var]; + } + NbFix++; +} + +NbRlx = 0; +NbForcing = 0; +REBOUCLAGE: +Rebouclage = NON_SPX; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + if ( SensContrainte[Cnt] == 'R' ) continue; + il = Spx->Mdeb[Cnt]; + ilMax = il + Spx->NbTerm[Cnt]; + Smin = 0; + Smax = 0; + while ( il < ilMax ) { + Var = Spx->Indcol[il]; + if ( Spx->A[il] > 0 ) { + Smin += Spx->A[il] * Spx->Xmin[Var]; + Smax += Spx->A[il] * Spx->Xmax[Var]; + } + else { + Smin += Spx->A[il] * Spx->Xmax[Var]; + Smax += Spx->A[il] * Spx->Xmin[Var]; + } + il++; + } + if ( SensContrainte[Cnt] == '<' ) { + if ( Smax <= Spx->B[Cnt] ) { + NbRlx++; + SensContrainte[Cnt] = 'R'; + } + else if ( Smin >= Spx->B[Cnt] ) { + NbForcing++; + SensContrainte[Cnt] = 'R'; + Rebouclage = OUI_SPX; + il = Spx->Mdeb[Cnt]; + ilMax = il + Spx->NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Spx->Indcol[il]; + if ( Spx->Xmax[Var] != Spx->Xmin[Var] ) NbFix++; + if ( Spx->A[il] > 0 ) Spx->Xmax[Var] = Spx->Xmin[Var]; + else Spx->Xmin[Var] = Spx->Xmax[Var]; + il++; + } + } + } + else { + if ( fabs( Smax - Spx->B[Cnt] ) < 1.e-8 ) { + NbForcing++; + SensContrainte[Cnt] = 'R'; + Rebouclage = OUI_SPX; + il = Spx->Mdeb[Cnt]; + ilMax = il + Spx->NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Spx->Indcol[il]; + if ( Spx->Xmax[Var] != Spx->Xmin[Var] ) NbFix++; + if ( Spx->A[il] > 0 ) Spx->Xmin[Var] = Spx->Xmax[Var]; + else Spx->Xmax[Var] = Spx->Xmin[Var]; + il++; + } + + } + else if ( fabs( Smin - Spx->B[Cnt] ) < 1.e-8 ) { + NbForcing++; + SensContrainte[Cnt] = 'R'; + Rebouclage = OUI_SPX; + il = Spx->Mdeb[Cnt]; + ilMax = il + Spx->NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Spx->Indcol[il]; + if ( Spx->Xmax[Var] != Spx->Xmin[Var] ) NbFix++; + if ( Spx->A[il] > 0 ) Spx->Xmax[Var] = Spx->Xmin[Var]; + else Spx->Xmin[Var] = Spx->Xmax[Var]; + il++; + } + } + } +} +if ( Rebouclage == OUI_SPX ) goto REBOUCLAGE; + +free( SensContrainte ); +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + Spx->Xmin[Var] = XminSv[Var]; + Spx->Xmax[Var] = XmaxSv[Var]; +} +free( XminSv ); +free( XmaxSv ); + +printf("NbRlx %d NbForcing %d\n",NbRlx,NbForcing); + +printf("NbFix %d sur %d restent %d\n",NbFix,Spx->NombreDeContraintes,Spx->NombreDeContraintes-NbFix); +printf("Nombre de contraintes d'inegalite %d\n",NbIneg); +/* Fin test */ + +# endif + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_construire_probleme.c b/src/ext/Sirius_Solver/simplexe/spx_construire_probleme.c new file mode 100644 index 0000000000..96e9e91c25 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_construire_probleme.c @@ -0,0 +1,581 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + FONCTION: Construction du probleme + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_ConstruireLeProbleme( + PROBLEME_SPX * Spx, + double * C_E, /* Couts lineaires */ + double * X_E, /* Inconnues */ + double * Xmin_E, /* Borne inf des variables */ + double * Xmax_E, /* Borne sup des variables */ + int NbVar_E, /* Nombre de variables */ + int * TypeVar_E, /* Indicateur du type de variable, il ne doit prendre que les + suivantes (voir le fichier spx_define.h mais ne jamais utiliser + les valeurs explicites des constantes): + VARIABLE_FIXE , + VARIABLE_BORNEE_DES_DEUX_COTES , + VARIABLE_BORNEE_INFERIEUREMENT , + VARIABLE_BORNEE_SUPERIEUREMENT , + VARIABLE_NON_BORNEE + */ + /* La matrice des contraintes rangee par lignes */ + int NbContr_E, /* Nombre de contraintes */ + int * Mdeb_E, /* Indice debut (dans A) des lignes de la matrice des + contraintes */ + int * NbTerm_E, /* Nombre de termes de la ligne */ + int * Indcol_E, /* Indice colonne des termes de chaque ligne. + Attention, les termes de la ligne doivent etre + ranges dans l'ordre croissant des indices de + colonnes */ + double * A_E, /* Les termes de la matrice de contraintes contenus + dans un grand vecteur */ + /* Le second membre */ + char * TypeDeContrainte_E, /* Type de contrainte < ou > ou = */ + double * B_E, /* Le second membre */ + /* La base */ + int * PositionDeLaVariable_E, + int NbVarDeBaseComplementaires_E, + int * ComplementDeLaBase_E, + /* Pilotage de l'algorithme dual */ + double CoutMax, + int UtiliserCoutMax + ) +{ +int i; int Cnt_E; int il; int ilMax; int il_E; int ilMax_E; int Var_E; +double Coeff; int Cnt; double S; double Marge; double * Csv; double * C; +double * Xmax; double * Xmin; double * X; char * TypeDeVariable; char * OrigineDeLaVariable; +char * CorrectionDuale; char * PositionDeLaVariable; int * CorrespondanceVarEntreeVarSimplexe; +int * CorrespondanceVarSimplexeVarEntree; int * CorrespondanceCntEntreeCntSimplexe; +int * CorrespondanceCntSimplexeCntEntree; double * ScaleX; double * ScaleB; +double * SeuilDeViolationDeBorne; double * B; int * Mdeb; int * NbTerm; int * Indcol; double * A; +double * BAvantTranslationEtApresScaling; int NombreDeVariables; int NombreDeContraintes; +int NombreDeTermes; char YaDesVariablesBorneesSuperieurement; int NombreDeVariablesNatives; +char * StatutBorneSupCourante; char * StatutBorneSupAuxiliaire; int * NumeroDesVariablesACoutNonNul; +double * SeuilDAmissibiliteDuale1; double * SeuilDAmissibiliteDuale2; + +YaDesVariablesBorneesSuperieurement = NON_SPX; + +# if RELAXATION_CONTRAINTES == OUI_SPX + if ( NbVar_E < NbContr_E ) Spx->FaireDeLaRelaxationDeContrainte = OUI_SPX; + else Spx->FaireDeLaRelaxationDeContrainte = NON_SPX; +# endif + +Spx->FaireScalingLU = 0; +Spx->NombreDeVariables = 0; +Spx->CoutMax = LINFINI_POUR_LE_COUT; /* Attention, ce n'est qu'une securite de plus, il vaut + mieux ne pas trop compter dessus */ +Spx->UtiliserCoutMax = NON_SPX; +if ( Spx->AlgorithmeChoisi == SPX_DUAL && UtiliserCoutMax == OUI_SPX ) { + Marge = 1.e-6 * fabs ( CoutMax ); + if ( Marge < 1.e-6 ) Marge = 1.e-6; + if ( Marge > 1.e+1 ) Marge = 1.e+1; + Spx->CoutMax = CoutMax + Marge; + Spx->UtiliserCoutMax = OUI_SPX; +} + +Spx->ToleranceSurLesVariablesEntieresAjustees = NON_SPX; + +Spx->NombreDeVariablesACoutNonNul = 0; + +Spx->PremierSimplexe = OUI_SPX; +Spx->StockageParColonneSauvegarde = NON_SPX; + +Spx->BuffNbBoundFlip = 0; +Spx->NbItBoundFlip = 0; +Spx->FaireTriRapide = NON_SPX; + +Spx->PartieFixeDuCout = 0.; + +Spx->UnSurRAND_MAX = 1. / RAND_MAX; +/* Initialisation d'une sequence pseudo aleatoire reproductible */ +Spx->A1 = PNE_SRand( 0.192837465 ); /* Fonction PNE */ +srand( 1 ); /* Fonction C */ + +Spx->LeSteepestEdgeEstInitilise = NON_SPX; + +Spx->PlusGrandTermeDeLaMatrice = 1.; + +/* Decompte des variables et premier controle de la base dans le cas ou elle est fournie */ + +Csv = Spx->Csv ; +C = Spx->C; +X = Spx->X; +Xmax = Spx->Xmax; +Xmin = Spx->Xmin; +CorrectionDuale = Spx->CorrectionDuale; +PositionDeLaVariable = Spx->PositionDeLaVariable; +TypeDeVariable = Spx->TypeDeVariable; +OrigineDeLaVariable = Spx->OrigineDeLaVariable; + +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +StatutBorneSupAuxiliaire = Spx->StatutBorneSupAuxiliaire; + +CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; +CorrespondanceVarSimplexeVarEntree = Spx->CorrespondanceVarSimplexeVarEntree; +CorrespondanceCntEntreeCntSimplexe = Spx->CorrespondanceCntEntreeCntSimplexe; +CorrespondanceCntSimplexeCntEntree = Spx->CorrespondanceCntSimplexeCntEntree; + +NombreDeVariables = Spx->NombreDeVariables; +for ( i = 0 ; i < NbVar_E ; i++ ) { + + if ( TypeVar_E[i] == VARIABLE_FIXE ) { + /* La variable est fixe, on suppose que la valeur est donnee dans X_E */ + CorrespondanceVarEntreeVarSimplexe[i] = -1; + PositionDeLaVariable_E[i] = HORS_BASE_SUR_BORNE_INF; /* Histoire d'initialiser la valeur */ + Spx->PartieFixeDuCout += C_E[i] * X_E[i]; + continue; + } + + Csv [NombreDeVariables] = C_E[i]; + C [NombreDeVariables] = 0.; + Xmax [NombreDeVariables] = Xmax_E[i]; + Xmin [NombreDeVariables] = Xmin_E[i]; + CorrectionDuale[NombreDeVariables] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + + if ( TypeVar_E[i] == VARIABLE_BORNEE_DES_DEUX_COTES || + TypeVar_E[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + Spx->PartieFixeDuCout+= C_E[i] * Xmin_E[i]; + } + + if ( Spx->LaBaseDeDepartEstFournie == OUI_SPX ) { + /* Base de depart fournie */ + if ( PositionDeLaVariable_E[i] == EN_BASE ) { + PositionDeLaVariable[NombreDeVariables] = EN_BASE_LIBRE; + /* X[NombreDeVariables] = Xmin_E[i] ; */ + } + else if ( PositionDeLaVariable_E[i] == HORS_BASE_SUR_BORNE_INF ) { + PositionDeLaVariable[NombreDeVariables] = HORS_BASE_SUR_BORNE_INF; + /* X [NombreDeVariables] = Xmin_E[i]; */ + } + else if ( PositionDeLaVariable_E[i] == HORS_BASE_SUR_BORNE_SUP ) { + PositionDeLaVariable[NombreDeVariables] = HORS_BASE_SUR_BORNE_SUP; + /* X [NombreDeVariables] = Xmax_E[i]; */ + } + else if ( PositionDeLaVariable_E[i] == HORS_BASE_A_ZERO ) { + PositionDeLaVariable[NombreDeVariables] = HORS_BASE_A_ZERO; + /* X [NombreDeVariables] = 0.; */ + } + else { + printf(" Bug dans la fourniture de la base de depart, la variable %d est mal positionnee\n",i); + printf(" son positionnement donne est %d \n",(int) PositionDeLaVariable_E[i]); + exit(0); + } + } + else { + /* Base de depart non fournie */ + PositionDeLaVariable[NombreDeVariables] = HORS_BASE_SUR_BORNE_INF; + /* X [NombreDeVariables] = Xmin_E[i]; */ + } + + CorrespondanceVarEntreeVarSimplexe[i] = NombreDeVariables; + CorrespondanceVarSimplexeVarEntree[NombreDeVariables] = i; + + if ( TypeVar_E[i] == VARIABLE_BORNEE_DES_DEUX_COTES ) TypeDeVariable[NombreDeVariables] = BORNEE; + else if ( TypeVar_E[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + TypeDeVariable[NombreDeVariables] = BORNEE_INFERIEUREMENT; + Xmax [NombreDeVariables] = LINFINI_POUR_X; + } + else if ( TypeVar_E[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + TypeDeVariable[NombreDeVariables] = BORNEE_SUPERIEUREMENT; + Xmin [NombreDeVariables] = -LINFINI_POUR_X; + YaDesVariablesBorneesSuperieurement = OUI_SPX; + } + else if ( TypeVar_E[i] == VARIABLE_NON_BORNEE ) { + TypeDeVariable[NombreDeVariables] = NON_BORNEE; + Xmin [NombreDeVariables] = -LINFINI_POUR_X; + Xmax [NombreDeVariables] = LINFINI_POUR_X; + } + else { + printf("Erreur entree du solveur: le seul type de variables reconnues est: \n"); + printf(" VARIABLE_FIXE -> valeur de constante: %d\n",(int) VARIABLE_FIXE); + printf(" VARIABLE_BORNEE_DES_DEUX_COTES -> valeur de constante: %d\n",(int) VARIABLE_BORNEE_DES_DEUX_COTES); + printf(" VARIABLE_BORNEE_INFERIEUREMENT -> valeur de constante: %d\n",(int) VARIABLE_BORNEE_INFERIEUREMENT); + printf(" VARIABLE_BORNEE_SUPERIEUREMENT -> valeur de constante: %d\n",(int) VARIABLE_BORNEE_SUPERIEUREMENT); + printf(" VARIABLE_NON_BORNEE -> valeur de constante: %d\n",(int) VARIABLE_NON_BORNEE); + printf("Or la variable %d est du type %d => exit volontaire car pb de mise au point\n",i,(int) TypeVar_E[i]); + exit(0); + } + + OrigineDeLaVariable [NombreDeVariables] = NATIVE; + StatutBorneSupCourante [NombreDeVariables] = BORNE_NATIVE; + StatutBorneSupAuxiliaire[NombreDeVariables] = BORNE_AUXILIAIRE_INVALIDE; + + NombreDeVariables++; + +} + +Spx->NombreDeVariables = NombreDeVariables; +Spx->NombreDeVariablesNatives = NombreDeVariables; +NombreDeVariablesNatives = NombreDeVariables; + +B = Spx->B; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; + +Spx->NombreDeContraintes = 0; +NombreDeContraintes = 0; +for ( il = 0 , Cnt_E = 0 ; Cnt_E < NbContr_E ; Cnt_E++ ) { + + CorrespondanceCntEntreeCntSimplexe[Cnt_E] = -1; + + Coeff = 1.; + if ( TypeDeContrainte_E[Cnt_E] == '>' ) Coeff = -1.; /* Pour transformer en < */ + + Mdeb[NombreDeContraintes] = il; + NombreDeTermes = 0; + S = 0.0; + + il_E = Mdeb_E[Cnt_E]; + ilMax_E = il_E + NbTerm_E[Cnt_E]; + while ( il_E < ilMax_E) { + Var_E = Indcol_E[il_E]; + /* On verifie le numero de la variable car il se peut que la contrainte + contienne des variables d'ecart (exemple coupes de Gomory) dans ce cas + la contrainte sera construite lorsque les variables d'ecart seront connues */ + if ( Var_E >= NbVar_E ) { + NombreDeTermes = 0; + break; + } + if ( TypeVar_E[Var_E] == VARIABLE_FIXE ) { + /* Si la variable est fixee, on ne la met pas dans la matrice des contraintes + mais on la comptabilise dans le second membre */ + /*S+= A_E[il_E] * X_E[Var_E];*/ + /* BUG 14/12/2015: il faut aussi multipilier par Coeff comme dans le cas ou + la variable n'est pas fixee */ + S += Coeff * A_E[il_E] * X_E[Var_E]; + } + else { + A [il] = Coeff * A_E[il_E]; + Indcol[il] = CorrespondanceVarEntreeVarSimplexe[Var_E]; + NombreDeTermes++; + il++; + } + il_E++; + } + /* Il y a des variables non fixees dans la contrainte ? */ + if ( NombreDeTermes == 0 ) { /* Pas de nouvelle contrainte => fin de boucle */ + /* printf("PAS NOUVELLE CONTRAINTE\n"); */ + if ( TypeDeContrainte_E[Cnt_E] == '=' ) { + if ( fabs( S - B_E[Cnt_E] ) > SEUIL_DADMISSIBILITE ) { + Spx->YaUneSolution = NON_SPX; return; + } + } + else if ( TypeDeContrainte_E[Cnt_E] == '<' ) { + if ( S > B_E[Cnt_E] + SEUIL_DADMISSIBILITE ) { + Spx->YaUneSolution = NON_SPX; return; + } + } + else if ( TypeDeContrainte_E[Cnt_E] == '>' ) { + if ( S < B_E[Cnt_E] - SEUIL_DADMISSIBILITE ) { + Spx->YaUneSolution = NON_SPX; return; + } + } + continue; + } + + /* Les variables additionnelles */ + + if ( TypeDeContrainte_E[Cnt_E] == '=' ) { + /* Dans le cas des contraintes d'egalite il ne peut y avoir au plus qu'une seule + variable additionnelle laquelle sera affectée a la base initiale */ + il++; /* On laisse de la place pour l'eventuelle variable de base */ + } + else { + /* Dans le cas des contraintes d'inegalite il ne peut y avoir au plus que 2 + variables additionnelles une variable d'ecart et si necessaire une variable + affectée a la base initiale */ + il++; /* On laisse de la place pour la variable d'ecart */ + il++; /* On laisse de la place pour l'eventuelle variable de base */ + } + + NbTerm[NombreDeContraintes] = NombreDeTermes; + B[NombreDeContraintes] = ( Coeff * B_E[Cnt_E] ) - S; + + CorrespondanceCntSimplexeCntEntree[NombreDeContraintes] = Cnt_E; + CorrespondanceCntEntreeCntSimplexe[Cnt_E] = NombreDeContraintes; + NombreDeContraintes++; + +} +Spx->NombreDeContraintes = NombreDeContraintes; + +# if SPX_ACTIVATION_SUPPRESSION_PETITS_TERMES == OUI_SPX + /* Imperatif: a faire avant la mise sous forme standard des contraintes */ + /* C'est deja fait dans la partie pne mais comme le simplexe petit etre appele separement, + et qu'a ce niveau on ne le sait pas, on relance ce calcul. + Remarque: il se peut cependant (rarissime) qu'il y a une (legere) difference avec la + partie PNE. En effet, la suppression des tout petit termes y est faite avant le + presolve or le simplexe est appele apres le presolve */ + PNE_EnleverLesToutPetitsTermes( Mdeb, NbTerm, Indcol, A, Xmax, Xmin, NombreDeContraintes, Spx->AffichageDesTraces ); +# endif + +if ( YaDesVariablesBorneesSuperieurement == NON_SPX ) goto FinVariablesBorneesSuperieurement; + +/* Transformation interne: les variables de type BORNEE_SUPERIEUREMENT sont transformees en BORNEE_INFERIEUREMENT + par un simple changement de variable */ +/* 1- Partie cout et bornes */ +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + if ( TypeDeVariable[i] != BORNEE_SUPERIEUREMENT ) continue; + Csv [i] = -Csv[i]; + C [i] = -C[i]; + Xmin[i] = -Xmax[i]; + Xmax[i] = LINFINI_POUR_X; +} + +/* 2- Partie matrice des contraintes */ +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( TypeDeVariable[Indcol[il]] == BORNEE_SUPERIEUREMENT ) A[il] = -A[il]; + il++; + } +} + +/* 3- Changement de variable */ +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + if ( TypeDeVariable[i] == BORNEE_SUPERIEUREMENT ) TypeDeVariable[i] = BORNEE_INFERIEUREMENT; +} +/* Fin de la transformation interne BORNEE_SUPERIEUREMENT -> BORNEE_INFERIEUREMENT */ + +FinVariablesBorneesSuperieurement: + +/* Scaling du probleme avant sa mise sous forme standard (on le fait ici pour eviter + de faire un scaling sur les variables additionnelles de toutes sortes) */ + +BAvantTranslationEtApresScaling = Spx->BAvantTranslationEtApresScaling; +memcpy( (char *) BAvantTranslationEtApresScaling, (char *) B, Spx->NombreDeContraintes * sizeof( double ) ); + +SPX_TranslaterLesBornes( Spx ); + +/* SPX_ChainageDeLaTransposee( Spx , CREUX ); */ /* Car le scaling ne l'utilise plus */ + +ScaleX = Spx->ScaleX; +ScaleB = Spx->ScaleB; +SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; + +Spx->ScaleLigneDesCouts = 1.; +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + ScaleX [i] = 1.; + SeuilDeViolationDeBorne[i] = SEUIL_DE_VIOLATION_DE_BORNE; +} +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) ScaleB[i] = 1.; + +SeuilDAmissibiliteDuale1 = Spx->SeuilDAmissibiliteDuale1; +SeuilDAmissibiliteDuale2 = Spx->SeuilDAmissibiliteDuale2; +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + SeuilDAmissibiliteDuale1[i] = SEUIL_ADMISSIBILITE_DUALE_1; + SeuilDAmissibiliteDuale2[i] = SEUIL_ADMISSIBILITE_DUALE_2; +} + +/* Calcul des matrices de scaling */ +SPX_CalculerLeScaling( Spx ); +/* Application du scaling */ +SPX_Scaling( Spx ); + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + BAvantTranslationEtApresScaling[Cnt] *= ScaleB[Cnt]; +} + +/* Mise du probleme sous la forme standard */ +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + Cnt_E = CorrespondanceCntSimplexeCntEntree[Cnt]; + if ( Cnt_E < 0 ) { + printf(" Bug dans SPX_ConstruireLeProbleme \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } + /* Mise sous forme standard */ + if ( TypeDeContrainte_E[Cnt_E] != '=' ) { + SPX_MettreLaContrainteSousFormeStandard( Spx , Cnt ); + if ( Spx->YaUneSolution == NON_SPX ) return; + } +} + +/* Construction de la base de depart */ + +/* SPX_ChainageDeLaTransposee( Spx , COMPACT ); */ + +if ( Spx->LaBaseDeDepartEstFournie == NON_SPX ) SPX_DualConstruireUneCrashBase( Spx ); +else { + SPX_DualConstruireLaBaseInitiale( Spx, NbVar_E , PositionDeLaVariable_E, + NbVarDeBaseComplementaires_E, ComplementDeLaBase_E , + TypeDeContrainte_E ); +} + +/* Stockage de la matrice des contraintes dans l'ordre croissant des colonnes */ +/* Apres plusieurs essais, le stockage dans l'ordre ne semble pas avoir d'impatc + significatif sur les temps de calculs */ +/* +SPX_OrdonnerMatriceDesContraintes( Spx->NombreDeContraintes, Spx->Mdeb, Spx->NbTerm, + Spx->Indcol, Spx->A ); +*/ + +SPX_ChainageDeLaTransposee( Spx , COMPACT ); + +/* Et on complete le facteur de scaling pour les variables ajoutees */ +for ( i = NombreDeVariablesNatives ; i < Spx->NombreDeVariables ; i++ ) { + ScaleX [i] = 1.; + CorrectionDuale[i] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; +} + +#if VERBOSE_SPX + printf("Nombre de variables dans le simplexe %d\n", Spx->NombreDeVariables); + fflush( stdout ); +#endif + +memcpy( (char *) C, (char *) Csv, Spx->NombreDeVariables * sizeof( double ) ); + +il = 0; +NumeroDesVariablesACoutNonNul = Spx->NumeroDesVariablesACoutNonNul; +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + if ( C[i] != 0 ) { + NumeroDesVariablesACoutNonNul[il] = i; + il++; + } +} +Spx->NombreDeVariablesACoutNonNul = il; + +/* Sauvegarde du nombre de variables et du nombre de contraintes simplexe du + probleme sans coupes */ +Spx->NombreDeVariablesDuProblemeSansCoupes = Spx->NombreDeVariables; +Spx->NombreDeContraintesDuProblemeSansCoupes = Spx->NombreDeContraintes; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* A ce stade, les contraintes d'inegalite sont toujours de signe < + et la place pour la variable d'ecart a deja ete reservee */ + +void SPX_MettreLaContrainteSousFormeStandard( PROBLEME_SPX * Spx , int Cnt ) +{ +int il; int ilMax; int Var; double Smin; double Seuil; int * Indcol; double * A; +double * Xmin; double * Xmax; char * TypeDeVariable; double * B; int * Mdeb; +int * NbTerm; double * XminEntree; double * X; double * C; double * ScaleB; +double * SeuilDeViolationDeBorne; double * XmaxEntree; int * CntVarEcartOuArtif; +int * CorrespondanceVarSimplexeVarEntree; char * PositionDeLaVariable; +double * Csv; char * OrigineDeLaVariable; char * StatutBorneSupCourante; char * StatutBorneSupAuxiliaire; + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; +B = Spx->B; +ScaleB = Spx->ScaleB; +TypeDeVariable = Spx->TypeDeVariable; +Xmin = Spx->Xmin; +Xmax = Spx->Xmax; +XminEntree = Spx->XminEntree; +XmaxEntree = Spx->XmaxEntree; +X = Spx->X; +C = Spx->C; +Csv = Spx->Csv; +SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; +PositionDeLaVariable = Spx->PositionDeLaVariable; +OrigineDeLaVariable = Spx->OrigineDeLaVariable; +CntVarEcartOuArtif = Spx->CntVarEcartOuArtif; +CorrespondanceVarSimplexeVarEntree = Spx->CorrespondanceVarSimplexeVarEntree; + +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +StatutBorneSupAuxiliaire = Spx->StatutBorneSupAuxiliaire; + +il = Mdeb[Cnt]; +ilMax = il + NbTerm[Cnt]; +Smin = 0.; +while ( il < ilMax) { + Var = Indcol[il]; + if ( A[il] <= 0. ) { + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT || TypeDeVariable[Var] == NON_BORNEE ) goto CreationDeLaVariableDEcart; + Smin+= A[il] * Xmax[Var]; + } + else { + if ( TypeDeVariable[Var] == NON_BORNEE ) goto CreationDeLaVariableDEcart; + Smin+= A[il] * Xmin[Var]; + } + il++; +} + +if ( Smin > ( B[Cnt] + SEUIL_DADMISSIBILITE ) ) { + #if VERBOSE_SPX + printf("Simplexe: impossible de satisfaire la contrainte d'inegalite %d car Smin = %lf B = %lf \n",Cnt,Smin,Spx->B[Cnt]); + #endif + Spx->YaUneSolution = NON_SPX; + return; +} + +CreationDeLaVariableDEcart: + +/* Creation de la variable d'ecart */ +XminEntree [Spx->NombreDeVariables] = 0.; +X [Spx->NombreDeVariables] = 0.; +C [Spx->NombreDeVariables] = 0.; +Xmin [Spx->NombreDeVariables] = 0.; +Xmax [Spx->NombreDeVariables] = LINFINI_POUR_X; +TypeDeVariable[Spx->NombreDeVariables] = BORNEE_INFERIEUREMENT; + +Seuil = SEUIL_DE_VIOLATION_DE_BORNE_NON_NATIVE * ScaleB[Cnt]; + +if ( Seuil < SEUIL_MIN_DE_VIOLATION_DE_BORNE_NON_NATIVE ) Seuil = SEUIL_MIN_DE_VIOLATION_DE_BORNE_NON_NATIVE; +else if ( Seuil > SEUIL_MAX_DE_VIOLATION_DE_BORNE_NON_NATIVE ) Seuil = SEUIL_MAX_DE_VIOLATION_DE_BORNE_NON_NATIVE; + +SeuilDeViolationDeBorne[Spx->NombreDeVariables] = Seuil; + +Spx->SeuilDAmissibiliteDuale1[Spx->NombreDeVariables] = SEUIL_ADMISSIBILITE_DUALE_1; +Spx->SeuilDAmissibiliteDuale2[Spx->NombreDeVariables] = SEUIL_ADMISSIBILITE_DUALE_2; + +XmaxEntree[Spx->NombreDeVariables] = Xmax[Spx->NombreDeVariables]; + +CorrespondanceVarSimplexeVarEntree[Spx->NombreDeVariables] = -1; + +PositionDeLaVariable[Spx->NombreDeVariables] = HORS_BASE_SUR_BORNE_INF; + +/* On la met dans l'equation de la contrainte */ +il = Mdeb[Cnt] + NbTerm[Cnt]; /* On a deja reserve la place de cette variable a la creation du probleme */ +NbTerm[Cnt]++; +Indcol[il] = Spx->NombreDeVariables; +A [il] = 1.; /* Important: ne pas mettre autre chose que 1 */ + +Csv [Spx->NombreDeVariables] = C[Spx->NombreDeVariables]; +OrigineDeLaVariable [Spx->NombreDeVariables] = ECART; +StatutBorneSupCourante [Spx->NombreDeVariables] = BORNE_NATIVE; +StatutBorneSupAuxiliaire[Spx->NombreDeVariables] = BORNE_AUXILIAIRE_INVALIDE; + +CntVarEcartOuArtif [Spx->NombreDeVariables] = Cnt; + +/* Incrementation du nombre de variables */ +Spx->NombreDeVariables++; + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_creation_noeuds_en_exploration_rapide.c b/src/ext/Sirius_Solver/simplexe/spx_creation_noeuds_en_exploration_rapide.c new file mode 100644 index 0000000000..47527715d3 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_creation_noeuds_en_exploration_rapide.c @@ -0,0 +1,190 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: En exploration rapide (pilotee par le branch and bound), + creation des noeuds fils d'un noeud qui vient d'etre + evalue. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +#include "pne_define.h" + +#include "bb_define.h" +#include "bb_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +/* On connait le noeud courant, c'est celui qui vient d'ętre examiné */ +void Spx_CreationNoeudsFils( PROBLEME_SPX * Spx, void * PneProb, void * BbProb, + int VariablesPneAInstancier ) +{ +NOEUD * NoeudPere; NOEUD * Noeud; NOEUD * NoeudEnExamen; /*int CodeRetour ;*/ int FilsACreer; int ValeurDInstanciation; +int NombreDeVariablesAInstancier; int NumerosDesVariablesAInstancier[1]; int Var; int VariableDEcart; +int NbVarDeBaseComplementaires; int NbT; int il; int ilMax; int Cnt; int Cnt_E; int NumCoupe; +int NombreDeVariablesPNE; int VarPne; int YaUneSolution; double ValeurDuCritereAuNoeud; + +PROBLEME_PNE * Pne; BB * Bb; + +Pne = (PROBLEME_PNE *) PneProb; +Bb = (BB *) BbProb; + +NombreDeVariablesPNE = Pne->NombreDeVariablesTrav; + +NoeudEnExamen = Bb->NoeudEnExamen; + +ValeurDuCritereAuNoeud = Spx->Cout; + +/* La base de depart des fils sera la base courante */ + +NombreDeVariablesAInstancier = 1; +NumerosDesVariablesAInstancier[0] = VariablesPneAInstancier; + +YaUneSolution = OUI; + +/* Pour eviter de supprimer ce noeud lors du nettoyage de l'arbre, on diminue la + valeur du minorant par rapport au cout de la solution entiere */ +/* Il y a un test dans NettoyerArbre ou on enleve 1.e-9 a la meilleure solution entiere */ +if ( ValeurDuCritereAuNoeud >= Bb->CoutDeLaMeilleureSolutionEntiere - 1.e-9 ) { + ValeurDuCritereAuNoeud = Bb->CoutDeLaMeilleureSolutionEntiere - 2.e-9 ; +} +NoeudEnExamen->MinorantDuCritereAuNoeud = ValeurDuCritereAuNoeud; + +/* printf("Cout %e CoutMax %e\n",Spx->Cout,Spx->CoutMax); */ + +BB_NettoyerLArbre( Bb, &YaUneSolution , NoeudEnExamen ); /* Fait aussi la mise a jour du statut */ + +Bb->BasesFilsDisponibles = NON_PNE; + +for ( VarPne = 0 ; VarPne < NombreDeVariablesPNE ; VarPne++ ) NoeudEnExamen->PositionDeLaVariable[VarPne] = -1; + +for ( VarPne = 0 ; VarPne < NombreDeVariablesPNE ; VarPne++ ) { + Var = Spx->CorrespondanceVarEntreeVarSimplexe[VarPne]; + if ( Var >= 0 ) { + if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + NoeudEnExamen->PositionDeLaVariable[VarPne] = HORS_BASE_SUR_BORNE_SUP; + } + else if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + NoeudEnExamen->PositionDeLaVariable[VarPne] = HORS_BASE_SUR_BORNE_INF; + } + else if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_A_ZERO ) { + NoeudEnExamen->PositionDeLaVariable[VarPne] = HORS_BASE_A_ZERO; + } + else { + /* Une variable native est basique. Si la contrainte de cette variable en base + est une coupe, on va considerer que cette coupe est saturee. En principe, elle + sera conservee. */ + NoeudEnExamen->PositionDeLaVariable[VarPne] = EN_BASE; + } + } +} + +NbVarDeBaseComplementaires = 0; +for ( Var = 0 ; Var < Spx->NombreDeVariablesDuProblemeSansCoupes ; Var++ ) { + + if ( Spx->OrigineDeLaVariable[Var] == NATIVE ) continue; + + if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP || + Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF || + Spx->PositionDeLaVariable[Var] == HORS_BASE_A_ZERO ) continue; + + /* La variable est en base, la colonne de la variable doit avoir un seul terme */ + NbT = 0; + il = Spx->Cdeb[Var]; + ilMax = il + Spx->CNbTerm[Var]; + while ( il < ilMax ) { + NbT++; + Cnt = Spx->NumeroDeContrainte[il]; + il++; + } + if ( NbT != 1 ) { + printf("Bug dans SPX_RecupererLaSolution nombre de termes dans la colonne de la variable %d incorrect, %d\n",Var,NbT); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } + Cnt_E = Spx->CorrespondanceCntSimplexeCntEntree[Cnt]; + if ( Cnt_E >= 0 ) { + NoeudEnExamen->ComplementDeLaBase[NbVarDeBaseComplementaires] = Cnt_E; + NbVarDeBaseComplementaires = NbVarDeBaseComplementaires + 1; + } +} +NoeudEnExamen->NbVarDeBaseComplementaires = NbVarDeBaseComplementaires; + +/* Il faut determiner l'etat de saturation des coupes */ + +NumCoupe = 0; +if ( Spx->NombreDeContraintes - Spx->NombreDeContraintesDuProblemeSansCoupes != Bb->NombreDeCoupesAjoutees ) { + printf("pb Bb->NombreDeCoupesAjoutees dans SPX\n"); +} +for ( Cnt = Spx->NombreDeContraintesDuProblemeSansCoupes ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + /* On cherche la variable Cnt_E correspondante */ + /* while ( NbTermCoupes[Cnt_E] <= 0 ) NumCoupe; attention je crois que dans certains car il peut y avoir 0 termes dans une coupe + oui mais alors elle ne sont pas rpise en compte dans modifier probleme mais NumCoupe il y a probleme dans la + numeortation . Il peut y avoir 0 termes car il peut y avoir appel a une fonction qui met ca a + O pour le noeud racine dans PNE trier les coupes */ + /* Variable d'ecart */ + VariableDEcart = Spx->Indcol[Spx->Mdeb[Cnt] + Spx->NbTerm[Cnt] - 1]; + if ( Spx->PositionDeLaVariable[VariableDEcart] == HORS_BASE_SUR_BORNE_INF ) { + /* La coupe est saturee */ + Bb->CoupeSaturee[NumCoupe] = OUI_PNE; + } + else { + /* La coupe n'est pas saturee */ + Bb->CoupeSaturee[NumCoupe] = NON_PNE; + } + NumCoupe++; +} + +NoeudPere = NoeudEnExamen; + +FilsACreer = FILS_GAUCHE; +ValeurDInstanciation = 0; +Noeud = BB_AllouerUnNoeud( Bb, + NoeudPere, + NoeudPere->ProfondeurDuNoeud + 1, + FilsACreer, + ValeurDInstanciation, + NombreDeVariablesAInstancier, + NumerosDesVariablesAInstancier, + ValeurDuCritereAuNoeud ); +NoeudPere->NoeudSuivantGauche = Noeud; + +SPX_SauvegarderLaBaseDeDepart( Spx , (void *) Noeud ); + +FilsACreer = FILS_DROIT; +ValeurDInstanciation = 1; +Noeud = BB_AllouerUnNoeud( Bb, + NoeudPere, + NoeudPere->ProfondeurDuNoeud + 1, + FilsACreer, + ValeurDInstanciation, + NombreDeVariablesAInstancier, + NumerosDesVariablesAInstancier, + ValeurDuCritereAuNoeud ); +NoeudPere->NoeudSuivantDroit = Noeud; + +SPX_SauvegarderLaBaseDeDepart( Spx , (void *) Noeud ); + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_define.h b/src/ext/Sirius_Solver/simplexe/spx_define.h new file mode 100644 index 0000000000..4d17c67493 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_define.h @@ -0,0 +1,452 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef DEFINITIONS_SPX_FAITES +/*******************************************************************************************/ + +# include "spx_sys.h" +# include "spx_constantes_externes.h" +# include "spx_constantes_internes.h" + +/* Pour les coupes d'intersection */ +typedef struct{ +int NombreDeTermes; +int * NumeroDeVariableMatrice; +double * ProduitScalaire; +} LIGNE_DE_PRODUITS_SCALAIRES; + +typedef struct{ +/* Les variables continues */ +int NombreDeTermes; +int * NumeroDeVariableSpx; +double * Coefficient; +double SecondMembre; +} LIGNE_DE_MATRICE; + +typedef struct{ +double * Vecteur; +char * LaVariableSpxEstEntiere; /* OUI_SPX ou NON_SPX */ +double * B; +LIGNE_DE_PRODUITS_SCALAIRES ** LigneDeProduitScalaire; +LIGNE_DE_MATRICE ** LigneDeMatrice; +double * NormeAvantReduction; +int NombreDeVariables; +double * XmaxSv; + +double AlphaI0; +char * TSpx; +double * CoeffSpx; +} DONNEES_POUR_COUPES_DINTERSECTION; + +/* Pour les Gomory */ +typedef struct{ +char * T; +double * Coeff; +double * B; +char * LaVariableSpxEstEntiere; /* OUI_SPX ou NON_SPX */ +double * XmaxSv; +} DONNEES_POUR_COUPES_DE_GOMORY; + +/* Pour la mini exploration */ +typedef struct{ +char * PositionDeLaVariable; +char * InDualFramework; +int * ContrainteDeLaVariableEnBase; +double * DualPoids; +int * VariableEnBaseDeLaContrainte; +} BASE_INSTANCIATION; + +typedef struct{ +void * NoeudPere; +void * Fils_0; +void * Fils_1; +BASE_INSTANCIATION * BaseDuNoeud; +int VariableSortieDeLaBase; +char TypeDeSortieDeLaBase; +int Profondeur; +} NOEUD_INSTANCIATION; + +/* Pour le probleme Spx */ +typedef struct { +/* Pour les outils de gestion memoire */ +void * Tas; + +/*------------------------------------------------------------------------*/ +int NbCycles; +char AffichageDesTraces; +char TypeDePricing; /* PRICING_DANTZIG ou PRICING_STEEPEST_EDGE */ +char FaireDuScalingSPX; +char StrategieAntiDegenerescence; /* AGRESSIF ou PEU_AGRESSIF */ +int CycleDeControleDeDegenerescence; + +char EcrireLegendePhase1; +char EcrireLegendePhase2; +int Contexte; +int AlgorithmeChoisi; +int LaBaseDeDepartEstFournie; +int YaUneSolution; +int NombreMaxDIterations; +double DureeMaxDuCalcul; +int CycleDeRefactorisation; +double UnSurRAND_MAX; + +int FaireDuRaffinementIteratif; +char ChoixDeVariableSortanteAuHasard; +char BaseInversibleDisponible; +int NombreMaxDeChoixAuHasard; +int NombreDeChoixFaitsAuHasard; +char AdmissibilitePossible; +char InverseProbablementDense; +char ToleranceSurLesVariablesEntieresAjustees; /* OUI_SPX ou NON_SPX */ + +/*---------------------- Tailles allouees -----------------------*/ +int NombreDeVariablesAllouees; +int NombreDeContraintesAllouees; +int NbTermesAlloues; +/*---------------------- Les variables du probleme ------------------------*/ +char PresenceDeVariablesDeBornesIdentiques; +int NombreDeVariables; +int NombreDeVariablesACoutNonNul; +int NombreDeVariablesNatives; +int NombreDeVariablesDuProblemeSansCoupes; +int * NumeroDesVariablesACoutNonNul; +double * C; /* Dimension nombre de variables */ +double * Csv; /* Dimension nombre de variables */ +double * X; /* Dimension nombre de variables */ +double * Xmin; /* Dimension nombre de variables */ +double * Xmax; /* Dimension nombre de variables */ +char * TypeDeVariable; /* 3 valeurs possibles: + BORNEE , BORNEE_INFERIEUREMENT , NON_BORNEE */ +char * OrigineDeLaVariable; /* 3 valeurs possibles: + NATIVE , ECART , BASIQUE_ARTIFICIELLE */ +/* Bornes auxiliaires: +1- Pour l'instant seul la borne sup est utilisee. +2- Pour l'instant seul le type BORNE_AUXILIAIRE_PRESOLVE est utilise. +3- Elles ne s'appliquent pas aux variables non bornees. */ +int NombreDeBornesAuxiliairesUtilisees; +int IterationPourBornesAuxiliaires; +double CoeffMultiplicateurDesBornesAuxiliaires; +char * StatutBorneSupCourante; /* BORNE_NATIVE, BORNE_AUXILIAIRE_PRESOLVE, BORNE_AUXILIAIRE_FICTIVE */ +double * BorneSupAuxiliaire; +char * StatutBorneSupAuxiliaire; /* BORNE_AUXILIAIRE_PRESOLVE, BORNE_AUXILIAIRE_FICTIVE, BORNE_AUXILIAIRE_INVALIDE */ +/* Fin bornes auxilaires */ + +int * CntVarEcartOuArtif; +double * XEntree; /* Dimension nombre de variables */ +double * XminEntree; /* Dimension nombre de variables */ +double * XmaxEntree; /* Dimension nombre de variables */ +double * SeuilDeViolationDeBorne; /* Dimension nombre de variables */ + +double * SeuilDAmissibiliteDuale1; /* Une valeur par variable pour tenir compte du scaling */ +double * SeuilDAmissibiliteDuale2; /* Une valeur par variable pour tenir compte du scaling */ + +double * ScaleX; /* Dimension nombre de variables */ +double ScaleLigneDesCouts; +int * CorrespondanceVarEntreeVarSimplexe; /* Dimension nombre de variables d'entree */ +int * CorrespondanceVarSimplexeVarEntree; /* Dimension nombre de variables d'entree + Nombre de contraintes d'entree */ + +/*------------------------------------------------------------------------*/ +/*---------------------- Matrice des contraintes -------------------------*/ +int NombreDeContraintes; +int NombreDeContraintesDuProblemeSansCoupes; +double * B; /* Dimension nombre de contraintes */ +double * BAvantTranslationEtApresScaling; /* Dimension nombre de contraintes */ +double * ScaleB; /* Dimension nombre de contraintes */ +int * Mdeb; /* Dimension nombre de contraintes */ +int * NbTerm; /* Dimension nombre de contraintes */ +double * A; /* Dimension nombre de termes */ +int * Indcol; /* Dimension nombre de termes */ +int * CorrespondanceCntSimplexeCntEntree; /* Dimension nombre de contraintes */ +int * CorrespondanceCntEntreeCntSimplexe; /* Dimension nombre de contraintes */ +/*-------------------------------------------------------------------------*/ +/*---- Matrice des contraintes avec uniquement les variables hors base ----*/ +int * IndexDansLaMatriceHorsBase; +int * MdebHorsBase; +int * NbTermHorsBase; +double * AHorsBase; +int * IndcolHorsBase; +int * InverseIndexDansLaMatriceHorsBase; + +/*------------------------------------------------------------------------*/ +double ValeurMoyenneDuSecondMembre; /* Pour construire des bornes sup artificielles */ +double PlusGrandTermeDeLaMatrice; +double PlusPetitTermeDeLaMatrice; +double RapportDeScaling; +double CoutMoyen; +double EcartDeBornesMoyen; +double PerturbationMax; +/*---------------- Transposee de la matrice des contraintes --------------*/ +char StockageParColonneSauvegarde; +int * Cdeb ; /* Dimension nombre de variables */ +int * Csui ; /* Dimension nombre de termes */ +int * CNbTerm; /* Dimension nombre de variables */ +int * CNbTermSansCoupes; /* Dimension nombre de variables */ +int * CNbTermesDeCoupes; /* Dimension nombre de variables */ +double * ACol; /* Dimension nombre de termes */ +int * NumeroDeContrainte; /* Dimension nombre de termes */ +int * CdebBase; /* Dimension nombre de contraintes */ +int * NbTermesDesColonnesDeLaBase; /* Dimension nombre de contraintes */ +/*-------------------------- Eta matrices ---------------------------------*/ +int LastEta; +int RemplissageMaxDeLaFPI; +int * EtaDeb; /* Nombre de changements de base avant refactorisation */ +int * EtaNbTerm; /* Nombre de changements de base avant refactorisation */ +int * EtaColonne; /* Nombre de changements de base avant refactorisation */ +int * EtaIndiceLigne; /* Nombre de chgt de base avant refactorisation * nb contraintes */ +double * EtaMoins1Valeur; /* Nombre de chgt de base avant refactorisation * nb contraintes */ +/*------------------------------------------------------------------------*/ +/*------------------- Zone des donnees de travail ------------------------*/ + +int Iteration; +time_t HeureDeCalendrierDebut; +int NbCyclesSansControleDeDegenerescence; +int PhaseEnCours; /* PHASE_1 ou PHASE_2 */ + +int ChangementDeBase; +int VariableEntrante; +double DeltaXSurLaVariableHorsBase; +int VariableSortante; +int SortSurXmaxOuSurXmin; +int NombreDeChangementsDeBase; +char StrongBranchingEnCours; +char PremierSimplexe; +char BBarreAEteCalculeParMiseAJour; /* Vaut OUI_SPX ou NON_SPX */ +char CBarreAEteCalculeParMiseAJour; /* Vaut OUI_SPX ou NON_SPX */ + +/* Tableau de travail */ +int * T; /* dimensionne au nombre de variables (i.e. toujours > au nombre de contraintes, toujours -1 quand on en a besoin */ + +/* Tableaux de travail */ +int NbABarreSNonNuls; /* Utile que dans le cas TypeDeStockageDeABarreS = COMPACT_SPX */ +int * CntDeABarreSNonNuls; /* Utile que dans le cas TypeDeStockageDeABarreS = COMPACT_SPX */ +double * ABarreS; /* Dimension nombre de contraintes */ + +double * Bs; /* Dimension nombre de contraintes */ +double * BBarre; /* Dimension nombre de contraintes */ +char CalculerBBarre; +char FaireMiseAJourDeBBarre; +int BuffNbBoundFlip; +int NbItBoundFlip; +int NbBoundFlipIterationPrecedente; + +int NbBoundFlip; +int * BoundFlip; /* Dimension nombre de variables: (Numero de variable + 1) si passe Xmin vers Xmax + -(Numero de variable + 1) si passe Xmax vers Xmin */ +double ABarreSCntBase; + +/* Donnees concernant la base */ +double * Pi; /* Dimension nombre de contraintes */ +double * CBarre; /* Dimension nombre de variables */ +char * PositionDeLaVariable; /* Dimension nombre de variables */ +int * ContrainteDeLaVariableEnBase; /* Dimension nombre de variables */ +int * VariableEnBaseDeLaContrainte; /* Dimension nombre de contraintes */ +int * NombreDeVariablesHorsBaseDeLaContrainte; /* Dimension nombre de contraintes */ + +/* Tableaux pour le pricing */ +int NombreDeContraintesASurveiller; +int * IndexDansContrainteASurveiller; /* Dimensionne au nombre de contraintes */ +int * NumerosDesContraintesASurveiller; /* Dimensionne au nombre de contraintes */ +double * ValeurDeViolationDeBorne; /* Au carre. Dimensionne au nombre de contraintes */ + +/* Variables hors base */ +int NombreDeVariablesHorsBase; +int * NumerosDesVariablesHorsBase; /* Dimension: variables - nombre de contraintes */ +double * NBarreR; /* Dimension: variables */ +int * IndexDeLaVariableDansLesVariablesHorsBase; /* Dimension: nombre de variables */ + +/* Cas hyper creux */ +int NombreDeValeursNonNullesDeNBarreR; +int * NumVarNBarreRNonNul; /* Dimension: variables - nombre de contraintes */ +/* */ + +/* Donnees specifiques a l'algorithme dual */ +double SeuilDePivotDual; +int NombreDeVariablesATester; +char PremierPassage; +char FaireTriRapide; +int * NumeroDesVariableATester; +double * CBarreSurNBarreR; +double * CBarreSurNBarreRAvecTolerance; + +char TypeDeStockageDeErBMoinsUn; +int NbTermesNonNulsDeErBMoinsUn; +int * IndexTermesNonNulsDeErBMoinsUn; +double * ErBMoinsUn; + +double DeltaPiSurLaVariableEnBase; + +char CalculerCBarre; + +double SommeDesInfaisabilitesPrimales; +double Cout; /* Valeur du cout de la solution */ +double CoutMax; /* Valeur du cout au dessus de laquelle on arrete les calculs (utilite: branch and bound) */ +int UtiliserCoutMax; /* Vaut OUI_SPX si on desire faire le test par rapport a CoutMax, et NON_SPX si on ne veut + pas utiliser cette possibilite */ +double PartieFixeDuCout; /* Partie du cout qui est due aux variables dont la valeur est fixe. C'est calculé en + entree du solveur */ + +char LeSteepestEdgeEstInitilise; +char * InDualFramework; /* Pour la methode dual devex ou steepest edge: dimension nombre de variables */ +double * DualPoids ; /* Pour la methode dual devex ou steepest edge: dimension nombre de contraintes */ +double * Tau ; /* Pour la methode dual devex ou steepest edge: dimension nombre de contraintes */ + +char LesCoutsOntEteModifies; +char ModifCoutsAutorisee; +double CoefficientPourLaValeurDePerturbationDeCoutAPosteriori; +char * CorrectionDuale; + +/* Les zones memoire ci-dessous peuvent etre liberees des la fin de phase 1 de l'algorithme dual mais + on ne le fait pas afin de pouvoir utiliser ces zones comme tableaux temporaires si necessaire */ +char LaBaseEstDualeAdmissible; +int NbInfaisabilitesDualesALaPremiereIteration; +int NbInfaisabilitesDuales; +double SommeDesInfaisabilitesDuales; +double * V; /* Dimension nombre de contraintes */ +char * FaisabiliteDeLaVariable; /* Dimension nombre de variables */ + +/* Fin des zones memoires specifiques a la fin de phase 1 de l'algorithme dual */ + +/* Sauvegardes pour le branch and bound (utile pour le choix de la variable a instancier) */ +double * XSV; /* Dimension nombre de variables */ +double ValeurDuPivotMarkowitzSV; /* Le seuil Markowitz qui a servi a factoriser la derniere base + inversible */ +char * PositionDeLaVariableSV; /* Dimension nombre de variables */ +double * CBarreSV; /* Dimension nombre de variables */ +char * InDualFrameworkSV; /* Dimension nombre de variables */ +int * ContrainteDeLaVariableEnBaseSV; /* Dimension nombre de variables */ + +double * BBarreSV; /* Dimension nombre de contraintes */ +double * DualPoidsSV; /* Dimension nombre de contraintes */ +int * VariableEnBaseDeLaContrainteSV; /* Dimension nombre de contraintes */ + +int * CdebBaseSV; /* Dimension nombre de contraintes */ +int * NbTermesDesColonnesDeLaBaseSV; /* Dimension nombre de contraintes */ + +/*-------------------------------------------------------------------------*/ + +char UtiliserLaLuUpdate; +int FaireScalingLU; +char FactoriserLaBase; /* Indicateur positionne a OUI_SPX en cas de derive de la forme produit de l'inverse */ +char FaireChangementDeBase; + +/* Precaution pour la stabilite des calculs. Lorsqu'un probleme de stabilite des calculs est detecte et + qu'on demande une factorisation, on augmente le seuil du pivot de Markowitz. On le decremente + ensuite tant qu'on ne rencontre pas de probleme de stabilite numerique */ +char ProblemeDeStabiliteDeLaFactorisation; /* Vaut OUI_SPX ou NON_SPX */ +char FlagStabiliteDeLaFactorisation; /* Vaut 0 ou 1 */ +double ValeurDuPivotMarkowitz; + +/*-------------------------------------------------------------------------*/ + +/* Pour le pilotage de l'hyper creux */ +char TypeDeStockageDeABarreS; /* Vaut COMPACT_SPX ou VECTEUR_SPX */ +char TypeDeStockageDeNBarreR; /* Vaut COMPACT_SPX ou VECTEUR_SPX */ + +char TypeDeCreuxDeLaBase; /* Vaut BASE_HYPER_CREUSE ou BASE_CREUSE ou BASE_PLEINE */ + +char CalculErBMoinsUnEnHyperCreux; /* OUI_SPX au depart */ +char CalculErBMoinsEnHyperCreuxPossible; /* OUI_SPX au depart */ +int CountEchecsErBMoins; /* 0 au depart */ +int AvertissementsEchecsErBMoins; /* 0 au depart */ +int NbEchecsErBMoins; /* 0 au depart */ + +char CalculABarreSEnHyperCreux; /* OUI_SPX au depart */ +char CalculABarreSEnHyperCreuxPossible; /* OUI_SPX au depart */ +int CountEchecsABarreS; /* 0 au depart */ +int AvertissementsEchecsABarreS; /* 0 au depart */ +int NbEchecsABarreS; /* 0 au depart */ + +char CalculTauEnHyperCreux; /* OUI_SPX au depart */ +char CalculTauEnHyperCreuxPossible; /* OUI_SPX au depart */ +int CountEchecsTau; /* 0 au depart */ +int AvertissementsEchecsTau; /* 0 au depart */ +int NbEchecsTau; /* 0 au depart */ + +/*-------------------------------------------------------------------------*/ + +void * MatriceFactorisee; +int RangDeLaMatriceFactorisee; +int NombreDeFactorisationsDeBaseReduite; +int ForcerUtilisationDeLaBaseComplete; /* OUI_SPX ou NON_SPX */ +int NombreDeReactivationsDeLaBaseReduite; +int NombreDeBasesReduitesSuccessives; +int NombreDeBasesCompletesSuccessives; +int NombreDinfaisabilitesSiBaseReduite; +int NbEchecsReductionNombreDinfaisabilitesSiBaseReduite; +char InitBaseReduite; +char * PositionHorsBaseReduiteAutorisee; /* OUI_SPX ou NON_SPX */ + +char UtiliserLaBaseReduite; /* OUI_SPX ou NON_SPX */ +int IterationDeConstructionDeLaBaseReduite; +int ProchaineIterationDeReinitDesCouts; + +int * OrdreColonneDeLaBaseFactorisee; /* Dimension nombre de contraintes */ +int * ColonneDeLaBaseFactorisee; /* Dimension nombre de contraintes */ +int * OrdreLigneDeLaBaseFactorisee; /* Dimension nombre de contraintes */ +int * LigneDeLaBaseFactorisee; /* Dimension nombre de contraintes */ + +int * CdebProblemeReduit; /* Dimension nombre de variables */ +int * CNbTermProblemeReduit; /* Dimension nombre de variables */ +double * ValeurDesTermesDesColonnesDuProblemeReduit; +int * IndicesDeLigneDesTermesDuProblemeReduit; +int NbElementsAllouesPourLeProblemeReduit; + +double * AReduit; /* Dimension nombre de contraintes toujours a 0 quand on en a besoin */ +int * IndexAReduit; /* Dimension nombre de contraintes */ + +int * Marqueur; /* Dimension nombre de contraintes toujours a -1 quand on en a besoin */ + +/*-------------------------------------------------------------------------*/ +int AnomalieDetectee; +jmp_buf EnvSpx; +/*-------------------------------------------------------------------------*/ + +/* Pour les coupes d'intersection */ +DONNEES_POUR_COUPES_DINTERSECTION * DonneesPourCoupesDIntersection; +char CoupesDintersectionAllouees; /* Vaut OUI_SPX ou NON_SPX */ + +/* Pour les coupes coupes de Gomory */ +DONNEES_POUR_COUPES_DE_GOMORY * DonneesPourCoupesDeGomory; + +/*---------------------------------*/ +/* Pour la PNE */ +void * ProblemePneDeSpx; /* Mis a jour par la PNE */ + +char ExplorationRapideEnCours; /* OUI_SPX ou NON_SPX */ + +/*------------------------------------------*/ +/* Pour utiliser le tirage aleatoire de pne */ +double A1; + +/*------------------------------------------*/ + +} PROBLEME_SPX; + + +/*******************************************************************************************/ +# define DEFINITIONS_SPX_FAITES +# endif +# ifdef __cplusplus + } +# endif + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_definition_arguments.h b/src/ext/Sirius_Solver/simplexe/spx_definition_arguments.h new file mode 100644 index 0000000000..1838bbbcbf --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_definition_arguments.h @@ -0,0 +1,191 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef PROBLEME_SIMPLEXE_DEJA_DEFINI +/*******************************************************************************************/ +/* + Le passage des informations a la routine de resolution du simplexe se fait par un pointeur + a la structure C definie ci-apres. + + Le fichier spx_constantes_externes.h doit etre inclus dans le code de l'appelant. + Le fichier spx_definition_arguments.h doit etre inclus dans le code de l'appelant, + il contient la definition de la structure C exploitee par la fonction. + Apres avoir renseigne les champs, le module utilisateur appelle la fonction + SPX_Simplexe avec, pour argument d'appel: + - un pointeur ŕ un objet de type PROBLEME_SIMPLEXE: il permet de renseigner les donnees + du probleme ŕ résoudre + - un pointeur ŕ un objet de type PROBLEME_SPX. Lorsque la valeur de ce pointeur vaut NULL, + SPX_Simplexe alloue un nouvel objet de type PROBLEME_SPX sur lequel il travaillera. + Dans le cas contraire SPX_Simplexe travaillera sur l'objet de type PROBLEME_SPX passé + par l'appelant. + + SPX_Simplexe renvoie un pointeur ŕ un objet de type PROBLEME_SPX, ce pointeur + correspond ŕ l'objet sur lequel SPX_Simplexe vient de faire ses calculs. + + L'appelant peut de cette façon travailler sur plusieurs instances de problemes qu'il + souhaite faire resoudre par le simplexe. + + Exemple d'utilisation : + + PROBLEME_SIMPLEXE Mon_Probleme; <- definition d'une structure "Mon_Probleme" de type PROBLEME_SIMPLEXE + void * ProblemeSpx; <- Utiliser void * comme type de pointeur permet ŕ l'appelant d'ignorer la + composition de la structure PROBLEME_SPX, qu'il n'a d'ailleurs pas besoin + de connaitre. + ....... + ....... + Remplissage des champs de la structure + ....... + ....... + ....... + Appel de la fonction: + + ProblemeSpx = SPX_Simplexe( &Mon_Probleme , ProblemeSpx ); + +*/ + +typedef struct { + int Contexte; /* Contexte dans lequel le simplexe est utilise. Cet argument peut prendre 3 valeurs: + BRANCH_AND_BOUND_OU_CUT: le simplexe est appelé dans un contexte de Branch And Bound + ou de Branch And Cut + BRANCH_AND_BOUND_OU_CUT_NOEUD: le simplexe est appelé dans un contexte de Branch And Bound + ou de Branch And Cut mais on ne reinitialise pas le probleme + SIMPLEXE_SEUL: le simplexe est appelé hors d'un contexte de Branch and Bound ou de + Branch And Cut (dans ce cas, certaines sauvegardes particuličres ne sont + pas faites) */ + int NombreMaxDIterations; /* Si < 0 , le simplexe prendre sa valeur par defaut */ + double DureeMaxDuCalcul; /* Exprime en secondes (attention c'est du double). + Mettre une valeur negative si pas de duree max a prendre en compte */ + double * CoutLineaire; /* Couts lineaires */ + double * X; /* Vecteur des variables */ + double * Xmin; /* Bornes min des variables */ + double * Xmax; /* Bornes max des variables */ + int NombreDeVariables; /* Nombre de variables */ + int * TypeDeVariable; /* Indicateur du type de variable, il ne doit prendre que les suivantes + (voir le fichier spx_constantes_externes.h mais ne jamais utiliser les valeurs explicites + des constantes): + VARIABLE_FIXE , + VARIABLE_BORNEE_DES_DEUX_COTES , + VARIABLE_BORNEE_INFERIEUREMENT , + VARIABLE_BORNEE_SUPERIEUREMENT , + VARIABLE_NON_BORNEE + */ + /* La matrice des contraintes */ + int NombreDeContraintes; /* Nombre de contraintes */ + int * IndicesDebutDeLigne; /* Pointeur sur le debut de chaque ligne de la matrice des contraintes */ + int * NombreDeTermesDesLignes; /* Nombre de termes non nuls de chaque ligne */ + int * IndicesColonnes; /* Indice colonne des termes de la matrice des contraintes. + Attention, les termes de la ligne doivent etre ranges dans l'ordre + croissant des indices de colonnes */ + double * CoefficientsDeLaMatriceDesContraintes; /* Les termes de la matrice des contraintes */ + /* Le second membre */ + char * Sens; /* Sens de contrainte: '<' ou '>' ou '=' */ + double * SecondMembre; /* Valeurs de second membre */ + /* Choix de l'algorithme */ + int ChoixDeLAlgorithme; /* L'utilisateur doit mettre : (RQ seul le dual marche) + SPX_PRIMAL s'il veut utiliser l'algorithme primal + SPX_DUAL s'il veut utiliser l'algorithme dual */ + /* Guidage de l'algorithme */ + int TypeDePricing; /* Le pricing est l'étape du calcul dans laquelle on choisit la variable sortante + dans l'algorithme dual (ou la variale entrante dans l'algorithme primal). + Deux choix sont possibles: + * PRICING_DANTZIG: c'est la méthode basique, elle est rapide mais dans certains + cas conduit ŕ faire beaucoup d'itérations pour trouver l'optimum. + * PRICING_STEEPEST_EDGE: méthode élaborée (Forrest-Goldfarb), elle demande plus de + calculs mais permet de réduite significativement le nombre d'itérations. Il est + recommander de l'utiliser pour les problčmes difficiles. */ + int FaireDuScaling; /* Vaut OUI_SPX ou NON_SPX. Si l'utilisateur positionne la valeur a OUI_SPX, + le simplexe fait un scaling du probleme dčs le début de la résolution. + Le scaling a pour but d'améliorer le conditionnement du problčme. Il est + recommandé de l'utiliser lorsque les coefficients de la matrice des contraintes + sont trčs différents les un des autres (rapport > 100) */ + int StrategieAntiDegenerescence; /* Vaut AGRESSIF ou PEU_AGRESSIF. + * AGRESSIF: le controle est fait ŕ chaque iterations. + * PEU_AGRESSIF: le controle est fait moins souvent. + -> Choix recommandé: AGRESSIF + */ + /* En Entree ou en Sortie */ + int BaseDeDepartFournie; /* Vaut OUI_SPX ou NON_SPX */ + + int * PositionDeLaVariable; /* Pour chaque variable, sa position vis a vis de la base. Une variable peut etre de 4 type: + EN_BASE, HORS_BASE_SUR_BORNE_INF,HORS_BASE_SUR_BORNE_SUP,HORS_BASE_A_ZERO*/ + int NbVarDeBaseComplementaires; /* Nombre de variables basiques complementaires (c'est une valeur d'entree mais de sortie aussi) */ + int * ComplementDeLaBase; + + int ExistenceDUneSolution; /* En sortie, vaut : + OUI_SPX s'il y a une solution, + NON_SPX s'il n'y a pas de solution admissible + SPX_ERREUR_INTERNE si probleme a l'execution (saturation memoire par exemple), et + dans ce cas il n'y a pas de solution + SPX_MATRICE_DE_BASE_SINGULIERE si on n'a pas pu construire de matrice de base reguliere, + et dans ce cas il n'y a pas de solution + */ + int LibererMemoireALaFin; /* En Entree: + - Si OUI_SPX la memoire est liberee a la fin du simplexe + - Si NON_SPX la memoire n'est pas liberee a la fin du simplexe. Cette est utile si l'on + veut conserver temporairement les donnees du probleme pour calculer des coupes de Gomory + par exemple. Attention, l'appelant doit ensuite liberer le memoire par un appel + a "SPX_LibererProbleme" */ + double CoutMax; /* En entree: cette information n'est utilisee que si l'algorithme choisi est l'algorithme dual. + On sait qu'a chaque iteration de l'algorithme dual, le cout courant est un minorant du cout optimal. + Il est donc possible de comparer ce cout ŕ un Cout Max, seuil au dessus duquel on convient d'arreter les + calculs (l'algorithme sort alors avec le verdict "pas de solution"). + Quelle en est l'utilite (mais il peut y en avoir d'autres) ? + Dans un contexte de branch and bound, des que l'on dispose d'une solution entiere, toutes les resolutions de + probleme relaxé menant a un cout superieur a ce cout sont a rejeter. Donc, si l'on se rend compte au cours de + l'algorithme dual, que la resolution du probleme relaxe va mener a un cout trop grand il est inutile de + poursuivre les calculs. Ceci permet de gagner du temps de calcul. + + ATTENTION: comme l'algorithme dual peut etre utilisé en tant que solveur (c'est ŕ dire + --------- en dehors d'un contexte de branch and bound) ou bien pour resoudre un probleme dont on + de souhaite pas donner de Cout Max parce qu'on ne le connait pas, l'information "CoutMax" + n'est utilisee par l'algorithme dual que si l'indicateur "UtiliserCoutMax" (argument suivant) + est positionne a "OUI-SPX". */ + int UtiliserCoutMax; + /* Les coupes: uniquement dans un contexte BRANCH AND BOUND ET CUT */ + int NombreDeContraintesCoupes; + double * BCoupes; /* Valeurs de second membre */ + char * PositionDeLaVariableDEcartCoupes; + int * MdebCoupes; + int * NbTermCoupes; + int * NuvarCoupes; + double * ACoupes; + /* En sortie */ + double * CoutsMarginauxDesContraintes; /* Cout marginaux des contraintes (attention, il faut dimensionner ce tableau + a NombreDeContraintes + NombreDeContraintesCoupes */ + double * CoutsReduits; /* Couts reduits des variables hors-base, longueur nombre de variables passees + en entree du probleme. Contient la valeur 0 si la variable est basique */ + /* Traces */ + char AffichageDesTraces; /* Vaut OUI_SPX ou NON_SPX */ + +} PROBLEME_SIMPLEXE; + +/*******************************************************************************************/ +# define PROBLEME_SIMPLEXE_DEJA_DEFINI +# endif +# ifdef __cplusplus + } +# endif + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_calculer_nbarre.c b/src/ext/Sirius_Solver/simplexe/spx_dual_calculer_nbarre.c new file mode 100644 index 0000000000..05e5097690 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_calculer_nbarre.c @@ -0,0 +1,565 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de NBarre pour la variable sortante + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_fonctions.h" + +# define RANDOM_MIN 1.e-10 +# define RANDOM_MAX 1 /*0.5*/ /*1.e-7*/ + +# define COEFF_MULT_DE_LA_PERTURBATION 10. + +# define SEUIL_DE_BRUITAGE_FIXE NON_SPX +# define SEUIL_DE_BRUITAGE (10.*SEUIL_ADMISSIBILITE_DUALE_2) + +# define TENIR_COMPTE_DES_BORNES_POUR_LA_VALEUR_DE_BRUITAGE OUI_SPX +# define VARIATION_MAX_DU_COUT_SUR_CHANGEMENT_DE_BORNE_1 /*50*/ 100 +# define VARIATION_MIN_DU_COUT_SUR_CHANGEMENT_DE_BORNE_1 1 + +# define VARIATION_MAX_DU_COUT_SUR_CHANGEMENT_DE_BORNE_2 1 + +# define BORNE_AUXILAIRE 1000. + +# define BRUITAGE_SUR_VARIABLES_BORNEES_DES_DEUX_COTES OUI_SPX + +# define EPS_HARRIS_MAX SEUIL_ADMISSIBILITE_DUALE_2 /*(2*SEUIL_ADMISSIBILITE_DUALE_2)*/ + +/*----------------------------------------------------------------------------*/ +void SPX_TenterRestaurationCalculErBMoinsEnHyperCreux( PROBLEME_SPX * Spx ) +{ +int Cnt; double * ErBMoinsUn; int Count; + +if ( Spx->CountEchecsErBMoins == 0 ) { + if ( Spx->Iteration % CYCLE_TENTATIVE_HYPER_CREUX == 0 ) { + Spx->NbEchecsErBMoins = SEUIL_REUSSITE_CREUX; + Spx->CountEchecsErBMoins = SEUIL_REUSSITE_CREUX + 2; + } +} +if ( Spx->CountEchecsErBMoins == 0 ) return; + +Spx->CountEchecsErBMoins--; +/* On compte le nombre de termes non nuls du resultat */ +ErBMoinsUn = Spx->ErBMoinsUn; +Count = 0; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) if ( ErBMoinsUn[Cnt] != 0.0 ) Count++; +if ( Count < 0.1 * Spx->NombreDeContraintes ) Spx->NbEchecsErBMoins--; +if ( Spx->NbEchecsErBMoins <= 0 ) { + # if VERBOSE_SPX + printf("Remise en service de l'hyper creux pour le calcul de la ligne pivot, iteration %d\n",Spx->Iteration); + # endif + Spx->AvertissementsEchecsErBMoins = 0; + Spx->CountEchecsErBMoins = 0; + Spx->CalculErBMoinsUnEnHyperCreux = OUI_SPX; +} +else if ( Spx->CountEchecsErBMoins <= 0 ) { + Spx->CountEchecsErBMoins = 0; + if ( Spx->CalculErBMoinsUnEnHyperCreux == NON_SPX ) Spx->AvertissementsEchecsErBMoins++; + if ( Spx->AvertissementsEchecsErBMoins >= SEUIL_ABANDON_HYPER_CREUX ) { + # if VERBOSE_SPX + printf("Arret prolonge de l'hyper creux pour le calcul de la ligne pivot, iteration %d\n",Spx->Iteration); + # endif + Spx->CalculErBMoinsEnHyperCreuxPossible = NON_SPX; + } +} + +return; +} +/*----------------------------------------------------------------------------*/ + +void SPX_DualCalculerNBarreR( PROBLEME_SPX * Spx, char CalculDeCBarreSurNBarre, char * ControlerAdmissibiliteDuale ) +{ +int Var; double S; char PositionDeLaVariable_x; double X; int i; char * PositionDeLaVariable; +double * NBarreR; int SortSurXmaxOuSurXmin; double * C; double * CBarre; char CalculEnHyperCreux; +double * CBarreSurNBarreR; double * CBarreSurNBarreRAvecTolerance; int * NumeroDesVariableATester; +char * CorrectionDuale; char FaireTestDegenerescence; double NBarreR_x; int j; double SeuilDePivot; +double UnSurNBarreR; int iLimite; int * NumerosDesVariables; double EpsHarris; int NbDeg0; int NbDeg; +double MinAbsCBarreNonDeg; double Delta; char ToutModifier; int Iter; double SeuilModifCout; +double * SeuilDAmissibiliteDuale; double Alpha; double * Csv; int * CNbTerm; double Random; +double B1; double B2; char * TypeDeVariable; double * Xmax; double * Xmin; double Xmx; +double PerturbationMax; double EpsHarrisMax; + +Spx->AdmissibilitePossible = NON_SPX; +*ControlerAdmissibiliteDuale = NON_SPX; + +if ( Spx->TypeDeCreuxDeLaBase == BASE_HYPER_CREUSE && Spx->CalculErBMoinsUnEnHyperCreux == OUI_SPX && + Spx->FaireDuRaffinementIteratif <= 0 ) { + CalculEnHyperCreux = OUI_SPX; + Spx->TypeDeStockageDeErBMoinsUn = COMPACT_SPX; +} +else { + CalculEnHyperCreux = NON_SPX; + Spx->TypeDeStockageDeErBMoinsUn = VECTEUR_SPX; +} + +SPX_CalculerErBMoins1( Spx, CalculEnHyperCreux ); + +/* Si on est pas en hyper creux, on essaie d'y revenir */ +if ( Spx->CalculErBMoinsUnEnHyperCreux == NON_SPX ) { + if ( Spx->CalculErBMoinsEnHyperCreuxPossible == OUI_SPX ) { + SPX_TenterRestaurationCalculErBMoinsEnHyperCreux( Spx ); + } +} + +if ( Spx->TypeDeStockageDeErBMoinsUn == COMPACT_SPX ) { + SPX_DualCalculerNBarreRHyperCreux( Spx ); +} +else { + SPX_DualCalculerNBarreRStandard( Spx ); +} + +if ( CalculDeCBarreSurNBarre == NON_SPX ) return; + +SeuilDePivot = Spx->SeuilDePivotDual; + +PositionDeLaVariable = Spx->PositionDeLaVariable; +NBarreR = Spx->NBarreR; +SortSurXmaxOuSurXmin = Spx->SortSurXmaxOuSurXmin; + +C = Spx->C; +Csv = Spx->Csv; +CBarre = Spx->CBarre; + +CNbTerm = Spx->CNbTerm; + +CBarreSurNBarreR = Spx->CBarreSurNBarreR; +CBarreSurNBarreRAvecTolerance = Spx->CBarreSurNBarreRAvecTolerance; +NumeroDesVariableATester = Spx->NumeroDesVariableATester; + +CorrectionDuale = Spx->CorrectionDuale; + +FaireTestDegenerescence = NON_SPX; +if ( Spx->NbCyclesSansControleDeDegenerescence >= Spx->CycleDeControleDeDegenerescence ) { + Spx->NbCyclesSansControleDeDegenerescence = 0; + if ( Spx->ModifCoutsAutorisee == OUI_SPX ) FaireTestDegenerescence = OUI_SPX; +} +else { + Spx->NbCyclesSansControleDeDegenerescence++; +} + +/***************************** Preparation du test du ratio ***********************************/ +Iter = 1; + +SeuilDAmissibiliteDuale = Spx->SeuilDAmissibiliteDuale1; + +Spx->NombreDeVariablesATester = 0; + +j = 0; + +if ( Spx->TypeDeStockageDeNBarreR == VECTEUR_SPX ) { + iLimite = Spx->NombreDeVariablesHorsBase; + NumerosDesVariables = Spx->NumerosDesVariablesHorsBase; +} +else { + iLimite = Spx->NombreDeValeursNonNullesDeNBarreR; + NumerosDesVariables = Spx->NumVarNBarreRNonNul; +} + +TypeDeVariable = Spx->TypeDeVariable; + +/* Indicateurs utilises pour la degenerescence */ +NbDeg0 = 0; +NbDeg = 0; +MinAbsCBarreNonDeg = LINFINI_SPX; + +EpsHarrisMax = EPS_HARRIS_MAX; + +for ( i = 0 ; i < iLimite ; i++ ) { + + Var = NumerosDesVariables[i]; + if ( fabs( NBarreR[Var] ) < SeuilDePivot ) continue; + + NBarreR_x = NBarreR[Var]; + PositionDeLaVariable_x = PositionDeLaVariable[Var]; + /* Classement des CBarreSurNBarreR qui vont servir au choix de la variables + entrante dans l'algorithme dual. + + Si la variable sortante sort sur XMIN + ------------------------------------- + Cas 1 - la variable hors base est sur BORNE INF: + alors son CBarre est >= 0 + on est interesses que par les valeurs de NBarreR < 0 + le rapport CBarre / NBarreR est <= 0 + Cas 2 - la variable hors base est sur BORNE SUP: + alors son CBarre est <= 0 + on est interesses que par les valeurs de NBarreR > 0 + le rapport CBarre / NBarreR est <= 0 + Cas 3 - la variable hors base est sur HORS_BASE_A_ZERO (i.e. non bornée): + alors son CBarre est = 0 quel que soit le signe de NBarreR, + la variable devra entrer en base + + Si la variable sortante sort sur XMAX + ------------------------------------- + Cas 1 - la variable hors base est sur BORNE INF: + alors son CBarre est >= 0 + on est interesses que par les valeurs de NBarreR > 0 + les rapport CBarre / NBarreR est >= 0 + Cas 2 - la variable hors base est sur BORNE SUP: + alors son CBarre est <= 0 + on est interesses que par les valeurs de NBarreR < 0 + le rapport CBarre / NBarreR est >= 0 + Cas 3 - la variable hors base est sur HORS_BASE_A_ZERO (i.e. non bornée): + alors son CBarre est = 0 quel que soit le signe de NBarreR, + la variable devra entrer en base + */ + if ( SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + /* Pour les variables autres que non bornees on est interesses que par les rapports negatifs */ + if ( PositionDeLaVariable_x == HORS_BASE_SUR_BORNE_INF ) { + /* Si la variable est HORS_BASE_SUR_BORNE_INF et si NBarreR est positif, la variable ne + quittera pas la base */ + if ( NBarreR_x > 0.0 ) continue; + } + else if ( PositionDeLaVariable_x == HORS_BASE_SUR_BORNE_SUP ) { + /* Si la variable est HORS_BASE_SUR_BORNE_SUP et si NBarreR est negatif, la variable ne + quittera pas la base */ + if ( NBarreR_x < 0.0 ) continue; + } + /* Si on arrive la c'est que c'est une variable non bornee */ + } + else { /* La variable sort sur XMAX */ + /* Pour les variables autres que non bornees on est interesses que par les rapports positifs */ + if ( PositionDeLaVariable_x == HORS_BASE_SUR_BORNE_INF ) { + /* Si la variable est HORS_BASE_SUR_BORNE_INF et si NBarreR est negatif, la variable ne + quittera pas la base */ + if ( NBarreR_x < 0.0 ) continue; + } + else if ( PositionDeLaVariable_x == HORS_BASE_SUR_BORNE_SUP ) { + /* Si la variable est HORS_BASE_SUR_BORNE_INF et si NBarreR est positif, la variable ne + quittera pas la base */ + if ( NBarreR_x > 0.0 ) continue; + } + /* Si on arrive la c'est que c'est une variable non bornee */ + } + + /* Calcul de CBarre sur NBarreR */ + UnSurNBarreR = 1. / NBarreR_x; + X = CBarre[Var] * UnSurNBarreR; + + if ( COEFF_TOLERANCE_POUR_LE_TEST_DE_HARRIS * SeuilDAmissibiliteDuale[Var] > EpsHarrisMax ) EpsHarris = EpsHarrisMax * UnSurNBarreR; + else EpsHarris = COEFF_TOLERANCE_POUR_LE_TEST_DE_HARRIS * SeuilDAmissibiliteDuale[Var] * UnSurNBarreR; + + if ( PositionDeLaVariable_x == HORS_BASE_SUR_BORNE_INF ) { + /* Le cout reduit est positif (sauf s'il y a des infaisabilites duales) */ + if ( SortSurXmaxOuSurXmin != SORT_SUR_XMIN ) { + CBarreSurNBarreR [j] = X; + CBarreSurNBarreRAvecTolerance[j] = X + EpsHarris; + } + else { + CBarreSurNBarreR [j] = -X; + CBarreSurNBarreRAvecTolerance[j] = -(X + EpsHarris); + } + NumeroDesVariableATester[j] = i; + j++; + + if ( FaireTestDegenerescence == OUI_SPX ) { + # if SEUIL_DE_BRUITAGE_FIXE == OUI_SPX + SeuilModifCout = SEUIL_DE_BRUITAGE; + # else + SeuilModifCout = COEFF_SEUIL_POUR_MODIFICATION_DE_COUT * SeuilDAmissibiliteDuale[Var]; + # endif + + # if BRUITAGE_SUR_VARIABLES_BORNEES_DES_DEUX_COTES == OUI_SPX + if ( CBarre[Var] < SeuilModifCout ) { + NbDeg0++; + if ( CorrectionDuale[Var] != 0 ) NbDeg++; + } + else if ( fabs( CBarre[Var] ) < MinAbsCBarreNonDeg ) MinAbsCBarreNonDeg = fabs( CBarre[Var] ); + # else + if ( TypeDeVariable[Var] != BORNEE ) { + if ( CBarre[Var] < SeuilModifCout ) { + NbDeg0++; + if ( CorrectionDuale[Var] != 0 ) NbDeg++; + } + else if ( fabs( CBarre[Var] ) < MinAbsCBarreNonDeg ) MinAbsCBarreNonDeg = fabs( CBarre[Var] ); + } + # endif + + } + + } + else if ( PositionDeLaVariable_x == HORS_BASE_SUR_BORNE_SUP ) { + /* Le cout reduit est negatif (sauf s'il y a des infaisabilites duales) */ + if ( SortSurXmaxOuSurXmin != SORT_SUR_XMIN ) { + CBarreSurNBarreR [j] = X; + CBarreSurNBarreRAvecTolerance[j] = X - EpsHarris; + } + else { + CBarreSurNBarreR[j] = -X; + CBarreSurNBarreRAvecTolerance[j] = -(X - EpsHarris); + } + NumeroDesVariableATester[j] = i; + j++; + + if ( FaireTestDegenerescence == OUI_SPX ) { + # if SEUIL_DE_BRUITAGE_FIXE == OUI_SPX + SeuilModifCout = SEUIL_DE_BRUITAGE; + # else + SeuilModifCout = COEFF_SEUIL_POUR_MODIFICATION_DE_COUT * SeuilDAmissibiliteDuale[Var]; + # endif + + # if BRUITAGE_SUR_VARIABLES_BORNEES_DES_DEUX_COTES == OUI_SPX + if ( CBarre[Var] > -SeuilModifCout ) { + NbDeg0++; + if ( CorrectionDuale[Var] != 0 ) NbDeg++; + } + else if ( fabs( CBarre[Var] ) < MinAbsCBarreNonDeg ) MinAbsCBarreNonDeg = fabs( CBarre[Var] ); + # else + if ( TypeDeVariable[Var] != BORNEE ) { + if ( CBarre[Var] > -SeuilModifCout ) { + NbDeg0++; + if ( CorrectionDuale[Var] != 0 ) NbDeg++; + } + else if ( fabs( CBarre[Var] ) < MinAbsCBarreNonDeg ) MinAbsCBarreNonDeg = fabs( CBarre[Var] ); + } + # endif + + } + + } + else { + /* On est dans la cas d'une variable non bornee */ + /* Comme on fait entrer en priorite les variables non bornees, des qu'on en trouve une + on arrete */ + CBarreSurNBarreR [0] = 0.; + CBarreSurNBarreRAvecTolerance[0] = 0.; + NumeroDesVariableATester [0] = i; + Spx->NombreDeVariablesATester = 1; + return; + } + +} + +Spx->NombreDeVariablesATester = j; + +if ( FaireTestDegenerescence == NON_SPX ) return; + +/* S'il y a risque de degenerescence on modifie les couts */ + +ToutModifier = NON_SPX; +if ( NbDeg == 0 ) { + if ( NbDeg0 == 0 ) return; + else ToutModifier = OUI_SPX; +} + + +if ( NbDeg == 0 ) return; + +/* Rq PerturbationMax peut etre caclule une fois pour toutes */ +PerturbationMax = Spx->PerturbationMax; +if ( PerturbationMax > VARIATION_MAX_DU_COUT_SUR_CHANGEMENT_DE_BORNE_1 ) PerturbationMax = VARIATION_MAX_DU_COUT_SUR_CHANGEMENT_DE_BORNE_1; +else if ( PerturbationMax > VARIATION_MIN_DU_COUT_SUR_CHANGEMENT_DE_BORNE_1 ) PerturbationMax = VARIATION_MIN_DU_COUT_SUR_CHANGEMENT_DE_BORNE_1; + +TypeDeVariable = Spx->TypeDeVariable; +Xmax = Spx->Xmax; +Xmin = Spx->Xmin; + +Spx->LesCoutsOntEteModifies = OUI_SPX; + +S = Spx->CoefficientPourLaValeurDePerturbationDeCoutAPosteriori * COEFF_MULT_DE_LA_PERTURBATION * VALEUR_PERTURBATION_COUT_A_POSTERIORI; + +if ( ToutModifier == NON_SPX ) { + Delta = S / (double) NbDeg; + /* Plus grande des corrections inferieure a un seuil */ + if ( NbDeg * Delta > MinAbsCBarreNonDeg ) Delta = MinAbsCBarreNonDeg / NbDeg; + /* Correction pas trop petite quand-meme */ + if ( NbDeg * Delta < SEUIL_ADMISSIBILITE_DUALE_2 ) Delta = SEUIL_ADMISSIBILITE_DUALE_2 / NbDeg; +} +else { + Delta = S / (double) NbDeg0; + /* Plus grande des corrections inferieure a un seuil */ + if ( NbDeg0 * Delta > MinAbsCBarreNonDeg ) Delta = MinAbsCBarreNonDeg / NbDeg0; + /* Correction pas trop petite quand-meme */ + if ( NbDeg0 * Delta < SEUIL_ADMISSIBILITE_DUALE_2 ) Delta = SEUIL_ADMISSIBILITE_DUALE_2 / NbDeg0; +} + +S = Delta; +Spx->A1 = PNE_Rand( Spx->A1 ); /* Nombre aleatoire entre 0 et 1 */ +Random = RANDOM_MIN; +Random += Spx->A1 * ( RANDOM_MAX - RANDOM_MIN ); +Alpha = 1. + Random; + +/* Maintenant on modifie les couts */ +B1 = 0.1 * SEUIL_ADMISSIBILITE_DUALE_1; +B2 = 0.1 * SEUIL_ADMISSIBILITE_DUALE_1; + +for ( j = 0 ; j < Spx->NombreDeVariablesATester ; j++ ) { + + Var = NumerosDesVariables[NumeroDesVariableATester[j]]; + + # if BRUITAGE_SUR_VARIABLES_BORNEES_DES_DEUX_COTES == NON_SPX + if ( TypeDeVariable[Var] == BORNEE ) continue; + # endif + + # if SEUIL_DE_BRUITAGE_FIXE == OUI_SPX + SeuilModifCout = SEUIL_DE_BRUITAGE; + # else + SeuilModifCout = COEFF_SEUIL_POUR_MODIFICATION_DE_COUT * SeuilDAmissibiliteDuale[Var]; + # endif + + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + if ( CBarre[Var] < SeuilModifCout ) { + + if ( ToutModifier == NON_SPX ) { + if ( CorrectionDuale[Var] == 0 ) { + /* Rendre au minimum dual admissible */ + /* Si la correction demandee tend a revenir vers le cout initial on l'accepte afin retablir le cout initial */ + /* + if ( CBarre[Var] < 0 ) { + X = -CBarre[Var]; + X += B1 * Alpha; + if ( Csv[Var] > C[Var] ) { + if ( C[Var] + X > Csv[Var] ) X = Csv[Var] - C[Var]; + C[Var] += X; + CBarre[Var] += X; + } + } + */ + continue; + } + } + + /* Rend au minimum dual admissible sauf si la variable est bornee car il suffira de la changer de borne + pour la rendre dual admissible */ + if ( CBarre[Var] < 0 && TypeDeVariable[Var] != BORNEE ) { + X = -CBarre[Var]; + if ( X > S ) { + S = X; + /* Comme on arriverait sur 0 on repousse un peu plus */ + S += B2; + } + } + + # if TENIR_COMPTE_DES_BORNES_POUR_LA_VALEUR_DE_BRUITAGE == OUI_SPX + /* Si la variable est bornee on limite le bruitage */ + if ( TypeDeVariable[Var] == BORNEE ) Xmx = Xmax[Var]; + else Xmx = BORNE_AUXILAIRE; + if ( CorrectionDuale[Var] != 0 || 1 ) { + if ( S * Alpha * ( Xmx - Xmin[Var] ) > PerturbationMax ) { + S = PerturbationMax / ( Alpha * ( Xmx - Xmin[Var] ) ); + } + } + else if ( S * Alpha * ( Xmx - Xmin[Var] ) > VARIATION_MAX_DU_COUT_SUR_CHANGEMENT_DE_BORNE_2 ) { + S = VARIATION_MAX_DU_COUT_SUR_CHANGEMENT_DE_BORNE_2 / ( Alpha * ( Xmx - Xmin[Var] ) ); + } + # endif + + C[Var] += S * Alpha; + CBarre[Var] += S * Alpha; + + CorrectionDuale[Var] -= 1; + if ( CorrectionDuale[Var] <= 0 ) CorrectionDuale[Var] = 0; + S += Delta; + + X = CBarre[Var] / NBarreR[Var]; + + if ( COEFF_TOLERANCE_POUR_LE_TEST_DE_HARRIS * SeuilDAmissibiliteDuale[Var] > EpsHarrisMax ) EpsHarris = EpsHarrisMax / NBarreR[Var]; + else EpsHarris = COEFF_TOLERANCE_POUR_LE_TEST_DE_HARRIS * SeuilDAmissibiliteDuale[Var] / NBarreR[Var]; + + if ( SortSurXmaxOuSurXmin != SORT_SUR_XMIN ) { + CBarreSurNBarreR [j] = X; + CBarreSurNBarreRAvecTolerance[j] = X + EpsHarris; + } + else { + CBarreSurNBarreR [j] = -X; + CBarreSurNBarreRAvecTolerance[j] = -(X + EpsHarris); + } + } + } + else if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + if ( CBarre[Var] > -SeuilModifCout ) { + + if ( ToutModifier == NON_SPX ) { + if ( CorrectionDuale[Var] == 0 ) { + /* Rendre au minimum dual admissible */ + /* Si la correction demandee tend a revenir vers le cout initial on l'accepte afin retablir le cout initial */ + /* + if ( CBarre[Var] > 0 ) { + X = CBarre[Var]; + X += B1 * Alpha; + if ( Csv[Var] < C[Var] ) { + if ( C[Var] - X < Csv[Var] ) X = C[Var] - Csv[Var]; + C[Var] -= X; + CBarre[Var] -= X; + } + } + */ + continue; + } + } + + /* Rend au minimum dual admissible */ + if ( CBarre[Var] > 0 ) { + X = CBarre[Var]; + if ( X > S ) { + S = X; + /* Comme on arriverait sur 0 on repousse un peu plus */ + S += B2; + } + } + + # if TENIR_COMPTE_DES_BORNES_POUR_LA_VALEUR_DE_BRUITAGE == OUI_SPX + /* On limite le bruitage */ + if ( TypeDeVariable[Var] == BORNEE ) Xmx = Xmax[Var]; + else Xmx = BORNE_AUXILAIRE; + if ( CorrectionDuale[Var] != 0 || 1 ) { + if ( S * Alpha * ( Xmx - Xmin[Var] ) > PerturbationMax ) { + S = PerturbationMax / ( Alpha * ( Xmx - Xmin[Var] ) ); + } + } + else if ( S * Alpha * ( Xmx - Xmin[Var] ) > VARIATION_MAX_DU_COUT_SUR_CHANGEMENT_DE_BORNE_2 ) { + S = VARIATION_MAX_DU_COUT_SUR_CHANGEMENT_DE_BORNE_2 / ( Alpha * ( Xmx - Xmin[Var] ) ); + } + # endif + + C[Var] -= S * Alpha; + CBarre[Var] -= S * Alpha; + + CorrectionDuale[Var] -= 1; + if ( CorrectionDuale[Var] <= 0 ) CorrectionDuale[Var] = 0; + S += Delta; + + X = CBarre[Var] / NBarreR[Var]; + + if ( COEFF_TOLERANCE_POUR_LE_TEST_DE_HARRIS * SeuilDAmissibiliteDuale[Var] > EpsHarrisMax ) EpsHarris = EpsHarrisMax / NBarreR[Var]; + else EpsHarris = COEFF_TOLERANCE_POUR_LE_TEST_DE_HARRIS * SeuilDAmissibiliteDuale[Var] / NBarreR[Var]; + + if ( SortSurXmaxOuSurXmin != SORT_SUR_XMIN ) { + CBarreSurNBarreR [j] = X; + CBarreSurNBarreRAvecTolerance[j] = X - EpsHarris; + } + else { + CBarreSurNBarreR [j] = -X; + CBarreSurNBarreRAvecTolerance[j] = -(X - EpsHarris); + } + } + } +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_calculer_nbarre_hyper_creux.c b/src/ext/Sirius_Solver/simplexe/spx_dual_calculer_nbarre_hyper_creux.c new file mode 100644 index 0000000000..42c25e2518 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_calculer_nbarre_hyper_creux.c @@ -0,0 +1,193 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de NBarre pour la variable sortante dans le cas + hyper creux. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +# define POSITIF 1 +# define NEGATIF 2 +# define POSITIF_ET_NEGATIF 3 + +/*----------------------------------------------------------------------------*/ + +void SPX_DualCalculerNBarreRHyperCreux( PROBLEME_SPX * Spx ) +{ +int Var; int il; int ilMax; double X; int i; double * ErBMoinsUn; int Cnt; int * Indcol; +double * A; int j; int * T; char * PositionDeLaVariable; int * IndexTermesNonNulsDeErBMoinsUn; +int NbTermesNonNulsDeErBMoinsUn; int * NumVarNBarreRNonNul; int NombreDeValeursNonNullesDeNBarreR; +double * ACol; int * Cdeb; int * CNbTerm; int * NumeroDeContrainte; int * NumerosDesVariablesHorsBase; +double * NBarreR; double * Erb; int * Mdeb; int * NbTerm; int Seuil; int * NombreDeVariablesHorsBaseDeLaContrainte; +double * Xmin; double * Xmax; int jFin; int * IndicesDeLigne; int * LigneDeLaBaseFactorisee; + +ErBMoinsUn = Spx->ErBMoinsUn; +IndexTermesNonNulsDeErBMoinsUn = Spx->IndexTermesNonNulsDeErBMoinsUn; +NBarreR = Spx->NBarreR; +NbTermesNonNulsDeErBMoinsUn = Spx->NbTermesNonNulsDeErBMoinsUn; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) Seuil = Spx->RangDeLaMatriceFactorisee; +else Seuil = Spx->NombreDeContraintes; + +Seuil = Spx->NombreDeContraintes; /* On reste comme ca pour l'instant */ + +if ( NbTermesNonNulsDeErBMoinsUn < 0.3 * Seuil || Spx->UtiliserLaBaseReduite == OUI_SPX ) { /* Il semble qu'il vaut mieux toujours faire ca si base reduite */ + /* Cette methode pose des problemes de precision car il y a plus d'allers + retour en memoire or a chaque aller retour il y a un ecretage */ + Spx->TypeDeStockageDeNBarreR = ADRESSAGE_INDIRECT_SPX; + + Mdeb = Spx->Mdeb; + NbTerm = Spx->NbTerm; + Indcol = Spx->Indcol; + A = Spx->A; + + PositionDeLaVariable = Spx->PositionDeLaVariable; + + NombreDeVariablesHorsBaseDeLaContrainte = Spx->NombreDeVariablesHorsBaseDeLaContrainte; + + T = Spx->T; + NumVarNBarreRNonNul = Spx->NumVarNBarreRNonNul; + NombreDeValeursNonNullesDeNBarreR = 0; + + /* Il faut supprimer les variables pour lesquelles Xmin = Xmax */ + Xmin = Spx->Xmin; + Xmax = Spx->Xmax; + + for ( j = 0 ; j < NbTermesNonNulsDeErBMoinsUn ; j++ ) { + Cnt = IndexTermesNonNulsDeErBMoinsUn[j]; + if ( NombreDeVariablesHorsBaseDeLaContrainte[Cnt] == 0 ) continue; + X = ErBMoinsUn[j]; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( PositionDeLaVariable[Var] != EN_BASE_LIBRE ) { + if ( T[Var] == 1 ) { + NBarreR[Var] += X * A[il]; + } + else { + T[Var] = 1; + NBarreR[Var] = X * A[il]; + NumVarNBarreRNonNul[NombreDeValeursNonNullesDeNBarreR] = Var; + NombreDeValeursNonNullesDeNBarreR++; + } + } + il++; + } + } + + for ( i = 0 ; i < NombreDeValeursNonNullesDeNBarreR ; i++ ) T[NumVarNBarreRNonNul[i]] = -1; + + /* Il faut supprimer les variables pour lesquelles Xmin = Xmax */ + if ( Spx->PresenceDeVariablesDeBornesIdentiques == OUI_SPX ) { + j = 0; + jFin = NombreDeValeursNonNullesDeNBarreR - 1; + while ( j <= jFin ) { + Var = NumVarNBarreRNonNul[j]; + if ( Xmin[Var] == Xmax[Var] ) { + NumVarNBarreRNonNul[j] = NumVarNBarreRNonNul[jFin]; + jFin--; + continue; + } + j++; + } + NombreDeValeursNonNullesDeNBarreR = jFin + 1; + } + + Spx->NombreDeValeursNonNullesDeNBarreR = NombreDeValeursNonNullesDeNBarreR; + +} +else { + Spx->TypeDeStockageDeNBarreR = ADRESSAGE_INDIRECT_SPX /*VECTEUR_SPX*/; + NumVarNBarreRNonNul = Spx->NumVarNBarreRNonNul; + NombreDeValeursNonNullesDeNBarreR = 0; + + /* Expand de ErBMoinsUn */ + Erb = Spx->Bs; /* On peut aussi utiliser Spx->AReduit */ + + for ( j = 0 ; j < NbTermesNonNulsDeErBMoinsUn ; j++ ) Erb[IndexTermesNonNulsDeErBMoinsUn[j]] = ErBMoinsUn[j]; + ErBMoinsUn = Erb; + + NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; + + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + Cdeb = Spx->CdebProblemeReduit; + CNbTerm = Spx->CNbTermProblemeReduit; + IndicesDeLigne = Spx->IndicesDeLigneDesTermesDuProblemeReduit; + ACol = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; + LigneDeLaBaseFactorisee = Spx->LigneDeLaBaseFactorisee; + for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + X = 0.0; + while ( il < ilMax ) { + X += ErBMoinsUn[LigneDeLaBaseFactorisee[IndicesDeLigne[il]]] * ACol[il]; + il++; + } + if ( X != 0.0 ) { + NBarreR[Var] = X; + NumVarNBarreRNonNul[NombreDeValeursNonNullesDeNBarreR] = Var; + NombreDeValeursNonNullesDeNBarreR++; + } + } + } + else { + Cdeb = Spx->Cdeb; + CNbTerm = Spx->CNbTerm; + NumeroDeContrainte = Spx->NumeroDeContrainte; + ACol = Spx->ACol; + + for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + X = 0.0; + while ( il < ilMax ) { + X += ErBMoinsUn[NumeroDeContrainte[il]] * ACol[il]; + il++; + } + if ( X != 0.0 ) { + NBarreR[Var] = X; + NumVarNBarreRNonNul[NombreDeValeursNonNullesDeNBarreR] = Var; + NombreDeValeursNonNullesDeNBarreR++; + } + } + } + + Spx->NombreDeValeursNonNullesDeNBarreR = NombreDeValeursNonNullesDeNBarreR; + for ( j = 0 ; j < NbTermesNonNulsDeErBMoinsUn ; j++ ) Erb[IndexTermesNonNulsDeErBMoinsUn[j]] = 0.0; + +} + +return; +} + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_calculer_nbarrer_standard.c b/src/ext/Sirius_Solver/simplexe/spx_dual_calculer_nbarrer_standard.c new file mode 100644 index 0000000000..8d15f4709f --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_calculer_nbarrer_standard.c @@ -0,0 +1,140 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de NBarre pour la variable sortante + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define COEFF_VARIABLES 0.75 + +/*----------------------------------------------------------------------------*/ + +void SPX_DualCalculerNBarreRStandard( PROBLEME_SPX * Spx ) + +{ +int il; int ilMax; double X; int i; int NombreDeContraintes; int * NumerosDesVariablesHorsBase; +double * ErBMoinsUn; double * NBarreR; int * Cdeb; int * CNbTerm; double * ACol; +int * NumeroDeContrainte; int Cnt; int * Mdeb; int * NbTerm; int * Indcol; double * A; +int NombreDeVariablesHorsBase; int NombreDeVariables; char Methode; int Var; +char * PositionDeLaVariable; int * NombreDeVariablesHorsBaseDeLaContrainte; +int * IndicesDeLigne; int * LigneDeLaBaseFactorisee; + +NombreDeContraintes = Spx->NombreDeContraintes; +ErBMoinsUn = Spx->ErBMoinsUn; +NombreDeVariables = Spx->NombreDeVariables; +NombreDeVariablesHorsBase = Spx->NombreDeVariablesHorsBase; +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +NBarreR = Spx->NBarreR; + +Spx->TypeDeStockageDeNBarreR = VECTEUR_SPX; + +/* Si ErBMoinsUn est tres creux il vaut mieux la methode 1, sinon la methode 2 permet de faire + un calcul plus precis */ + +if ( Spx->InverseProbablementDense == OUI_SPX ) { + Methode = 2; +} +else { + if ( NombreDeContraintes < (int) ceil ( COEFF_VARIABLES * NombreDeVariables ) ) { + Methode = 1; + } + else { + Methode = 2; + } +} + +/* 2 methodes de calcul des produits scalaires */ + +if ( Methode == 1 ) { + /*memset( (char *) NBarreR , 0 , NombreDeVariables * sizeof( double ) );*/ + for ( i = 0 ; i < NombreDeVariables ; i++ ) NBarreR[i] = 0; + + Mdeb = Spx->Mdeb; + NbTerm = Spx->NbTerm; + + PositionDeLaVariable = Spx->PositionDeLaVariable; + + NombreDeVariablesHorsBaseDeLaContrainte = Spx->NombreDeVariablesHorsBaseDeLaContrainte; + + Indcol = Spx->Indcol; + A = Spx->A; + for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( ErBMoinsUn[Cnt] == 0.0 ) continue; + if ( NombreDeVariablesHorsBaseDeLaContrainte[Cnt] == 0 ) continue; + X = ErBMoinsUn[Cnt]; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( PositionDeLaVariable[Indcol[il]] != EN_BASE_LIBRE ) { + NBarreR[Indcol[il]] += X * A[il]; + } + il++; + } + } +} +else { + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + Cdeb = Spx->CdebProblemeReduit; + CNbTerm = Spx->CNbTermProblemeReduit; + IndicesDeLigne = Spx->IndicesDeLigneDesTermesDuProblemeReduit; + ACol = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; + LigneDeLaBaseFactorisee = Spx->LigneDeLaBaseFactorisee; + for ( i = 0 ; i < NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + X = 0; + while ( il < ilMax ) { + X += ErBMoinsUn[LigneDeLaBaseFactorisee[IndicesDeLigne[il]]] * ACol[il]; + il++; + } + NBarreR[Var] = X; + } + } + else { + Cdeb = Spx->Cdeb; + CNbTerm = Spx->CNbTerm; + NumeroDeContrainte = Spx->NumeroDeContrainte; + ACol = Spx->ACol; + + for ( i = 0 ; i < NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + X = 0; + while ( il < ilMax ) { + X += ErBMoinsUn[NumeroDeContrainte[il]] * ACol[il]; + il++; + } + NBarreR[Var] = X; + } + } +} + +return; +} + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_choix_variable_entrante.c b/src/ext/Sirius_Solver/simplexe/spx_dual_choix_variable_entrante.c new file mode 100644 index 0000000000..e7c26adb97 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_choix_variable_entrante.c @@ -0,0 +1,395 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Algorithme dual: choix de la variable qui entre en base. + + Rappel: dans l'alogrithme dual le test du ratio sert a determiner + la variable hors base qui entre en base alors que dans + l'algorithme primal c'est l'inverse + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define TRI_RAPPORTS_AVEC_HARRIS 1 +# define TRI_RAPPORTS_SANS_HARRIS 0 + +# define CYCLE_POUR_CHOIX_DU_TRI_RAPIDE 10 +# define SEUIL_DECLENCHEMENT_TRI_RAPIDE 10 +# define SEUIL_2_POUR_TRI_RAPIDE 100 + +int SPX_PartitionTriRapide( PROBLEME_SPX * , double * , int , int , char ); +void SPX_TriRapide( PROBLEME_SPX * , double * , int , int , char ); +void SPX_DualTestDuRatioChoixDeLaVariableEntrante( PROBLEME_SPX * , int * ); + +/*----------------------------------------------------------------------------*/ +int SPX_PartitionTriRapide( PROBLEME_SPX * Spx , double * Tableau , int Deb, int Fin , char TypeDeTri ) +{ +int Compt; double Pivot; int i; double X; /*char Ch;*/ int iV; int DebPlus1; +/*double * CBarreSurNBarreRAvecTolerance ; */ double * CBarreSurNBarreR ; +int * NumeroDesVariableATester ; + +TypeDeTri = 0; /* Pour ne pas avoir de warning a la compilation */ + +DebPlus1 = Deb + 1; +Compt = Deb; +Pivot = Tableau[Deb]; + +/* Tri sans tolerance de Harris */ +CBarreSurNBarreR = Spx->CBarreSurNBarreR; +NumeroDesVariableATester = Spx->NumeroDesVariableATester; +for ( i = DebPlus1 ; i <= Fin ; i++) { + if ( Tableau[i] < Pivot) { + Compt++; + /* On inverse le tableau sans tolerances */ + X = CBarreSurNBarreR[Compt]; + CBarreSurNBarreR[Compt] = CBarreSurNBarreR[i]; + CBarreSurNBarreR[i] = X; + iV = NumeroDesVariableATester[Compt]; + NumeroDesVariableATester[Compt] = NumeroDesVariableATester[i]; + NumeroDesVariableATester[i] = iV; + + } +} +X = CBarreSurNBarreR[Compt]; +CBarreSurNBarreR[Compt] = CBarreSurNBarreR[Deb]; +CBarreSurNBarreR[Deb] = X; +iV = NumeroDesVariableATester[Compt]; +NumeroDesVariableATester[Compt] = NumeroDesVariableATester[Deb]; +NumeroDesVariableATester[Deb] = iV; +return(Compt); +} +/*----------------------------------------------------------------------------*/ +void SPX_TriRapide( PROBLEME_SPX * Spx , double * Tableau , int Debut , int Fin , char TypeDeTri ) +{ +int Pivot; +if ( Debut < Fin ) { + Pivot = SPX_PartitionTriRapide( Spx , Tableau , Debut , Fin , TypeDeTri ); + SPX_TriRapide( Spx , Tableau , Debut , Pivot-1 , TypeDeTri ); + SPX_TriRapide( Spx , Tableau , Pivot+1 , Fin , TypeDeTri ); +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_DualTestDuRatioChoixDeLaVariableEntrante( PROBLEME_SPX * Spx , int * i0Harris ) +{ +int j; int i; double SeuilHarris; double NBarreRMx; int Var; +int iChoisi ; double * CBarreSurNBarreRAvecTolerance; +int * NumeroDesVariableATester; double * CBarreSurNBarreR; double * NBarreR; +int NombreDeVariablesATester; int * NumerosDesVariables; int jChoisi; + +NombreDeVariablesATester = Spx->NombreDeVariablesATester; +CBarreSurNBarreRAvecTolerance = Spx->CBarreSurNBarreRAvecTolerance; +NumeroDesVariableATester = Spx->NumeroDesVariableATester; +CBarreSurNBarreR = Spx->CBarreSurNBarreR; +NBarreR = Spx->NBarreR; + +if ( Spx->TypeDeStockageDeNBarreR == VECTEUR_SPX ) NumerosDesVariables = Spx->NumerosDesVariablesHorsBase; +else NumerosDesVariables = Spx->NumVarNBarreRNonNul; + +if ( Spx->FaireTriRapide == OUI_SPX ) { + if ( *i0Harris >= NombreDeVariablesATester ) return; + SeuilHarris = LINFINI_SPX; + while ( *i0Harris < NombreDeVariablesATester ) { + /* Car il peut y avoir des FlagVariableATester a 0 des le depart */ + if ( /*FlagVariableATester[*i0Harris] == 1*/ 1 ) { + SeuilHarris = CBarreSurNBarreRAvecTolerance[*i0Harris]; + *i0Harris = *i0Harris + 1; /* Attention c'est pas bon car c'est pas forcement celle la qu'on va choisir */ + break; + } + else *i0Harris = *i0Harris + 1; + } + iChoisi = -1; + NBarreRMx = -LINFINI_SPX; + for ( j = 0 ; j < NombreDeVariablesATester ; j++ ) { + i = NumeroDesVariableATester[j]; + if ( i < 0 ) continue; + Var = NumerosDesVariables[i]; + if ( CBarreSurNBarreR[j] > SeuilHarris ) break; + if ( fabs( NBarreR[Var] ) > NBarreRMx ) { + NBarreRMx = fabs( NBarreR[Var] ); + iChoisi = j; + Spx->VariableEntrante = Var; + } + } + if ( iChoisi >= 0 ) NumeroDesVariableATester[iChoisi] = -1; + return; +} + +/* On a pas fait de tri prealable */ + +SeuilHarris = LINFINI_SPX; +jChoisi = -1; +for ( j = 0 ; j < NombreDeVariablesATester ; j++ ) { + if ( CBarreSurNBarreRAvecTolerance[j] < SeuilHarris ) { + SeuilHarris = CBarreSurNBarreRAvecTolerance[j]; + jChoisi = j; + } +} + +if ( jChoisi < 0 ) return; + +jChoisi = -1; +NBarreRMx = -LINFINI_SPX; + +for ( j = 0 ; j < NombreDeVariablesATester ; j++ ) { + if ( CBarreSurNBarreR[j] > SeuilHarris ) continue; + i = NumeroDesVariableATester[j]; + if ( i < 0 ) continue; + Var = NumerosDesVariables[i]; + if ( fabs( NBarreR[Var] ) > NBarreRMx ) { + NBarreRMx = fabs( NBarreR[Var] ); + jChoisi = j; + Spx->VariableEntrante = Var; + } +} + +/* Si on n'a pas fait de tri, les indices des tableaux CBarreSurNBarreR et CBarreSurNBarreRAvecTolerance + sont les memes */ +if ( jChoisi >= 0 ) { + CBarreSurNBarreR [jChoisi] = CBarreSurNBarreR[NombreDeVariablesATester-1]; + CBarreSurNBarreRAvecTolerance[jChoisi] = CBarreSurNBarreRAvecTolerance[NombreDeVariablesATester-1]; + NumeroDesVariableATester [jChoisi] = NumeroDesVariableATester[NombreDeVariablesATester-1]; + Spx->NombreDeVariablesATester--; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_DualTestDuRatio( PROBLEME_SPX * Spx , int * i0Harris ) +{ +Spx->DeltaPiSurLaVariableEnBase = LINFINI_SPX; +Spx->VariableEntrante = -1; +Spx->ChangementDeBase = NON_SPX; + +if ( Spx->PremierPassage == OUI_SPX ) { + + if ( Spx->NbItBoundFlip >= CYCLE_POUR_CHOIX_DU_TRI_RAPIDE ) { + if ( Spx->BuffNbBoundFlip / Spx->NbItBoundFlip > SEUIL_DECLENCHEMENT_TRI_RAPIDE ) Spx->FaireTriRapide = OUI_SPX; + else Spx->FaireTriRapide = NON_SPX; + Spx->BuffNbBoundFlip = 0; + Spx->NbItBoundFlip = 0; + } + + if ( Spx->NbBoundFlipIterationPrecedente > SEUIL_2_POUR_TRI_RAPIDE ) { + Spx->FaireTriRapide = OUI_SPX; + } + + /* Inhibition pour l'instant 4/2/2011 car erreur sur flag var a tester */ + Spx->FaireTriRapide = NON_SPX; + + if ( Spx->FaireTriRapide == OUI_SPX ) { + SPX_TriRapide( Spx , Spx->CBarreSurNBarreR , 0 , Spx->NombreDeVariablesATester - 1 , TRI_RAPPORTS_SANS_HARRIS ); + } + + Spx->PremierPassage = NON_SPX; +} + +SPX_DualTestDuRatioChoixDeLaVariableEntrante( Spx , i0Harris ); + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_DualChoixDeLaVariableEntrante( PROBLEME_SPX * Spx ) +{ +int IndexCntBase; int DerniereVariableEntrante; double BBarreDeCntBase; int NbTermesBoundFlip; double SeuilBound; +double DeltaXSurLaVariableHorsBase; int i0Harris; double * Xmax; double * NBarreR; char * PositionDeLaVariable; +char * TypeDeVariable ; double * Xmin; int * CNbTerm; char * StatutBorneSupCourante; double XsVariableSortante; +double XiVariableSortante; + +double tk; double tk_1; double zk_1; double zk; double * CBarre; + +tk_1 = 0.0; +zk_1 = 0.0; +CBarre = Spx->CBarre; + +StatutBorneSupCourante = Spx->StatutBorneSupCourante; + +i0Harris = 0; + +Spx->PremierPassage = OUI_SPX; + +Spx->NbBoundFlip = 0; +Spx->FaireMiseAJourDeBBarre = OUI_SPX; + +SeuilBound = 0.1; + +DerniereVariableEntrante = -1; +NbTermesBoundFlip = 0; +DeltaXSurLaVariableHorsBase = 0.0; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + IndexCntBase = Spx->OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]]; +} +else { + IndexCntBase = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; +} + +BBarreDeCntBase = Spx->BBarre[IndexCntBase]; + +Xmax = Spx->Xmax; +Xmin = Spx->Xmin; +NBarreR = Spx->NBarreR; +PositionDeLaVariable = Spx->PositionDeLaVariable; +TypeDeVariable = Spx->TypeDeVariable; + +CNbTerm = Spx->CNbTerm; + +XsVariableSortante = Xmax[Spx->VariableSortante]; +XiVariableSortante = Xmin[Spx->VariableSortante]; + +Spx->ChangementDeBase = NON_SPX; + +while ( Spx->ChangementDeBase == NON_SPX ) { + + SPX_DualTestDuRatio( Spx , &i0Harris ); + if ( Spx->VariableEntrante < 0 ) break; /* Optimum non borne */ + + /* Calcul du deplacement primal sur la variable entrante */ + Spx->ChangementDeBase = OUI_SPX; + + if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + Spx->DeltaXSurLaVariableHorsBase = BBarreDeCntBase / NBarreR[Spx->VariableEntrante]; + } + else { /* SORT_SUR_XMAX */ + Spx->DeltaXSurLaVariableHorsBase = ( BBarreDeCntBase - XsVariableSortante ) / NBarreR[Spx->VariableEntrante]; + } + + tk = CBarre[Spx->VariableEntrante] / NBarreR[Spx->VariableEntrante]; + if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) zk = zk_1 + ( (tk - tk_1 ) * BBarreDeCntBase ); + else zk = zk_1 + ( (tk - tk_1 ) * ( BBarreDeCntBase - XsVariableSortante ) ); + zk_1 = zk; + tk_1 = tk; + + if ( fabs( Spx->DeltaXSurLaVariableHorsBase ) > Xmax[Spx->VariableEntrante] && + TypeDeVariable[Spx->VariableEntrante] == BORNEE ) { + /* + printf(" *** Iteration %d simple changement de borne sur la variable %d position %d DeltaXSurLaVariableHorsBase %lf Xmax %lf\n", + Spx->Iteration,Spx->VariableEntrante,(int) Spx->PositionDeLaVariable[Spx->VariableEntrante] ,Spx->DeltaXSurLaVariableHorsBase, + Spx->Xmax[Spx->VariableEntrante]); + */ + /* Simple changement de borne */ + if ( PositionDeLaVariable[Spx->VariableEntrante] == HORS_BASE_SUR_BORNE_SUP ) { + # ifdef UTILISER_BORNES_AUXILIAIRES + if ( StatutBorneSupCourante[Spx->VariableEntrante] != BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) { + # endif + Spx->ChangementDeBase = NON_SPX; + /* Attention, il faut revenir en arriere sur le changement de position si on ne fait pas le changement + de base */ + DeltaXSurLaVariableHorsBase = -Xmax[Spx->VariableEntrante]; + Spx->BoundFlip[Spx->NbBoundFlip] = -( Spx->VariableEntrante + 1 ); + Spx->NbBoundFlip++; + if ( Spx->NbBoundFlip == MAX_BOUND_FLIP ) { + Spx->FaireMiseAJourDeBBarre = NON_SPX; + } + NbTermesBoundFlip+= CNbTerm[Spx->VariableEntrante]; + if ( NbTermesBoundFlip > (int) ( SeuilBound * Spx->NombreDeContraintes ) ) Spx->FaireMiseAJourDeBBarre = NON_SPX; + # ifdef UTILISER_BORNES_AUXILIAIRES + } + # endif + } + else { /* HORS_BASE_SUR_BORNE_INF */ + # ifdef UTILISER_BORNES_AUXILIAIRES + /* Si la variable a une borne sup non native, on ne fait pas de bound flip puisque cela signifie qu'elle n'a pas + de borne sup native */ + if ( StatutBorneSupCourante[Spx->VariableEntrante] == BORNE_NATIVE ) { + # endif + Spx->ChangementDeBase = NON_SPX; + /* Attention, il faut revenir en arriere sur le changement de position si on ne fait pas le changement + de base */ + DeltaXSurLaVariableHorsBase = Xmax[Spx->VariableEntrante]; + Spx->BoundFlip[Spx->NbBoundFlip] = Spx->VariableEntrante + 1; + Spx->NbBoundFlip++; + if ( Spx->NbBoundFlip == MAX_BOUND_FLIP ) { + Spx->FaireMiseAJourDeBBarre = NON_SPX; + } + NbTermesBoundFlip+= CNbTerm[Spx->VariableEntrante]; + if ( NbTermesBoundFlip > (int) ( SeuilBound * Spx->NombreDeContraintes ) ) Spx->FaireMiseAJourDeBBarre = NON_SPX; + # ifdef UTILISER_BORNES_AUXILIAIRES + } + # endif + } + } + /* Dans le cas du bound flip, mise a jour de BBarre pour la variable sortante */ + if ( Spx->ChangementDeBase == NON_SPX ) { + BBarreDeCntBase-= DeltaXSurLaVariableHorsBase * NBarreR[Spx->VariableEntrante]; + if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + if ( BBarreDeCntBase >= XiVariableSortante ) { + /* On arrete les bound flip */ + Spx->ChangementDeBase = OUI_SPX; + /* Comme on fait effectivement le changement de base il ne faut pas faire le bound flip + sur cette variable */ + Spx->NbBoundFlip--; + break; + } + } + else { /* La variable sort sur Xmax */ + if ( BBarreDeCntBase <= XsVariableSortante ) { + /* On arrete les bound flip */ + Spx->ChangementDeBase = OUI_SPX; + /* Comme on fait effectivement le changement de base il ne faut pas faire le bound flip + sur cette variable */ + Spx->NbBoundFlip--; + break; + } + } + } + + DerniereVariableEntrante = Spx->VariableEntrante; + +} + +if ( Spx->VariableEntrante < 0 ) { + /* Par securite on fait toujours le changement car la mise a jour de BBarre est entachee d'erreur + et pourrait conduire a un diagnotic premature d'absence de solution */ + Spx->VariableEntrante = DerniereVariableEntrante; + + if ( Spx->VariableEntrante >= 0 ) { + /* La derniere variable avait fait un bound flip => pour les besoins de la mise a jour de BBarre on + initialise son deplacement a 0 */ + Spx->NbBoundFlip--; + } +} + +if ( Spx->VariableEntrante >= 0 ) { + + Spx->ChangementDeBase = OUI_SPX; + + Spx->BuffNbBoundFlip+= Spx->NbBoundFlip; + Spx->NbItBoundFlip++; + + Spx->NbBoundFlipIterationPrecedente = Spx->NbBoundFlip; + +} + +return; +} + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_choix_variable_sortante.c b/src/ext/Sirius_Solver/simplexe/spx_dual_choix_variable_sortante.c new file mode 100644 index 0000000000..2b370e79b3 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_choix_variable_sortante.c @@ -0,0 +1,224 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Algorithme dual: choix de la variable sortante. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +# include "pne_define.h" +# include "pne_fonctions.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_DualChoixDeLaVariableSortante( PROBLEME_SPX * Spx ) +{ +double PlusGrandeViolation; int ContrainteDeLaVariableSortante; int i; int iSor; +double * ValeurDeViolationDeBorne; double PlusPetiteViolation; int Index; +int * NumerosDesContraintesASurveiller; int Count; int CountMax; +# if POIDS_DANS_VALEUR_DE_VIOLATION == NON_SPX + double * DualPoids; +# endif + +/* RechercherLaVariableSortante */ + +Spx->VariableSortante = -1; +Spx->SortSurXmaxOuSurXmin = SORT_PAS; + +ContrainteDeLaVariableSortante = -1; + +iSor = -1; +PlusGrandeViolation = -1.; +PlusPetiteViolation = LINFINI_SPX; +ValeurDeViolationDeBorne = Spx->ValeurDeViolationDeBorne; +NumerosDesContraintesASurveiller = Spx->NumerosDesContraintesASurveiller; + +# if POIDS_DANS_VALEUR_DE_VIOLATION == NON_SPX + DualPoids = Spx->DualPoids; +# endif + +Count = 0; + +Spx->A1 = PNE_Rand( Spx->A1 ); +CountMax = (int) ceil(Spx->A1 * Spx->NombreDeContraintesASurveiller); +if ( CountMax < 5 ) CountMax = 5; + +for ( i = 0 ; i < Spx->NombreDeContraintesASurveiller ; i++ ) { + # if POIDS_DANS_VALEUR_DE_VIOLATION == OUI_SPX + if ( ValeurDeViolationDeBorne[i] > PlusGrandeViolation + SEUIL_DE_VIOLATION_DE_BORNE ) { + iSor = i; + PlusGrandeViolation = ValeurDeViolationDeBorne[i]; + if ( Count > CountMax ) break; + Count++; + } + # else + Index = NumerosDesContraintesASurveiller[i]; + if ( ValeurDeViolationDeBorne[i] / DualPoids[Index] > PlusGrandeViolation + SEUIL_DE_VIOLATION_DE_BORNE ) { + iSor = i; + PlusGrandeViolation = ValeurDeViolationDeBorne[i] / DualPoids[Index]; + if ( Count > CountMax ) break; + Count++; + } + # endif +} + +if ( iSor >= 0 ) { + Index = NumerosDesContraintesASurveiller[iSor]; + if ( Spx->BBarre[Index] < 0.0 ) Spx->SortSurXmaxOuSurXmin = SORT_SUR_XMIN; + else Spx->SortSurXmaxOuSurXmin = SORT_SUR_XMAX; + + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + Spx->VariableSortante = Spx->VariableEnBaseDeLaContrainte[Spx->ColonneDeLaBaseFactorisee[Index]]; + } + else { + Spx->VariableSortante = Spx->VariableEnBaseDeLaContrainte[Index]; + } + +} + +/* Traces */ +#if VERBOSE_SPX +if ( Spx->LaBaseDeDepartEstFournie == OUI_SPX && Spx->StrongBranchingEnCours != OUI_SPX ) { + if ( Spx->VariableSortante >= 0 ) { + printf(" *** Iteration %d\n",Spx->Iteration); + if ( Spx->OrigineDeLaVariable[Spx->VariableSortante] == NATIVE ) { + printf(" -> Algorithme dual variable de base sortante %d de type NATIVE ",Spx->VariableSortante); + } + else if ( Spx->OrigineDeLaVariable[Spx->VariableSortante] == ECART ) { + printf(" -> Algorithme dual variable de base sortante %d de type ECART ",Spx->VariableSortante); + } + else if ( Spx->OrigineDeLaVariable[Spx->VariableSortante] == BASIQUE_ARTIFICIELLE ) { + printf(" -> Algorithme dual variable de base sortante %d de type BASIQUE_ARTIFICIELLE ",Spx->VariableSortante); + } + else { + printf("Bug dans l algorithme dual, sous-programme SPX_DualChoixDeLaVariableKiKitLaBase\n"); + exit(0); + } + if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) printf("elle SORT_SUR_XMIN "); + else if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMAX ) printf("elle SORT_SUR_XMAX "); + else { + printf("Bug dans l algorithme dual, sous-programme SPX_DualChoixDeLaVariableKiKitLaBase\n"); + exit(0); + } + } +} +#endif +/* Fin traces */ + +return; + +} + +/*----------------------------------------------------------------------------*/ + +void SPX_DualChoixDeLaVariableSortanteAuHasard( PROBLEME_SPX * Spx ) +{ +int Cnt; int Var; double Xx; int Nombre; int NombreDeVariablesCandidates; int * VariableCandidate; +int * VariableEnBaseDeLaContrainte; double * X; double * BBarre; double * Xmax; char * TypeDeVariable; +int i; int UtiliserLaBaseReduite; int RangDeLaMatriceFactorisee; int Index; +int * OrdreColonneDeLaBaseFactorisee; double * SeuilDeViolationDeBorne; + +UtiliserLaBaseReduite = Spx->UtiliserLaBaseReduite; +OrdreColonneDeLaBaseFactorisee = Spx->OrdreColonneDeLaBaseFactorisee; +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; + +VariableCandidate = (int *) (Spx->Bs); /* On peut aussi utiliser Spx->AReduit */ + +Spx->VariableSortante = -1; +NombreDeVariablesCandidates = 0; + +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +X = Spx->X; +Xmax = Spx->Xmax; +BBarre = Spx->BBarre; +TypeDeVariable = Spx->TypeDeVariable; + +SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + + Var = VariableEnBaseDeLaContrainte[Cnt]; + + if ( UtiliserLaBaseReduite == OUI_SPX ) { + Index = OrdreColonneDeLaBaseFactorisee[Cnt]; + if ( Index >= RangDeLaMatriceFactorisee ) continue; + } + else { + Index = Cnt; + } + + X[Var] = BBarre[Index]; + if ( TypeDeVariable[Var] == NON_BORNEE ) continue; /* Une variable libre ne sort pas de la base */ + /* La variable est donc bornee ( des 2 cotes ou seulement bornee inferieurement ) */ + if ( BBarre[Index] < -SeuilDeViolationDeBorne[Var] ) { + VariableCandidate[NombreDeVariablesCandidates] = Var; + NombreDeVariablesCandidates++; + continue; + } + else if ( TypeDeVariable[Var] == BORNEE ) { + if ( BBarre[Index] > Xmax[Var] + SeuilDeViolationDeBorne[Var] ) { + VariableCandidate[NombreDeVariablesCandidates] = Var; + NombreDeVariablesCandidates++; + } + } +} + +if ( NombreDeVariablesCandidates <= 0 ) goto FinSelectionAuHasard; + +/* On tire un nombre au hasard compris entre 0 et NombreDeVariablesCandidates - 1 */ +# if UTILISER_PNE_RAND == OUI_SPX + Spx->A1 = PNE_Rand( Spx->A1 ); + Xx = Spx->A1 * (NombreDeVariablesCandidates - 1); +# else + Xx = rand() * Spx->UnSurRAND_MAX * (NombreDeVariablesCandidates - 1); +# endif + +Nombre = (int) Xx; +if ( Nombre >= NombreDeVariablesCandidates - 1 ) Nombre = NombreDeVariablesCandidates - 1; + +Spx->VariableSortante = VariableCandidate[Nombre]; + +if ( UtiliserLaBaseReduite == OUI_SPX ) { + Index = OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]]; +} +else { + Index = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; +} + +if ( BBarre[Index] < 0.0 ) Spx->SortSurXmaxOuSurXmin = SORT_SUR_XMIN; +else Spx->SortSurXmaxOuSurXmin = SORT_SUR_XMAX; + +FinSelectionAuHasard: + +for ( i = 0 ; i < NombreDeVariablesCandidates ; i++ ) VariableCandidate[i] = 0; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_comparer_abarre_et_nbarre.c b/src/ext/Sirius_Solver/simplexe/spx_dual_comparer_abarre_et_nbarre.c new file mode 100644 index 0000000000..675c5b298b --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_comparer_abarre_et_nbarre.c @@ -0,0 +1,160 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Comparaison de ABarreS et NBarreR. Si l'ecart est trop + grand, on refactorise la base et eventuellement on ne + fait pas le changement de base. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define NOMBRE_DE_FOIS_SCALING_SI_DISCORANCE 0 + +# define CYCLE_POUR_LA_COMPARAISON_ENTRE_ABarreS_ET_NBarreR 10 + +/*----------------------------------------------------------------------------*/ + +void SPX_DualComparerABarreSEtNBarreR( PROBLEME_SPX * Spx ) + +{ +double Seuil; double X; double ABarreS; double NBarreR; int VariableEntrante; int VariableSortante; + +if ( Spx->Iteration % CYCLE_POUR_LA_COMPARAISON_ENTRE_ABarreS_ET_NBarreR != 0 ) return; + +VariableEntrante = Spx->VariableEntrante; +VariableSortante = Spx->VariableSortante; + +ABarreS = Spx->ABarreSCntBase; + +NBarreR = Spx->NBarreR[VariableEntrante]; + +/* En cas de discordance de Spx->ABarreSCntBase et de Spx->NBarreR[Spx->VariableEntrante] alors il + faut s'empresser de refactoriser (et en principe il ne faudrait pas faire le changement de base) */ +if ( fabs( ABarreS ) < 0.1 * VALEUR_DE_PIVOT_ACCEPTABLE ) { + #if VERBOSE_SPX + printf("Iteration %d factorisation de la base demandee car Spx->ABarreS trop faible on fait pas le changement de base\n",Spx->Iteration); + printf(" Spx->ABarreS= %e \n",ABarreS); + #endif + + Spx->FaireScalingLU = NOMBRE_DE_FOIS_SCALING_SI_DISCORANCE; + Spx->FlagStabiliteDeLaFactorisation = 1; + Spx->FactoriserLaBase = OUI_SPX; + Spx->ChoixDeVariableSortanteAuHasard = OUI_SPX; + Spx->NombreMaxDeChoixAuHasard = 2; + Spx->NombreDeChoixFaitsAuHasard = 0; + Spx->FaireDuRaffinementIteratif = 5; + SPX_FactoriserLaBase( Spx ); + Spx->FaireChangementDeBase = NON_SPX; + + /* On augmente le seuil dual de pivotage */ + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + + #if VERBOSE_SPX + printf("Iteration %d nombre de choix de pivot au hasard a faire parmi les choix acceptables: %d\n", + Spx->Iteration,Spx->NombreMaxDeChoixAuHasard); + #endif + return; +} + +if ( ABarreS * NBarreR < 0. ) { + #if VERBOSE_SPX + printf("Iteration %d factorisation de la base demandee car Spx->ABarreS et Spx->NBarreR de signes differents\n",Spx->Iteration); + printf(" Spx->ABarreS= %e NBarreR= %e\n",ABarreS,NBarreR); + #endif + + Spx->FaireScalingLU = NOMBRE_DE_FOIS_SCALING_SI_DISCORANCE; + Spx->FlagStabiliteDeLaFactorisation = 1; + Spx->FactoriserLaBase = OUI_SPX; + Spx->ChoixDeVariableSortanteAuHasard = OUI_SPX; + Spx->NombreMaxDeChoixAuHasard = 1; + Spx->NombreDeChoixFaitsAuHasard = 0; + Spx->FaireDuRaffinementIteratif = 5; + SPX_FactoriserLaBase( Spx ); + Spx->FaireChangementDeBase = NON_SPX; + + /* On augmente le seuil dual de pivotage */ + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + + #if VERBOSE_SPX + printf("Iteration %d nombre de choix de pivot au hasard a faire parmi les choix acceptables: %d\n", + Spx->Iteration,Spx->NombreMaxDeChoixAuHasard); + #endif + + + return; +} + +if ( fabs( ABarreS ) < 0.5 * VALEUR_DE_PIVOT_ACCEPTABLE ) { + #if VERBOSE_SPX + printf("Iteration %d factorisation de la base demandee car Spx->ABarreS trop faible mais on fait le changement de base\n",Spx->Iteration); + printf(" Spx->ABarreS= %e NBarreR= %e\n",ABarreS,NBarreR ); + #endif + + Spx->FaireDuRaffinementIteratif = 5; + Spx->FlagStabiliteDeLaFactorisation = 1; + Spx->FactoriserLaBase = OUI_SPX; + + /* On augmente le seuil dual de pivotage */ + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + + return; +} + + +/* +Seuil = 1.e-4 * fabs ( NBarreR ); +if ( Seuil < 1.e-6 ) Seuil = 1.e-6; +else if ( Seuil > 0.1 ) Seuil = 0.1; +X = fabs( ABarreS - NBarreR ); +if ( X > Seuil && X > 1.e-4 ) { +*/ + +Seuil = 1.e-3; +X = fabs( ABarreS - NBarreR ) / ( 1. + fabs( NBarreR ) ); +if ( X > Seuil ) { + #if VERBOSE_SPX + printf("Iteration %d factorisation de la base demandee car Spx->ABarreS trop different de Spx->NBarreR\n",Spx->Iteration); + printf(" Spx->ABarreS= %e NBarreR= %e\n",ABarreS,NBarreR ); + #endif + + if ( Spx->NombreDeChangementsDeBase < 10 ) { + /* Si ca se produit dans les premieres iterations apres une factorisation */ + Spx->FlagStabiliteDeLaFactorisation = 1; + } + Spx->FactoriserLaBase = OUI_SPX; + /* Ancienne strategie */ + /*Spx->FaireLeChangementDeBase = NON_SPX;*/ + /* Le changement de base risque de ne pas etre fiable */ + if ( X < 0.01 * fabs ( NBarreR ) ) Spx->FaireChangementDeBase = OUI_SPX; + else Spx->FaireChangementDeBase = NON_SPX; + + /* On augmente le seuil dual de pivotage */ + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + + return; +} + +return; + +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_confirmer_dual_non_borne.c b/src/ext/Sirius_Solver/simplexe/spx_dual_confirmer_dual_non_borne.c new file mode 100644 index 0000000000..c51896c57a --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_confirmer_dual_non_borne.c @@ -0,0 +1,280 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Confirmation dual non borne (i.e. pas de solution) + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +# define VERBOSE_SPX 0 + +/*----------------------------------------------------------------------------*/ + +void SPX_DualConfirmerDualNonBorne( PROBLEME_SPX * Spx ) + +{ +double NBarreR; double X; /* char PositionDeLaVariable; */ double MinRapport; double CBarreTPlus; +double CBarreTMoins; double NBarreRTPlus; double NBarreRTMoins; double S; double SeuilDePivot; +double Violation; int CntChoix; int Cnt; int j; double * ErBMoinsUn; double * Erb; /* int Var; int il ; int ilMax; */ +char NBarreRInitialise; double Seuil ; int Index; + +# if PRICING_AVEC_VIOLATIONS_STRICTES == OUI_SPX + int IndexMax; int Var; int YaDesBornesViolees; double ValBBarre; double * Xmax; double * SeuilDeViolationDeBorne; + int * VariableEnBaseDeLaContrainte; int * ColonneDeLaBaseFactorisee; char * TypeDeVariable; double * BBarre; +# endif + +Spx->AdmissibilitePossible = NON_SPX; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + Index = Spx->OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]]; +} +else { + Index = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; +} + +/* Si la variable sortante viole trop ses bornes, on ne cherche pas plus loin */ +if ( Spx->BBarre[Index] < Spx->Xmin[Spx->VariableSortante] ) { + Violation = Spx->Xmin[Spx->VariableSortante] - Spx->BBarre[Index]; +} +else Violation = Spx->BBarre[Index] - Spx->Xmax[Spx->VariableSortante]; + +if ( fabs( Violation ) > SEUIL_MAX_DE_VIOLATION_DE_BORNE ) { + #if VERBOSE_SPX + printf("Violation trop importante %e on confirme le dual non borne, poids %e seuil de violation %e SeuilDePivotDual %e\n",Violation, + Spx->DualPoids[Index],Spx->SeuilDeViolationDeBorne[Spx->VariableSortante],Spx->SeuilDePivotDual); + #endif + return; +} + + +# if PRICING_AVEC_VIOLATIONS_STRICTES == OUI_SPX + Xmax = Spx->Xmax; + SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; + VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + ColonneDeLaBaseFactorisee = Spx->ColonneDeLaBaseFactorisee; + TypeDeVariable = Spx->TypeDeVariable; + BBarre = Spx->BBarre; + + /* Si on travaille avec une gestion des tolerance nulles pour la liste des variables en base a controler, on verifie les valeurs + par rapport aux tolerance. Si elles sont toutes respectees alors on a une solution admissible optimale */ + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) IndexMax = Spx->RangDeLaMatriceFactorisee; + else IndexMax = Spx->NombreDeContraintes; + YaDesBornesViolees = NON_SPX; + for ( Index = 0 ; Index < IndexMax ; Index++ ) { + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + Var = VariableEnBaseDeLaContrainte[ColonneDeLaBaseFactorisee[Index]]; + } + else { + Var = VariableEnBaseDeLaContrainte[Index]; + } + if ( TypeDeVariable[Var] == NON_BORNEE ) continue; + + ValBBarre = BBarre[Index]; + if ( ValBBarre < -SeuilDeViolationDeBorne[Var] ) { + YaDesBornesViolees = OUI_SPX; + break; + } + if ( TypeDeVariable[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( ValBBarre > Xmax[Var] + SeuilDeViolationDeBorne[Var] ) { + YaDesBornesViolees = OUI_SPX; + break; + } + } + } + + if ( YaDesBornesViolees == NON_SPX ) { + Spx->AdmissibilitePossible = OUI_SPX; + return; + } +# endif + +SeuilDePivot = VALEUR_DE_PIVOT_ACCEPTABLE; +NBarreRInitialise = NON_SPX; +NBarreR = 1; /* Pour ne pas avoir de warning a la compilation */ + +#if VERBOSE_SPX + printf("Recherche des variables entrantes TPlus et TMoins pour confirmer le dual non borne\n"); fflush(stdout); +#endif + +Erb = NULL; +if ( Spx->TypeDeStockageDeErBMoinsUn != COMPACT_SPX ) { + ErBMoinsUn = Spx->ErBMoinsUn; +} +else { + Erb = Spx->Bs; /* On peut aussi utiliser Spx->AReduit */ + for ( j = 0 ; j < Spx->NbTermesNonNulsDeErBMoinsUn ; j++ ) { + Erb[Spx->IndexTermesNonNulsDeErBMoinsUn[j]] = Spx->ErBMoinsUn[j]; + } + ErBMoinsUn = Erb; +} + +/* Norme infinie */ +for ( S = -1., Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + if ( fabs( ErBMoinsUn[Cnt] ) > S ) S = fabs( ErBMoinsUn[Cnt] ); +} +S = 1. / S; + +/* Le vecteur dual */ +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) Spx->Pi[Cnt] = -ErBMoinsUn[Cnt] * S; + +/* Si la seule variable qui peut sortir est une variable t alors on est bien non admissible */ +MinRapport = LINFINI_SPX; +CntChoix = -1; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + CBarreTPlus = 1. - Spx->Pi[Cnt]; + CBarreTMoins = 1. + Spx->Pi[Cnt]; + if ( CBarreTPlus < 0. || CBarreTMoins < 0. ) { + printf("Iteration %d CBarreTPlus %lf CBarreTMoins %lf Cnt %d\n",Spx->Iteration,CBarreTPlus,CBarreTMoins,Cnt); + } + NBarreRTPlus = ErBMoinsUn[Cnt]; + NBarreRTMoins = -ErBMoinsUn[Cnt]; + if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + /* Si le produit CBarre * NBarreR est négatif la variable peut rentre en base */ + if ( fabs( NBarreRTPlus ) >= SeuilDePivot ) { + X = CBarreTPlus / NBarreRTPlus; + if ( X < 0. && fabs( X ) < MinRapport ) { + /*printf("Contrainte %d la variable TPlus peut entrer en base, CBarreTPlus %lf NBarreRTPlus %lf\n",Cnt,CBarreTPlus,NBarreRTPlus);*/ + MinRapport = fabs( X ); + NBarreR = NBarreRTPlus; + NBarreRInitialise = OUI_SPX; + CntChoix = Cnt; + } + } + if ( fabs( NBarreRTMoins ) >= SeuilDePivot ) { + X = CBarreTMoins / NBarreRTMoins; + if ( X < 0. && fabs( X ) < MinRapport ) { + /*printf("Contrainte %d la variable TMoins peut entrer en base, CBarreTMoins %lf NBarreRTMoins %lf\n",Cnt,CBarreTMoins,NBarreRTMoins);*/ + MinRapport = fabs( X ); + NBarreR = NBarreRTMoins; + NBarreRInitialise = OUI_SPX; + CntChoix = Cnt; + } + } + } + else if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMAX ) { + /* Si le produit CBarre * NBarreR est positif la variable peut rentre en base */ + if ( fabs( NBarreRTPlus ) >= SeuilDePivot ) { + X = CBarreTPlus / NBarreRTPlus; + if ( X > 0. && X < MinRapport ) { + /*printf("Contrainte %d la variable TPlus peut entrer en base, CBarreTPlus %lf NBarreRTPlus %lf\n",Cnt,CBarreTPlus,NBarreRTPlus);*/ + MinRapport = X; + NBarreR = NBarreRTPlus; + NBarreRInitialise = OUI_SPX; + CntChoix = Cnt; + } + } + if ( fabs( NBarreRTMoins ) >= SeuilDePivot ) { + X = CBarreTMoins / NBarreRTMoins; + if ( X > 0. && X < MinRapport ) { + /*printf("Contrainte %d la variable TMoins peut entrer en base, CBarreTMoins %lf NBarreRTMoins %lf\n",Cnt,CBarreTMoins,NBarreRTMoins);*/ + MinRapport = X; + NBarreR = NBarreRTMoins; + NBarreRInitialise = OUI_SPX; + CntChoix = Cnt; + } + } + } +} + +if ( NBarreRInitialise == OUI_SPX && CntChoix >= 0 ) { + if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + Spx->DeltaXSurLaVariableHorsBase = Spx->BBarre[Index] / NBarreR; + } + else { /* SORT_SUR_XMAX */ + Spx->DeltaXSurLaVariableHorsBase = ( Spx->BBarre[Index] - Spx->Xmax[Spx->VariableSortante] ) / NBarreR; + } + + /* Les variables t representent des variables d'ecart i.e. des possibilites de violation des contraintes */ + /* + Seuil = SEUIL_DE_VIOLATION_DE_BORNE_NON_NATIVE * Spx->ScaleB[CntChoix]; + if ( Seuil < SEUIL_MIN_DE_VIOLATION_DE_BORNE_NON_NATIVE ) Seuil = SEUIL_MIN_DE_VIOLATION_DE_BORNE_NON_NATIVE; + else if ( Seuil > SEUIL_MAX_DE_VIOLATION_DE_BORNE_NON_NATIVE ) Seuil = SEUIL_MAX_DE_VIOLATION_DE_BORNE_NON_NATIVE; + */ + + Seuil = SEUIL_DADMISSIBILITE * Spx->ScaleB[CntChoix]; + if ( Seuil < 0.01 * SEUIL_DADMISSIBILITE ) Seuil = 0.01 * SEUIL_DADMISSIBILITE; + else if ( Seuil > 10 * SEUIL_DADMISSIBILITE ) Seuil = 10 * SEUIL_DADMISSIBILITE; + + #if VERBOSE_SPX + printf("Type de sortie %d Delta X a faire sur T %15.10lf Seuil %e\n",Spx->SortSurXmaxOuSurXmin,Spx->DeltaXSurLaVariableHorsBase, + Seuil); + #endif + + if ( fabs( Spx->DeltaXSurLaVariableHorsBase ) < Seuil ) { + Spx->AdmissibilitePossible = OUI_SPX; + #if VERBOSE_SPX + printf("Rectification du diagnostique: admissibilite possible\n"); + printf("Iteration %d DeltaXSurLaVariableHorsBase %e SeuilDeViolationDeBorne %e SEUIL_DE_VIOLATION_DE_BORNE %e\n", + Spx->Iteration, + Spx->DeltaXSurLaVariableHorsBase, + Spx->SeuilDeViolationDeBorne[Spx->VariableSortante], + SEUIL_DE_VIOLATION_DE_BORNE ); + printf(" Variable sortante: Xmin %e X %e Xmax %e\n", + Spx->Xmin[Spx->VariableSortante], + Spx->BBarre[Index], + Spx->Xmax[Spx->VariableSortante] ); + #endif + } + else { + #if VERBOSE_SPX + printf("On confirme le dual non borne\n"); + printf("Iteration %d DeltaXSurLaVariableHorsBase %e SeuilDeViolationDeBorne %e SEUIL_DE_VIOLATION_DE_BORNE %e\n", + Spx->Iteration, + Spx->DeltaXSurLaVariableHorsBase, + Spx->SeuilDeViolationDeBorne[Spx->VariableSortante], + SEUIL_DE_VIOLATION_DE_BORNE ); + printf(" Variable sortante: Xmin %e X %e Xmax %e\n", + Spx->Xmin[Spx->VariableSortante], + Spx->BBarre[Index], + Spx->Xmax[Spx->VariableSortante] ); + #endif + } +} +else { + if ( fabs( Violation ) > SEUIL_DE_VIOLATION_DE_BORNE ) { + #if VERBOSE_SPX + printf("On confirme le dual non borne NBarreRInitialise %d CntChoix %d\n",NBarreRInitialise,CntChoix); + #endif + } + else { + #if VERBOSE_SPX + printf("Rectification du diagnostique: admissibilite possible\n"); + #endif + Spx->AdmissibilitePossible = OUI_SPX; + } +} + +/* Raz eventuelle du vecteur ayant servi pour Erb */ +if ( Spx->TypeDeStockageDeErBMoinsUn == COMPACT_SPX && Erb != NULL ) { + for ( j = 0 ; j < Spx->NbTermesNonNulsDeErBMoinsUn ; j++ ) Erb[Spx->IndexTermesNonNulsDeErBMoinsUn[j]] = 0.0; +} + +return; +} + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_construire_base_initiale.c b/src/ext/Sirius_Solver/simplexe/spx_dual_construire_base_initiale.c new file mode 100644 index 0000000000..f7ab5f0557 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_construire_base_initiale.c @@ -0,0 +1,119 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + FONCTION: Construction de la base dans le cas ou la base de depart + est fournie + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_DualConstruireLaBaseInitiale( PROBLEME_SPX * Spx, + int NbVar_E, + int * PositionDeLaVariable_E, + int NbVarDeBaseComplementaires_E, + int * ComplementDeLaBase_E, + char * TypeDeContrainte_E ) +{ +int Cnt; int Cnt_E ; int j ; int Var_E; int VarSimplexe; int il; int VarEcart; + +if ( Spx->LaBaseDeDepartEstFournie == NON_SPX ) { + printf(" Bug dans SPX_DualConstruireLaBaseInitiale, la base initiale doit etre fournie\n"); + exit(0); +} + +/* Cas ou la base est fournie */ +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) Spx->VariableEnBaseDeLaContrainte[Cnt] = -1; + +/* Complement de base */ +for ( Var_E = 0 ; Var_E < NbVarDeBaseComplementaires_E ; Var_E++ ) { + Cnt_E = ComplementDeLaBase_E[Var_E]; + Cnt = Spx->CorrespondanceCntEntreeCntSimplexe[Cnt_E]; + if ( TypeDeContrainte_E[Cnt_E] == '=' ) { + /* Si le type de la contrainte est = on cree la variable */ + if ( Cnt >= 0 ) SPX_DualCreerVariableDeBase( Spx , Cnt ); + } + else { + /* Si la contrainte est de type inegalite, on peut utiliser la variable d'ecart */ + if ( Cnt >= 0 ) { + /* A ce stade lŕ, la contrainte a déja été mise sous forme standard: la variable + d'ecart a été créee */ + il = Spx->Mdeb[Cnt] + Spx->NbTerm[Cnt] - 1; + VarEcart = Spx->Indcol[il]; + Spx->PositionDeLaVariable [VarEcart] = EN_BASE_LIBRE; + Spx->ContrainteDeLaVariableEnBase[VarEcart] = Cnt; + Spx->VariableEnBaseDeLaContrainte[Cnt] = VarEcart; + } + } +} + +/* Pour les contraintes restantes */ +for ( j = 0 , Var_E = 0 ; Var_E < NbVar_E ; Var_E++ ) { + if ( PositionDeLaVariable_E[Var_E] != EN_BASE ) continue; + VarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe[Var_E]; + if ( VarSimplexe < 0 ) continue; + Spx->PositionDeLaVariable[VarSimplexe] = EN_BASE_LIBRE; + while ( Spx->VariableEnBaseDeLaContrainte[j] != - 1 ) j++; + Spx->ContrainteDeLaVariableEnBase[VarSimplexe] = j; + Spx->VariableEnBaseDeLaContrainte[j] = VarSimplexe; + j++; +} + +return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_controle_des_bornes_auxiliaires.c b/src/ext/Sirius_Solver/simplexe/spx_dual_controle_des_bornes_auxiliaires.c new file mode 100644 index 0000000000..71d10d9f30 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_controle_des_bornes_auxiliaires.c @@ -0,0 +1,156 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Controle des bornes auxiliaires apres convergence. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# include "pne_define.h" + +# define COEFF_MULTIPLICATEUR 2.0 + +/*----------------------------------------------------------------------------*/ + +# ifdef UTILISER_BORNES_AUXILIAIRES + +/*----------------------------------------------------------------------------*/ + +void SPX_DualRepositionnerLesBornes( PROBLEME_SPX * Spx, char * Changements ) +{ +int Var; char ChangementDeBornes; char * StatutBorneSupCourante; char InfaisabiliteDuale; +char * PositionDeLaVariable; char * TypeDeVariable; double * Xmax; double * Xmin; + +InfaisabiliteDuale = NON_SPX; +ChangementDeBornes = NON_SPX; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +TypeDeVariable = Spx->TypeDeVariable; +Xmax = Spx->Xmax; +Xmin = Spx->Xmin; +PositionDeLaVariable = Spx->PositionDeLaVariable; +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( StatutBorneSupCourante[Var] == BORNE_NATIVE ) continue; + Xmax[Var] *= COEFF_MULTIPLICATEUR; + #if VERBOSE_SPX + printf("Augmentation de borne pour la variable %d, nouvelle borne %e\n",Var,Xmax[Var]); + # endif + if ( Xmax[Var] < LINFINI_SPX ) ChangementDeBornes = OUI_SPX; + else { + /* Si Xmax devient trop grand on sort avec le diagnostique existant */ + /* + printf("!!! Spx_DualRepositionnerLesBornes: probleme, on n'arrive pas a avoir une solution duale admissible meme\n"); + printf("en faisant tendre les bornes auxiliaires vers l'infini iteration %d\n",Spx->Iteration); + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) printf("Variable HORS_BASE_SUR_BORNE_INF "); + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) printf("Variable HORS_BASE_SUR_BORNE_SUP "); + if ( PositionDeLaVariable[Var] == HORS_BASE_A_ZERO ) printf("Variable HORS_BASE_A_ZERO "); + if ( PositionDeLaVariable[Var] == EN_BASE_LIBRE ) printf("EN_BASE_LIBRE "); + if ( Spx->StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_BORNEE_INFERIEUREMENT ) printf("BORNE_AUXILIAIRE_DE_VARIABLE_BORNEE_INFERIEUREMENT\n"); + if ( Spx->StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) printf("BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE\n"); + */ + if ( PositionDeLaVariable[Var] == EN_BASE_LIBRE ) { + printf("BUG dans SPX_DualRepositionnerLesBornes, une variable en base ne peut pas avoir de borne auxiliaire\n"); + exit(0); + } + /* On enleve la borne auxiliaire car sinon ca peut faire planter dans un branch and bound puisqu'on ne reinitialise + pas le statut des bornes sup courantes */ + SPX_SupprimerUneBorneAuxiliaire( Spx, Var ); + InfaisabiliteDuale = OUI_SPX; + } +} + +if ( InfaisabiliteDuale == OUI_SPX ) { + /* Il faut remettre toute les bornes natives car en cas de branch and bound cela peut faire + faire planter les simplexes suivants */ + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( StatutBorneSupCourante[Var] == BORNE_NATIVE ) continue; + /* On enleve la borne auxiliaire car sinon ca peut faire planter dans un branch and bound puisqu'on ne reinitialise + pas le statut des bornes sup courantes */ + SPX_SupprimerUneBorneAuxiliaire( Spx, Var ); + } + /* Afin de ne pas relancer une phase de simplexe */ + ChangementDeBornes = NON_SPX; + Spx->YaUneSolution = NON_SPX; +} + +*Changements = ChangementDeBornes; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_DualControlerLesBornesAuxiliaires( PROBLEME_SPX * Spx, char * Reoptimiser ) + +{ +char ChangementDeBornes; + +*Reoptimiser = NON_SPX; +if ( Spx->NombreDeBornesAuxiliairesUtilisees == 0 ) return; + +/* Qu'il y ait une solution ou non, il faut remettre les les bornes dans leur etat initial + puis relancer une phase 1 */ +/* printf("NombreDeBornesAuxiliairesUtilisees: %d YaUneSolution %d\n", Spx->NombreDeBornesAuxiliairesUtilisees,(int) Spx->YaUneSolution); */ + +Spx->CoeffMultiplicateurDesBornesAuxiliaires *= COEFF_MULTIPLICATEUR; +SPX_DualRepositionnerLesBornes( Spx, &ChangementDeBornes ); +if ( ChangementDeBornes == OUI_SPX ) { + *Reoptimiser = OUI_SPX; +} + +return; + +SPX_DualRepositionnerLesBornes( Spx, &ChangementDeBornes ); + +Spx->NombreDeBornesAuxiliairesUtilisees = 0; + +if ( ChangementDeBornes == OUI_SPX ) { + /* On Refait une admissiblite duale et on relance la phase 2 */ + Spx->IterationPourBornesAuxiliaires *= 2; + Spx->CoeffMultiplicateurDesBornesAuxiliaires *= COEFF_MULTIPLICATEUR; + printf("On refait une admissibilite duale. IterationPourBornesAuxiliaires: %d\n",Spx->IterationPourBornesAuxiliaires); + + SPX_DualPhase1Simplexe( Spx ); + printf("NombreDeBornesAuxiliairesUtilisees apres la nouvelle phase 1: %d\n",Spx->NombreDeBornesAuxiliairesUtilisees); + Spx->PhaseEnCours = PHASE_2; + if ( Spx->LaBaseEstDualeAdmissible == NON_SPX ) { + /* Echec */ + printf("On n'a pas pu trouver de base duale admissible \n"); + Spx->YaUneSolution = NON_SPX; + } + else { + *Reoptimiser = OUI_SPX; + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +# endif + +/*----------------------------------------------------------------------------*/ diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_controle_dual_non_borne.c b/src/ext/Sirius_Solver/simplexe/spx_dual_controle_dual_non_borne.c new file mode 100644 index 0000000000..3dde09b210 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_controle_dual_non_borne.c @@ -0,0 +1,140 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Verifications pour confirmer l'absence de solution + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_DualControleDualNonBorne( PROBLEME_SPX * Spx, char * ConfirmationDualNonBorneEnCours ) + +{ +int AdmissibiliteRestauree; char CoutsReduitsAJour; + +#if VERBOSE_SPX + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + if ( Spx->TypeDeVariable[Spx->VariableSortante] == BORNEE ) { + printf("Detection dual non borne a l iteration %d variable sortante %d valeur %10.8lf Min %lf Max %lf SeuilDeViolationDeBorne %e\n", + Spx->Iteration,Spx->VariableSortante, + Spx->BBarre[Spx->OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]]], + Spx->Xmin[Spx->VariableSortante],Spx->Xmax[Spx->VariableSortante],Spx->SeuilDeViolationDeBorne[Spx->VariableSortante]); + } + else if ( Spx->TypeDeVariable[Spx->VariableSortante] == BORNEE_INFERIEUREMENT ) { + printf("Detection dual non borne a l iteration %d variable sortante %d valeur %10.8lf Min %lf Max INFINI SeuilDeViolationDeBorne %e\n", + Spx->Iteration,Spx->VariableSortante, + Spx->BBarre[Spx->OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]]], + Spx->Xmin[Spx->VariableSortante],Spx->SeuilDeViolationDeBorne[Spx->VariableSortante]); + } + else if ( Spx->TypeDeVariable[Spx->VariableSortante] == BORNEE_SUPERIEUREMENT ) { + printf("Detection dual non borne a l iteration %d variable sortante %d valeur %10.8lf Min -INFINI Max %lf SeuilDeViolationDeBorne %e\n", + Spx->Iteration,Spx->VariableSortante, + Spx->BBarre[Spx->OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]]], + Spx->Xmax[Spx->VariableSortante],Spx->SeuilDeViolationDeBorne[Spx->VariableSortante]); + } + } + else { + if ( Spx->TypeDeVariable[Spx->VariableSortante] == BORNEE ) { + printf("Detection dual non borne a l iteration %d variable sortante %d valeur %10.8lf Min %lf Max %lf SeuilDeViolationDeBorne %e\n", + Spx->Iteration,Spx->VariableSortante,Spx->BBarre[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]], + Spx->Xmin[Spx->VariableSortante],Spx->Xmax[Spx->VariableSortante],Spx->SeuilDeViolationDeBorne[Spx->VariableSortante]); + } + else if ( Spx->TypeDeVariable[Spx->VariableSortante] == BORNEE_INFERIEUREMENT ) { + printf("Detection dual non borne a l iteration %d variable sortante %d valeur %10.8lf Min %lf Max INFINI SeuilDeViolationDeBorne %e\n", + Spx->Iteration,Spx->VariableSortante,Spx->BBarre[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]], + Spx->Xmin[Spx->VariableSortante],Spx->SeuilDeViolationDeBorne[Spx->VariableSortante]); + } + else if ( Spx->TypeDeVariable[Spx->VariableSortante] == BORNEE_SUPERIEUREMENT ) { + printf("Detection dual non borne a l iteration %d variable sortante %d valeur %10.8lf Min -INFINI Max %lf SeuilDeViolationDeBorne %e\n", + Spx->Iteration,Spx->VariableSortante,Spx->BBarre[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]], + Spx->Xmax[Spx->VariableSortante],Spx->SeuilDeViolationDeBorne[Spx->VariableSortante]); + } + } +#endif + +if ( Spx->NombreDeChangementsDeBase > 0 ) CoutsReduitsAJour = NON_SPX; +else CoutsReduitsAJour = OUI_SPX; + +if ( Spx->LesCoutsOntEteModifies == OUI_SPX ) { + /* Il est preferable de calculer les couts reduit par une resolution de systeme plutot que par une mise a jour */ + memcpy( (char *) Spx->C, (char *) Spx->Csv, Spx->NombreDeVariables * sizeof( double ) ); + Spx->LesCoutsOntEteModifies = NON_SPX; + CoutsReduitsAJour = NON_SPX; +} + +/* Il n'y a pas de variable entrante possible et donc en principe le dual est non borne */ +/* Si on a deja reinitilise les poids pour obtenir une confirmation de dual non borne alors + on continue: on ne trouvera pas de variable sortante et on sera amene a tester l'indicateur Spx->AdmissibilitePossible + si l'admissibilite est tout de meme possible, alors on repartira dans la sequence standard deroulee lorsqu'on + obtient une solution */ +if ( *ConfirmationDualNonBorneEnCours == NON_SPX ) { + /* On n'est pas encore dans la phase de confirmation: on controle tout d'abord l'admissibilite duale de + la base courante */ + if ( Spx->NombreDeChangementsDeBase > 0 ) { + /* Si la factorisee est trop ancienne on refactorise */ + SPX_FactoriserLaBase( Spx ); + if ( Spx->ChoixDeVariableSortanteAuHasard == OUI_SPX ) { + /* Probleme: la refactorisation n'a pas marche */ + return; + } + CoutsReduitsAJour = NON_SPX; + } + if ( CoutsReduitsAJour == NON_SPX ) { + /* Recalcul des couts reduits car ils peuvent etre imprecis */ + SPX_CalculerPi( Spx ); + SPX_CalculerLesCoutsReduits( Spx ); + CoutsReduitsAJour = OUI_SPX; + Spx->CalculerCBarre = NON_SPX; + } + /* Permet de creer des bornes si necessaire */ + SPX_VerifierAdmissibiliteDuale( Spx , &AdmissibiliteRestauree ); + /* Reinitialisation des poids du steepest edge pour choisir une variable sortante sur la base de la violation de borne */ + /* Non, il vaut mieux conserver les poids car parfois on se retourve dans des cas degeneres et dans ce cas + les poids sont utiles. La consequence est qu'on aura toujours la meme variable sortante (sauf s'il y a des + petites differences entre la mise a jour et le calcul complet de BBarre, mais le calcul de la variable entrante + sera fait avec les couts non bruites */ + /*SPX_InitDualPoids( Spx );*/ + + *ConfirmationDualNonBorneEnCours = OUI_SPX; + Spx->ModifCoutsAutorisee = NON_SPX; + + /* On remet le seuil de pivotage initial */ + Spx->SeuilDePivotDual = VALEUR_DE_PIVOT_ACCEPTABLE; + Spx->ChoixDeVariableSortanteAuHasard = NON_SPX; + Spx->NombreDeChoixFaitsAuHasard = 0; + return; +} +else { + /* Mise a jour de l'indicateur: Spx->AdmissibilitePossible */ + /* Quand on en arrive a cet extreme, on conserve les couts courants (donc eventuellement bruites) et + les couts reduits correspondants */ + *ConfirmationDualNonBorneEnCours = NON_SPX; + SPX_DualConfirmerDualNonBorne( Spx ); +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_controle_optimalite.c b/src/ext/Sirius_Solver/simplexe/spx_dual_controle_optimalite.c new file mode 100644 index 0000000000..39838a8219 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_controle_optimalite.c @@ -0,0 +1,187 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Controle de l'optimalite + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define VERBOSE_SPX 0 + +/*----------------------------------------------------------------------------*/ + +void SPX_DualControlerOptimalite( PROBLEME_SPX * Spx, int * NbControlesFinaux, + char * ControleSolutionFait ) +{ +int AdmissibiliteRestauree; int Marge; char CoutsReduitsAJour; int NombreDeCoutsBruitess; +char OnVientDeFactoriser; int Var; char * CorrectionDuale; double * C; double * Csv; + +#if VERBOSE_SPX + printf("SPX_DualControlerOptimalite a l iteration %d\n", Spx->Iteration); +#endif + +Spx->YaUneSolution = NON_SPX; +Spx->ModifCoutsAutorisee = NON_SPX; + +if ( Spx->NombreDeChangementsDeBase > 0 ) CoutsReduitsAJour = NON_SPX; +else CoutsReduitsAJour = OUI_SPX; + +/* On verifie qu'on peut faire encore des iterations si necessaire */ +/* Attention une augmentation inconsidere de NombreMaxDIterations peut conduire le simplexe a ne + jamais se terminer */ +if ( *NbControlesFinaux < NOMBRE_MAX_DE_CONTROLES_FINAUX ) { + Marge = (int) ceil( 0.5 * Spx->NombreDeContraintes ); + if ( Spx->Iteration < Spx->NombreMaxDIterations ) { + if ( Spx->NombreMaxDIterations - Marge < Spx->Iteration ) Spx->NombreMaxDIterations = Spx->Iteration + Marge; + } + else Spx->NombreMaxDIterations = Spx->Iteration + Marge; +} + +/* Optimum atteint: si il y a eu degenerescence, on restaure les couts */ +if ( Spx->LesCoutsOntEteModifies == OUI_SPX ) { + /* On remet les vrais couts */ + /*memcpy( (char *) Spx->C, (char *) Spx->Csv, Spx->NombreDeVariables * sizeof( double ) );*/ + NombreDeCoutsBruitess = 0; + CorrectionDuale = Spx->CorrectionDuale; + C = Spx->C; + Csv = Spx->Csv; + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( CorrectionDuale[Var] == 0 ) NombreDeCoutsBruitess++; + C[Var] = Csv[Var]; + } + if ( Spx->AffichageDesTraces == OUI_SPX ) { + printf("NombreDeCoutsBruitess %d NombreDeVariables %d ratio %e\n", + NombreDeCoutsBruitess,Spx->NombreDeVariables,(float) NombreDeCoutsBruitess / (float) Spx->NombreDeVariables); + } + + Spx->LesCoutsOntEteModifies = NON_SPX; + CoutsReduitsAJour = NON_SPX; + + if ( NombreDeCoutsBruitess > 0.1 * Spx->NombreDeVariables ) { + if ( Spx->AffichageDesTraces == OUI_SPX ) + printf("On relance la base reduite\n"); + Spx->ForcerUtilisationDeLaBaseComplete = 0; + Spx->InitBaseReduite = OUI_SPX; + } + + if ( Spx->AffichageDesTraces == OUI_SPX ) { + if ( Spx->ProblemePneDeSpx == NULL ) printf("Not far from optimality ..seems so ..\n"); + } + +} + +/* Controle d'admissibilite duale */ +if ( *NbControlesFinaux < NOMBRE_MAX_DE_CONTROLES_FINAUX ) { /* C'est pour eviter un cyclages pour des question d'epsilon */ + /* Avant de verifier l'admissibilite duale il est preferable de calculer exactement les + couts reduits pour eviter les derives dues a la mise a jour */ + OnVientDeFactoriser = NON_SPX; + if ( Spx->NombreDeChangementsDeBase > 0 && Spx->ExplorationRapideEnCours == NON_SPX ) { + OnVientDeFactoriser = OUI_SPX; + SPX_FactoriserLaBase( Spx ); + if ( Spx->ChoixDeVariableSortanteAuHasard == OUI_SPX ) { + *NbControlesFinaux = *NbControlesFinaux + 1; /* Incrementer le compteur car sinon il y a risque cyclage */ + /* Probleme: la refactorisation n'a pas marche */ + #if VERBOSE_SPX + printf( "SPX_DualControlerOptimalite: NbControlesFinaux %d ChoixDeVariableSortanteAuHasard: OUI\n", + *NbControlesFinaux); + #endif + return; + } + CoutsReduitsAJour = NON_SPX; + } + if ( CoutsReduitsAJour == NON_SPX ) { + /* Recalcul des couts reduits car ils peuvent etre imprecis */ + SPX_CalculerPi( Spx ); + SPX_CalculerLesCoutsReduits( Spx ); + CoutsReduitsAJour = OUI_SPX; + Spx->CalculerCBarre = NON_SPX; + } + *NbControlesFinaux = *NbControlesFinaux + 1; + SPX_VerifierAdmissibiliteDuale( Spx , &AdmissibiliteRestauree ); + if ( AdmissibiliteRestauree == OUI_SPX ) { + #if VERBOSE_SPX + printf( "SPX_DualControlerOptimalite: admissibilite duale restauree, on refait des iterations duales\n"); + #endif + Spx->CalculerBBarre = OUI_SPX; + /* La solution n'etait pas optimale, on repart dans les iterations */ + return; + } + /* Si la base vient d'etre factorisee, on relance une recherche de variables sortantes au cas ou + la solution n'etait pas primale admissible */ + if ( OnVientDeFactoriser == OUI_SPX ) { + Spx->CalculerBBarre = OUI_SPX; + return; + } +} + +/* A ce stade, soit on a depasse le nombre max de controles finaux, soit tout est OK */ +if ( *ControleSolutionFait == NON_SPX ) { + /* Si la date de factorisation precedente est trop ancienne on refactorise la base */ + if ( Spx->NombreDeChangementsDeBase >= (int) (0.5 * Spx->CycleDeRefactorisation) ) { + #if VERBOSE_SPX + printf("Factorisation de la base pour affiner la solution\n"); + #endif + /* Bizarement, si on refactorise apres un nombre de changements de bases trop petit ca peut dire qu'il n'y a pas de solution ensuite */ + SPX_FactoriserLaBase( Spx ); + Spx->CalculerBBarre = OUI_SPX; + Spx->CalculerCBarre = OUI_SPX; /* Attention il faut recalculer Pi quand meme pour avoir les variables duales */ + *ControleSolutionFait = OUI_SPX; + Spx->CycleDeRefactorisation = (int) (0.5 * Spx->CycleDeRefactorisation); + /* 2 car c'est decremente apres Debut */ + Spx->FaireDuRaffinementIteratif = 2; + return; + } +} + +if ( CoutsReduitsAJour == NON_SPX ) { + /* On affine quand meme les couts reduits pour le reduced cost fixing du branch and bound */ + SPX_CalculerPi( Spx ); + SPX_CalculerLesCoutsReduits( Spx ); + Spx->CalculerCBarre = NON_SPX; + + /* Controle de l'admissibilite duale: si la solution n'est pas duale admissible, on sort sans solution */ + SPX_VerifierAdmissibiliteDuale( Spx , &AdmissibiliteRestauree ); + if ( AdmissibiliteRestauree == OUI_SPX ) { + #if VERBOSE_SPX + printf( "SPX_DualControlerOptimalite: solution primale admissible mais non duale adminissible\n"); + #endif + + /* Il faut recalculer BBarre puisqu'on a change des bornes */ + Spx->CalculerBBarre = OUI_SPX; + /*Spx->CalculerCBarre = OUI_SPX;*/ + + return; + } +} + +#if VERBOSE_SPX + printf( "SPX_DualControlerOptimalite: fin de phase 2 atteint en %d iterations\n",Spx->Iteration-1); +#endif + +Spx->YaUneSolution = OUI_SPX; + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_crash_base.c b/src/ext/Sirius_Solver/simplexe/spx_dual_crash_base.c new file mode 100644 index 0000000000..6ad1a172b8 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_crash_base.c @@ -0,0 +1,893 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Construction d'une crash base triangulaire avec autant de + variables structurelles que possible. + Algorithme dual. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" /* Pour la valeur de PIVOT_MIN_SIMPLEXE */ + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +# define VERBOSE_SPX 0 + +# define SEUIL_DE_PIVOT ( 100. * PIVOT_MIN_SIMPLEXE ) /* Ce seuil doit etre superieur au pivot nul de la factorisation LU */ +# define MX_NBSCAN 2 +# define MX_NBTERMES 10 + +# define UTILISER_LA_VERIFICATION_DU_TRIANGLE + /*# undef UTILISER_LA_VERIFICATION_DU_TRIANGLE*/ + +# define VALEUR_SECOND_MEMBRE 0.1 /*0.1*/ +# define SEUIL_DADMISSIBILITE_TRIANGLE ( 1.0 * SEUIL_DADMISSIBILITE ) +# define COEFF_DE_DEGRADATION_DE_LERREUR 2.0 +# define NB_CALCULS_MOYENNE 10 + +typedef struct{ + int * Mdeb; + int * NbTerm; + int * Indcol; + double * A; + int NombreDeContraintesAParcourir; + int * ContrainteAParcourir; + char * VariableAffectable; + + int PlusGrandNombreDeTermesParLigne; + int * PremLigne; + int * SuivLigne; + int * PrecLigne; + + int ContrainteChoisie; + int VariableChoisie; +} CB; + +/*--------------------------------------------------------------------------------------------------*/ + +void SPX_CrashBaseChainageDeLaTransposee( PROBLEME_SPX * ); +void SPX_DualClasserUneLigne( int , CB * ); +void SPX_DualDeClasserUneLigne( int , CB * ); +void SPX_DualClasserToutesLesLignes( PROBLEME_SPX * , CB * ); +void SPX_DualMajChainageParLigne( CB * ); +void SPX_DualChoisirUneContrainteEtUneVariable( PROBLEME_SPX * , CB * ); + +int SPX_VerifResolutionCrashBase( PROBLEME_SPX * , CB * , double * , double * ); +void SPX_VerifResolutionCrashBaseTransposee( PROBLEME_SPX * , int * ); + +/*--------------------------------------------------------------------------------------------------*/ +/* Chainage de la transposee mais sans ACol */ + +void SPX_CrashBaseChainageDeLaTransposee( PROBLEME_SPX * Spx ) +{ +int i; int il; int ilMax; int Var ; int ilC ; +int * NumeroDeContrainte ; int * Mdeb; int * NbTerm ; int * Indcol; +int * Cdeb; int * CNbTerm; int * IndexCourant ; double * ACol; double * A; +int NombreDeVariables ; int NombreDeContraintes ; + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; + +ACol = Spx->ACol; +A = Spx->A; + +NumeroDeContrainte = Spx->NumeroDeContrainte; +NombreDeVariables = Spx->NombreDeVariables; +NombreDeContraintes = Spx->NombreDeContraintes; + +IndexCourant = (int *) malloc( NombreDeVariables * sizeof( int ) ); +if ( IndexCourant == NULL ) { + printf(" Simplexe: memoire insuffisante dans SPX_CrashBaseChainageDeLaTransposee \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); +} +memset( (char *) CNbTerm , 0 , NombreDeVariables * sizeof( int ) ); + +for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + CNbTerm[Indcol[il]]++; + il++; + } +} +for ( ilC = 0 , Var = 0 ; Var < NombreDeVariables ; Var++ ) { + Cdeb[Var] = ilC; + IndexCourant[Var] = ilC; + ilC+= CNbTerm[Var]; +} + +for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + NumeroDeContrainte[IndexCourant[Indcol[il]]] = i; + # ifdef UTILISER_LA_VERIFICATION_DU_TRIANGLE + ACol[IndexCourant[Indcol[il]]] = A[il]; + # endif + IndexCourant[Indcol[il]]++; + il++; + } +} + +free( IndexCourant ); + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Classement d'une ligne en fonction de son nombre de termes */ + +void SPX_DualClasserUneLigne( int Cnt, CB * Cb) +{ +int NbTermes; int CntSuiv; + +NbTermes = Cb->NbTerm[Cnt]; +CntSuiv = Cb->PremLigne[NbTermes]; +Cb->PremLigne[NbTermes] = Cnt; +Cb->SuivLigne[Cnt] = CntSuiv; +if ( CntSuiv >= 0 ) Cb->PrecLigne[CntSuiv] = Cnt; + +return; +} + +/*------------------------------------------------------------------------------------------------*/ +/* Enleve la ligne de son chainage en fonction de son nombre de termes */ + +void SPX_DualDeClasserUneLigne( int Cnt, CB * Cb ) +{ +int NbTermes; + +NbTermes = Cb->NbTerm[Cnt]; +if ( Cb->PremLigne[NbTermes] == Cnt ) { + /* C'est le premier element qu'on enleve */ + Cb->PremLigne[NbTermes] = Cb->SuivLigne[Cnt]; + return; +} +Cb->SuivLigne[Cb->PrecLigne[Cnt]] = Cb->SuivLigne[Cnt]; +if ( Cb->SuivLigne[Cnt] >= 0 ) Cb->PrecLigne[Cb->SuivLigne[Cnt]] = Cb->PrecLigne[Cnt]; + +return; +} + +/*--------------------------------------------------------------------------------------------------*/ +/* Classement de toutes les lignes en fonction de leur nombre de termes */ + +void SPX_DualClasserToutesLesLignes( PROBLEME_SPX * Spx, CB * Cb ) +{ +int Cnt; + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) SPX_DualClasserUneLigne( Cnt , Cb ); + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_DualMajChainageParLigne( CB * Cb ) +{ +int Cnt; int il; int ilMax; int Var; int i; int * Cb_ContrainteAParcourir; +int * Cb_Mdeb; int * Cb_NbTerm; int * Cb_Indcol; char * Cb_VariableAffectable; +double * Cb_A; + +Cb_ContrainteAParcourir = Cb->ContrainteAParcourir; +Cb_Mdeb = Cb->Mdeb; +Cb_NbTerm = Cb->NbTerm; +Cb_Indcol = Cb->Indcol; +Cb_A = Cb->A; +Cb_VariableAffectable = Cb->VariableAffectable; + +for ( i = 0 ; i < Cb->NombreDeContraintesAParcourir ; i++) { + Cnt = Cb_ContrainteAParcourir[i]; + SPX_DualDeClasserUneLigne( Cnt , Cb ); + /* On enleve les colonnes des variables non affectables du chainage par ligne */ + /* Les autres variables de la contraintes ont ContrainteAvecMinTermeLigne a recalculer */ + il = Cb_Mdeb[Cnt]; + ilMax = il + Cb_NbTerm[Cnt] - 1; + while ( il <= ilMax ) { + Var = Cb_Indcol[il]; + if ( Cb_VariableAffectable[Var] == NON_SPX ) { + /* On remplace il par le dernier */ + Cb_Indcol[il] = Cb_Indcol[ilMax]; + Cb_A [il] = Cb_A[ilMax]; + ilMax--; + Cb_NbTerm[Cnt]--; + } + else { + il++; + } + } + /* Classement des lignes modifiees */ + SPX_DualClasserUneLigne( Cnt , Cb ); +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +int SPX_VerifResolutionCrashBase( PROBLEME_SPX * Spx, CB * Cb, double * Bs, + double * Accumulateur ) +{ +int Var; int Cnt; int il; int ilMax; int ic; int icMax; int Resolution_OK; +double Pivot; double X; double S; int * Cb_Mdeb; int * Cb_NbTerm; int * Cb_Indcol; +double * Cb_A; int * Spx_Cdeb; int * Spx_CNbTerm;int * Spx_NumeroDeContrainte; +double * Spx_ACol; + +X = 0.0; + +Cb_Mdeb = Cb->Mdeb; +Cb_NbTerm = Cb->NbTerm; +Cb_Indcol = Cb->Indcol; +Cb_A = Cb->A; + +Spx_Cdeb = Spx->Cdeb; +Spx_CNbTerm = Spx->CNbTerm; +Spx_NumeroDeContrainte = Spx->NumeroDeContrainte; +Spx_ACol = Spx->ACol; + +Resolution_OK = OUI_SPX; + +/* On verifie si la nouvelle colonne ne deteriore pas trop le conditionnement de la matrice. + Pour cela on simule une resolution */ +Var = Cb->VariableChoisie; +Cnt = Cb->ContrainteChoisie; +il = Cb_Mdeb[Cnt]; +ilMax = il + Cb_NbTerm[Cnt]; +/* Recherche du pivot */ +while ( il < ilMax ) { + if ( Cb_Indcol[il] == Var ) { + /* Pivot trouve */ + Pivot = Cb_A[il]; + /* Controle de la resolution */ + X = Bs[Cnt] / Pivot; + S = Accumulateur[Cnt] + (Pivot * X); + if ( fabs( S - VALEUR_SECOND_MEMBRE ) > SEUIL_DADMISSIBILITE_TRIANGLE ) { + /*printf("Refus car S - VALEUR_SECOND_MEMBRE = %e\n",S - VALEUR_SECOND_MEMBRE );*/ + Resolution_OK = NON_SPX; + } + break; + } + il++; +} + +if ( Resolution_OK == OUI_SPX ) { + Var = Cb->VariableChoisie; + ic = Spx_Cdeb[Var]; + icMax = ic + Spx_CNbTerm[Var]; + while ( ic < icMax ) { + Cnt = Spx_NumeroDeContrainte[ic]; + S = Spx_ACol[ic] * X; + Accumulateur[Cnt]+= S; + Bs[Cnt]-= S; + ic++; + } +} + +return( Resolution_OK ); +} + +/*----------------------------------------------------------------------------*/ +/* La base triangulaire a ete construite. On effectue une resolution avec la + transposee avant de l'accepter. Si on s'aperçoit que ça se passe mal, on casse + une partie de la base et on complete avec des variables additionnelles */ + +void SPX_VerifResolutionCrashBaseTransposee( PROBLEME_SPX * Spx, int * Ordre ) +{ +int Kp; int NombreDeContraintes; int NombreDeVariables; int Var; int Cnt; +int il; int il0; int ilMax; double X; double S; char * PositionDeLaVariable; +int * ContrainteDeLaVariableEnBase; int * VariableEnBaseDeLaContrainte; +double * Accumulateur; int * Mdeb; int * NbTerm; int * Indcol; double * A; +double Pivot; double * SecondMembre; char * OrigineDeLaVariable; char * TypeDeVariable; +double CalculPremiereMoyenne; double CalculDeuxiemeMoyenne; int NbPremiereMoyenne; +int NbDeuxiemeMoyenne; double PremiereMoyenne; double DeuxiemeMoyenne; + +Pivot = 1.0; + +NombreDeContraintes = Spx->NombreDeContraintes; +NombreDeVariables = Spx->NombreDeVariables; + +PositionDeLaVariable = Spx->PositionDeLaVariable; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; + +SecondMembre = Spx->CBarreSurNBarreR; +Accumulateur = Spx->CBarre; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + SecondMembre[Var] = VALEUR_SECOND_MEMBRE; + Accumulateur[Var] = 0.0; +} + +PremiereMoyenne = 0.0; +DeuxiemeMoyenne = 0.0; +NbPremiereMoyenne = 0; +NbDeuxiemeMoyenne = 0; +CalculPremiereMoyenne = NON_SPX; +CalculDeuxiemeMoyenne = NON_SPX; + +for ( Kp = NombreDeContraintes - 1 ; Kp >= 0 ; Kp-- ) { + Var = Ordre[Kp]; + Cnt = ContrainteDeLaVariableEnBase[Var]; + /* Recherche du pivot */ + il0 = Mdeb[Cnt]; + il = il0; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( Indcol[il] == Var ) { + Pivot = A[il]; + break; + } + il++; + } + /* Calcul de la solution */ + X = SecondMembre[Var] / Pivot; + /* Verification de la resolution */ + S = (X * Pivot) + Accumulateur[Var]; + S = fabs( S - VALEUR_SECOND_MEMBRE ); + if ( S > SEUIL_DADMISSIBILITE_TRIANGLE ) { + if ( CalculPremiereMoyenne == OUI_SPX ) { + PremiereMoyenne+= S; + NbPremiereMoyenne++; + if ( NbPremiereMoyenne >= NB_CALCULS_MOYENNE ) { + CalculPremiereMoyenne = NON_SPX; + CalculDeuxiemeMoyenne = OUI_SPX; + PremiereMoyenne/= NbPremiereMoyenne; + } + } + else if ( CalculDeuxiemeMoyenne == OUI_SPX ) { + DeuxiemeMoyenne+= S; + NbDeuxiemeMoyenne++; + if ( NbDeuxiemeMoyenne >= NB_CALCULS_MOYENNE ) { + CalculDeuxiemeMoyenne = NON_SPX; + DeuxiemeMoyenne/= NbDeuxiemeMoyenne; + /*printf(" PremiereMoyenne %e DeuxiemeMoyenne %e\n",PremiereMoyenne,DeuxiemeMoyenne);*/ + if ( DeuxiemeMoyenne > COEFF_DE_DEGRADATION_DE_LERREUR * PremiereMoyenne ) { + /* L'erreur moyenne augmente */ + break; + } + else { + PremiereMoyenne = 0.0; + DeuxiemeMoyenne = 0.0; + NbPremiereMoyenne = 0; + NbDeuxiemeMoyenne = 0; + CalculPremiereMoyenne = NON_SPX; + CalculDeuxiemeMoyenne = NON_SPX; + } + } + } + else if ( S > SEUIL_DADMISSIBILITE_TRIANGLE ) { + /* Resolution imprecise */ + /*printf("Ecart de resolution transposee %e Kp = %d\n", S, Kp);*/ + CalculPremiereMoyenne = OUI_SPX; + } + } + /* Mise a jour de SecondMembre et Accumulateur */ + il = il0; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( PositionDeLaVariable[Var] == EN_BASE_LIBRE ) { + S = A[il] * X; + SecondMembre[Var]-= S; + Accumulateur[Var]+= S; + } + il++; + } +} + +OrigineDeLaVariable = Spx->OrigineDeLaVariable; +TypeDeVariable = Spx->TypeDeVariable; +for ( ; Kp >= 0 ; Kp-- ) { + /* Si ce n'est pas deja une variable additionnelle, on la cree */ + Var = Ordre[Kp]; + /* 16/4/2012: j'ajoute le test par rapport a ECART car il n'y a pas de difference d'usage par rapport a + une variable BASIQUE ARTIFICIELLE */ + if ( OrigineDeLaVariable[Var] == ECART ) continue; + if ( OrigineDeLaVariable[Var] == BASIQUE_ARTIFICIELLE ) continue; + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT || TypeDeVariable[Var] == BORNEE ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + } + else if ( TypeDeVariable[Var] == BORNEE_SUPERIEUREMENT ) PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_SUP; + else PositionDeLaVariable[Var] = HORS_BASE_A_ZERO; + Cnt = ContrainteDeLaVariableEnBase[Var]; + ContrainteDeLaVariableEnBase[Var] = -1; + VariableEnBaseDeLaContrainte[Cnt] = -1; + SPX_DualCreerVariableDeBase( Spx, Cnt ); + +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Contruction d'une base de depart. La matrice est deja sous forme standard. */ + +void SPX_DualConstruireUneCrashBase( PROBLEME_SPX * Spx ) +{ +int Var; int Cnt; int il ; int ilMax ; int NbC; int ic; int icMax; int i; +CB * Cb ; double * Bs; double * Accumulateur; int NombreDeRefus; int * Ordre; +int Kp ; +int * Cb_Mdeb; int * Cb_NbTerm; int * Cb_Indcol; char * Cb_VariableAffectable; +int * Spx_Cdeb;int * Spx_CNbTerm; int * Spx_NumeroDeContrainte; int * Cb_ContrainteAParcourir; +char * Spx_PositionDeLaVariable; char * Spx_TypeDeVariable; int * Spx_ContrainteDeLaVariableEnBase; +int * Spx_VariableEnBaseDeLaContrainte; + +SPX_CrashBaseChainageDeLaTransposee( Spx ); + +Cb = (CB *) malloc( sizeof( CB ) ); +if ( Cb == NULL ) { + printf("Memoire insuffisante dans le sous-programme SPX_DualConstruireUneCrashBase \n"); + Spx->AnomalieDetectee = NON_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); +} + +Cb->VariableAffectable = (char *) malloc(Spx->NombreDeVariables * sizeof( char ) ); + +Cb->Mdeb = (int *) malloc( Spx->NombreDeContraintesAllouees * sizeof( int ) ); +Cb->NbTerm = (int *) malloc( Spx->NombreDeContraintesAllouees * sizeof( int ) ); +Cb->Indcol = (int *) malloc( Spx->NbTermesAlloues * sizeof( int ) ); +Cb->A = (double *) malloc( Spx->NbTermesAlloues * sizeof( double ) ); + +Cb->ContrainteAParcourir = (int *) malloc( Spx->NombreDeContraintes * sizeof( int ) ); + +Cb->PremLigne = (int *) malloc( (Spx->NombreDeVariables + 1) * sizeof( int ) ); +Cb->SuivLigne = (int *) malloc( Spx->NombreDeContraintes * sizeof( int ) ); +Cb->PrecLigne = (int *) malloc( Spx->NombreDeContraintes * sizeof( int ) ); + +if ( Cb->VariableAffectable == NULL || Cb->Mdeb == NULL || Cb->NbTerm == NULL || + Cb->Indcol == NULL || Cb->A == NULL || Cb->ContrainteAParcourir == NULL || + Cb->PremLigne == NULL || Cb->SuivLigne == NULL || Cb->PrecLigne == NULL + ) +{ + printf("Memoire insuffisante dans le sous-programme SPX_DualConstruireUneCrashBase \n"); + Spx->AnomalieDetectee = NON_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); +} + +memcpy( (char *) Cb->Mdeb , (char *) Spx->Mdeb , Spx->NombreDeContraintes * sizeof( int ) ); +memcpy( (char *) Cb->NbTerm, (char *) Spx->NbTerm, Spx->NombreDeContraintes * sizeof( int ) ); +memcpy( (char *) Cb->Indcol, (char *) Spx->Indcol, Spx->NbTermesAlloues * sizeof( int ) ); +memcpy( (char *) Cb->A , (char *) Spx->A , Spx->NbTermesAlloues * sizeof( double ) ); + + +Cb_Mdeb = Cb->Mdeb; +Cb_NbTerm = Cb->NbTerm; +Cb_Indcol = Cb->Indcol; +Cb_VariableAffectable = Cb->VariableAffectable; +Spx_Cdeb = Spx->Cdeb; +Spx_CNbTerm = Spx->CNbTerm; +Spx_NumeroDeContrainte = Spx->NumeroDeContrainte; +Cb_ContrainteAParcourir = Cb->ContrainteAParcourir; + +Spx_PositionDeLaVariable = Spx->PositionDeLaVariable; +Spx_TypeDeVariable = Spx->TypeDeVariable; +Spx_ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +Spx_VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + Cb_VariableAffectable [Var] = OUI_SPX; + Spx_PositionDeLaVariable [Var] = HORS_BASE_SUR_BORNE_INF; + if ( Spx_TypeDeVariable[Var] == NON_BORNEE ) { + Spx_PositionDeLaVariable[Var] = HORS_BASE_A_ZERO; + } + Spx_ContrainteDeLaVariableEnBase[Var] = -1; + /* Car une ligne peut avoir Spx->NombreDeVariables termes */ + Cb->PremLigne[Var] = -1; +} +Cb->PremLigne[Spx->NombreDeVariables] = -1; + +SPX_DualClasserToutesLesLignes( Spx , Cb ); + +Cb->PlusGrandNombreDeTermesParLigne = -1; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + if ( Cb->NbTerm[Cnt] > Cb->PlusGrandNombreDeTermesParLigne ) Cb->PlusGrandNombreDeTermesParLigne = Cb->NbTerm[Cnt]; + Spx_VariableEnBaseDeLaContrainte[Cnt] = -1; + Cb->ContrainteAParcourir[Cnt] = NON_SPX; +} + +Bs = Spx->Bs; +Accumulateur = Spx->BBarre; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + Bs[Cnt] = VALEUR_SECOND_MEMBRE; + Accumulateur[Cnt] = 0.0; +} + +Ordre = Spx->CdebBase; +Kp = 0; + +while ( 1 ) { + + NombreDeRefus = 0; /* Utilite a verifier */ + + # ifdef UTILISER_LA_VERIFICATION_DU_TRIANGLE + DEBUT_WHILE: + # endif + + SPX_DualChoisirUneContrainteEtUneVariable( Spx , Cb ); + if ( Cb->ContrainteChoisie < 0 || Cb->VariableChoisie < 0 ) break; + + /* On verifie si la nouvelle colonne ne deteriore pas trop le conditionnement de la matrice. + Pour cela on simule une resolution */ + # ifdef UTILISER_LA_VERIFICATION_DU_TRIANGLE + if ( SPX_VerifResolutionCrashBase( Spx, Cb, Bs, Accumulateur ) == NON_SPX ) { + NombreDeRefus++; + if ( NombreDeRefus > 100 ) break; + /* On ne devrait refuser que le pivot. Comme c'est complique, on choisi d'eliminer la colonne */ + Cb->VariableAffectable[Cb->VariableChoisie] = NON_SPX; + Cb->NombreDeContraintesAParcourir = 0; + ic = Spx->Cdeb[Cb->VariableChoisie]; + icMax = ic + Spx->CNbTerm[Cb->VariableChoisie]; + while ( ic < icMax ) { + Cb->ContrainteAParcourir[Cb->NombreDeContraintesAParcourir] = Spx->NumeroDeContrainte[ic]; + Cb->NombreDeContraintesAParcourir++; + ic++; + } + SPX_DualMajChainageParLigne( Cb ); + goto DEBUT_WHILE; + } + # endif + + Spx_PositionDeLaVariable [Cb->VariableChoisie] = EN_BASE_LIBRE; + Spx_ContrainteDeLaVariableEnBase[Cb->VariableChoisie] = Cb->ContrainteChoisie; + Spx_VariableEnBaseDeLaContrainte[Cb->ContrainteChoisie] = Cb->VariableChoisie; + + Ordre[Kp] = Cb->VariableChoisie; + Kp++; + + /* Elimination de toutes les variables qui contiennent un terme dans la ligne + de la contrainte choisie y compris la variable choisie bien sur */ + Cb->NombreDeContraintesAParcourir = 0; + + il = Cb_Mdeb[Cb->ContrainteChoisie]; + ilMax = il + Cb_NbTerm[Cb->ContrainteChoisie]; + while ( il < ilMax ) { + Var = Cb_Indcol[il]; + Cb_VariableAffectable[Var] = NON_SPX; + ic = Spx_Cdeb[Var]; + icMax = ic + Spx_CNbTerm[Var]; + while ( ic < icMax ) { + Cnt = Spx_NumeroDeContrainte[ic]; + for ( i = 0 ; i < Cb->NombreDeContraintesAParcourir ; i++ ) { + if ( Cb_ContrainteAParcourir[i] == Cnt ) goto PasDeMaj; + } + Cb_ContrainteAParcourir[Cb->NombreDeContraintesAParcourir] = Cnt; + Cb->NombreDeContraintesAParcourir++; + PasDeMaj: + ic++; + } + il++; + } + + SPX_DualMajChainageParLigne( Cb ); + + SPX_DualDeClasserUneLigne( Cb->ContrainteChoisie, Cb ); + +} + +/* On a fait ce qu'on a pu. Maintenant toutes les variables ajoutees seront + de type artificiel c'est a dire de cout non nul, meme les variables d'ecart + ne pourront plus servir (pourquoi pas les variables d'ecart ?) */ +NbC = 0; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + if ( Spx_VariableEnBaseDeLaContrainte[Cnt] >= 0 ) continue; + + /* Le 16/4/2012: je verifie s'il y a une variable d'ecart disponible. Si c'est le cas je l'utilise car je ne + vois pas de difference d'usage avec une variable BASIQUE_ARTIFICIELLE */ + /* S'il y a une varible d'ecart on la prend */ + il = Spx->Mdeb[Cnt] + Spx->NbTerm[Cnt] - 1; + Var = Spx->Indcol[il]; + if ( Spx->OrigineDeLaVariable[Var] == ECART && Spx->PositionDeLaVariable[Var] != EN_BASE_LIBRE ) { + Spx->PositionDeLaVariable [Var] = EN_BASE_LIBRE; + Spx->ContrainteDeLaVariableEnBase[Var] = Cnt; + Spx->VariableEnBaseDeLaContrainte[Cnt] = Var; + Spx->CntVarEcartOuArtif[Var] = Cnt; + NbC++; + Ordre[Kp] = Var; + Kp++; + continue; + } + + /* Il faut creer une variable artificielle */ + /* printf("Complement de base pour la contrainte %d\n",Cnt); */ + NbC++; + SPX_DualCreerVariableDeBase( Spx, Cnt ); + Ordre[Kp] = Spx->NombreDeVariables - 1; + Kp++; +} + +# ifdef UTILISER_LA_VERIFICATION_DU_TRIANGLE + SPX_VerifResolutionCrashBaseTransposee( Spx, Ordre ); +# endif + +#if VERBOSE_SPX + printf("Nombre de contraintes non affectees par crash base DUAL %d sur %d \n",NbC,Spx->NombreDeContraintes); +#endif + +free( Cb->VariableAffectable ); +free( Cb->Mdeb ); +free( Cb->NbTerm ); +free( Cb->Indcol ); +free( Cb->A ); +free( Cb->ContrainteAParcourir ); +free( Cb->PremLigne ); +free( Cb->SuivLigne ); +free( Cb->PrecLigne ); + +free( Cb ); + +return; +} + +/*-------------------------------------------------------------------------------------------------*/ + +void SPX_DualChoisirUneContrainteEtUneVariable( PROBLEME_SPX * Spx , CB * Cb ) +{ +int il; int ilMax ; int Cnt; int CntChoix; int Var ; int VarChoix; +int MinTermesLigne ; int MinTermesColonne ; int VChoix ; +int MinTermesInit ; char TypeVar ; double Tie ; int CNbTerm ; +char TypeVarChoisie ; char TypChoix ; int i ; int NbScan ; +int NbCntParcourues; int MxCntParcourues ; + +int * Mdeb ; int * NbTerm; int * Indcol ; double * A ; +double * Xmin; double * Xmax; int * CNbTermArray; char * TypeDeVariable; + +Tie = 0.0; +TypChoix = 0; + +Mdeb = Cb->Mdeb; +NbTerm = Cb->NbTerm; +A = Cb->A; +Indcol = Cb->Indcol; + +Cb->ContrainteChoisie = -1; +Cb->VariableChoisie = -1; + +/* Choix de la ligne */ +MinTermesLigne = Spx->NombreDeVariables + 100; +MinTermesInit = Spx->NombreDeContraintes + 100; +CntChoix = -1; +VarChoix = -1; +TypeVarChoisie = 128; /* car c'est un char et on peut pas mettre -1 */ + +TypeDeVariable = Spx->TypeDeVariable; +Xmax = Spx->Xmax; +Xmin = Spx->Xmin; +CNbTermArray = Spx->CNbTerm; + +MxCntParcourues = 100; + +for ( i = 1 ; i <= Cb->PlusGrandNombreDeTermesParLigne && i < MinTermesLigne ; i++) { + /* Lignes a i termes */ + NbCntParcourues = 0; + Cnt = Cb->PremLigne[i]; + while ( Cnt >= 0 ) { + NbCntParcourues++; + /* La contrainte est candidate. On verifie qu'on peut choisir une colonne */ + MinTermesColonne = MinTermesInit; + VChoix = -1; + NbScan = 0; + + /* Recherche d'une variable non bornee */ + /* + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( fabs( A[il] ) > SEUIL_DE_PIVOT ) { + if ( TypeDeVariable[Var] == NON_BORNEE ) { + MinTermesColonne = 1; + VChoix = Var; + goto FinParcours; + } + } + il++; + } + */ + /* Recherche d'une variable d'ecart */ + /* + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( fabs( A[il] ) > SEUIL_DE_PIVOT ) { + if ( Spx->OrigineDeLaVariable[Var] == ECART ) { + MinTermesColonne = 1; + VChoix = Var; + goto FinParcours; + } + } + il++; + } + */ + /* Recherche d'une variable a 1 terme dans la colonne */ + /* + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( fabs( A[il] ) > SEUIL_DE_PIVOT ) { + if ( CNbTermArray[Var] == 1 ) { + MinTermesColonne = 1; + VChoix = Var; + goto FinParcours; + } + } + il++; + } + */ + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( fabs( A[il] ) > SEUIL_DE_PIVOT ) { + TypeVar = TypeDeVariable[Var]; + CNbTerm = CNbTermArray[Var]; + if ( CNbTerm < MinTermesColonne ) { + MinTermesColonne = CNbTerm; + VChoix = Var; + TypChoix = TypeVar; + Tie = Xmax[Var] - Xmin[Var]; + if ( NbCntParcourues > MxCntParcourues ) NbScan = MX_NBSCAN + 1; + if ( TypeVar == NON_BORNEE ) { + /* Si la variables est non bornee on la met tout de suite dans la base */ + goto FinParcours; + } + } + /* Plus on aura de variables bornees hors base plus on a de chance que la base soit duale + realisable */ + else if ( CNbTerm == MinTermesColonne ) { + /* Si on passe ici ça veut dire qu'on a choisi une variable de la ligne et donc + TypChoix est initialise */ + if ( TypeVar == NON_BORNEE ) { + MinTermesColonne = CNbTerm; + VChoix = Var; + TypChoix = TypeVar; + Tie = Xmax[Var] - Xmin[Var]; + if ( NbCntParcourues > MxCntParcourues ) NbScan = MX_NBSCAN + 1; + /* Si la variables est non bornee on la met tout de suite dans la base */ + goto FinParcours; + } + else if ( TypeVar == BORNEE_INFERIEUREMENT && TypChoix != NON_BORNEE ) { + MinTermesColonne = CNbTerm; + VChoix = Var; + TypChoix = TypeVar; + Tie = Xmax[Var] - Xmin[Var]; + if ( NbCntParcourues > MxCntParcourues ) { + NbScan = MX_NBSCAN + 1; + goto FinParcours; + } + } + else if( ( Xmax[Var] - Xmin[Var] ) > Tie && TypChoix != NON_BORNEE ) { + /* La variable est donc bornee */ + MinTermesColonne = CNbTerm; + VChoix = Var; + TypChoix = TypeVar; + Tie = Xmax[Var] - Xmin[Var]; + if ( NbCntParcourues > MxCntParcourues ) { + NbScan = MX_NBSCAN + 1; + goto FinParcours; + } + } + } + } + il++; + } + + FinParcours: + if ( VChoix >= 0 ) { + NbScan++; + MinTermesLigne = i; + CntChoix = Cnt; + VarChoix = VChoix; + TypeVarChoisie = TypChoix; + if ( TypeVarChoisie > NON_BORNEE ) goto FinBoucleDeRecherche; + if ( NbScan > MX_NBSCAN ) goto FinBoucleDeRecherche; + if ( MinTermesColonne == 1 ) goto FinBoucleDeRecherche; + if ( i >= MX_NBTERMES ) goto FinBoucleDeRecherche; + } + + Cnt = Cb->SuivLigne[Cnt]; + } +} + +FinBoucleDeRecherche: + +if ( CntChoix < 0 || VarChoix < 0 ) return; +Cb->ContrainteChoisie = CntChoix; +Cb->VariableChoisie = VarChoix; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Cas d'une contrainte pour laquelle on ne fourni pas de + de base. On cree une variable supplementaire a l'emplacement + deja reserve. */ + +void SPX_DualCreerVariableDeBase( PROBLEME_SPX * Spx, int Cnt ) +{ +int il; double Seuil; + +Spx->TypeDeVariable[Spx->NombreDeVariables] = BORNEE; +Spx->C[Spx->NombreDeVariables] = 0.; +Spx->X[Spx->NombreDeVariables] = 0.; + +/* Dans le cas de l'algorithme dual on veut faire sortir cette variable de la base au plus vite. On + met donc un cout nul mais des bornes nulles */ +Spx->XminEntree[Spx->NombreDeVariables] = 0.; +Spx->Xmin [Spx->NombreDeVariables] = 0.; +Spx->XmaxEntree[Spx->NombreDeVariables] = 0.; +Spx->Xmax [Spx->NombreDeVariables] = 0.; + +Seuil = SEUIL_DE_VIOLATION_DE_BORNE_NON_NATIVE * Spx->ScaleB[Cnt]; +if ( Seuil < SEUIL_MIN_DE_VIOLATION_DE_BORNE_NON_NATIVE ) Seuil = SEUIL_MIN_DE_VIOLATION_DE_BORNE_NON_NATIVE; +else if ( Seuil > SEUIL_MAX_DE_VIOLATION_DE_BORNE_NON_NATIVE ) Seuil = SEUIL_MAX_DE_VIOLATION_DE_BORNE_NON_NATIVE; +Spx->SeuilDeViolationDeBorne[Spx->NombreDeVariables] = Seuil; + +Spx->SeuilDAmissibiliteDuale1[Spx->NombreDeVariables] = SEUIL_ADMISSIBILITE_DUALE_1; +Spx->SeuilDAmissibiliteDuale2[Spx->NombreDeVariables] = SEUIL_ADMISSIBILITE_DUALE_2; + +Spx->PositionDeLaVariable [Spx->NombreDeVariables] = EN_BASE_LIBRE; /* L'important c'est que ce soit en base */ +Spx->ContrainteDeLaVariableEnBase[Spx->NombreDeVariables] = Cnt; +Spx->VariableEnBaseDeLaContrainte[Cnt] = Spx->NombreDeVariables; + +/* On la met dans l'équation de la contrainte */ +il = Spx->Mdeb[Cnt] + Spx->NbTerm[Cnt]; /* On a deja reserve la place de cette variable a la creation du probleme */ +Spx->NbTerm[Cnt]++; +Spx->Indcol[il] = Spx->NombreDeVariables; +Spx->A [il] = 1.0; /* Important: ne pas mettre autre chose que 1 */ + +Spx->Csv [Spx->NombreDeVariables] = Spx->C[Spx->NombreDeVariables]; +Spx->OrigineDeLaVariable [Spx->NombreDeVariables] = BASIQUE_ARTIFICIELLE; +Spx->StatutBorneSupCourante [Spx->NombreDeVariables] = BORNE_NATIVE; +Spx->StatutBorneSupAuxiliaire[Spx->NombreDeVariables] = BORNE_AUXILIAIRE_INVALIDE; + +Spx->CntVarEcartOuArtif [Spx->NombreDeVariables] = Cnt; + +Spx->CorrespondanceVarSimplexeVarEntree[Spx->NombreDeVariables] = -1; + +/* Incrementation du nombre de variables */ +Spx->NombreDeVariables++; + +return; +} + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_epurer_la_base.c b/src/ext/Sirius_Solver/simplexe/spx_dual_epurer_la_base.c new file mode 100644 index 0000000000..6a5cde793e --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_epurer_la_base.c @@ -0,0 +1,347 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Epuration de la base dans le cas du noeud racine du branch + and bound: on essai de faire sortir de la base les variables + artificelles des contraintes d'egalite et ainsi de diminuer + le nombre de variables. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# define NOMBRE_MAX_DE_CYCLAGE_APRES_OPTIMALITE 10 + +/*----------------------------------------------------------------------------*/ + +void SPX_DualEpurerLaBaseSimplexe( PROBLEME_SPX * Spx , + int * NombreDeCyclagesApresOptimalite, + char * EpurerLaBase , + char * Echec ) +{ +int Var; int Var1; double Amx; int Cnt; int il ; int ilMax; double S; +int ic ;int NombreDeVariables; char EpurationFaite; +int * ContrainteDeLaVariableEnBase; int * Mdeb; int * NbTerm; int * Indcol; +int * NumeroDeContrainte; int * Cdeb; char * StatutBorneSupCourante; +int * CNbTermSansCoupes; int * VariableEnBaseDeLaContrainte; int * CNbTerm; +char * OrigineDeLaVariable; char * PositionDeLaVariable; char * TypeDeVariable; +char * InDualFramework; char ControlerAdmissibiliteDuale; +double * NBarreR; double * A; double * C; double * X; double * XminEntree; +double * Xmin; double * XmaxEntree; double * Xmax; double * SeuilDeViolationDeBorne; +double * CBarre; double * ACol; double * Csv; +int i; int icMax; int iLimite; char Echange; int * NumerosDesVariables; +int * CdebBase; int * NbTermesDesColonnesDeLaBase; + +/* Epuration de la base: on regarde s'il y a des variables artificielles dans la base. + Si c'est le cas on essai de les en faire sortir */ +*Echec = NON_SPX; + +OrigineDeLaVariable = Spx->OrigineDeLaVariable; +PositionDeLaVariable = Spx->PositionDeLaVariable; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; +NBarreR = Spx->NBarreR; + +C = Spx->C; +Csv = Spx->Csv; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +NumeroDeContrainte = Spx->NumeroDeContrainte; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; + +TypeDeVariable = Spx->TypeDeVariable; +X = Spx->X; +XminEntree = Spx->XminEntree; +Xmin = Spx->Xmin; +XmaxEntree = Spx->XmaxEntree; +Xmax = Spx->Xmax; +SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; +CBarre = Spx->CBarre; +InDualFramework = Spx->InDualFramework; +CNbTermSansCoupes = Spx->CNbTermSansCoupes; +ACol = Spx->ACol; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + +CdebBase = Spx->CdebBase; +NbTermesDesColonnesDeLaBase = Spx->NbTermesDesColonnesDeLaBase; + +if ( Spx->PremierSimplexe == OUI_SPX && *EpurerLaBase == OUI_SPX && 0 ) { + /* L'algorithme de sortie de la base pour les variables artificielles est faux. En effet, il ne se base que sur + la conservation de l'adimissibilite primale. Or les couts reduits changent par le fait qu'une colonne de + la base change lorsqu'on fait sortir une variable artificielle sans prendre de precaution. En fait il + faut verifier que le cout reduit de la variable entrante est nul */ + /* Sinon ce qu'il faut faire c'est refaire des iterations de simplexe pour retrouver la base optimale. Comme les + variables artificielles ont ete sorties, elle n'entreront plus en base */ + #if VERBOSE_SPX + printf("Recherche des variables basiques artificielles qui sont encore dans la base pour epuration \n"); + #endif + EpurationFaite = NON_SPX; + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + + if ( OrigineDeLaVariable[Var] != BASIQUE_ARTIFICIELLE ) continue; + if ( PositionDeLaVariable[Var] != EN_BASE_LIBRE ) continue; + #if VERBOSE_SPX + printf("Variable basique artificielle %d encore en base, on tente de la faire sortir \n",Var); + #endif + /* La variable sortante est Var, seule une variable de la meme contrainte peut prendre sa place + dans la base */ + Spx->VariableSortante = Var; + Spx->SortSurXmaxOuSurXmin = SORT_SUR_XMIN; + Spx->VariableEntrante = -1; + /* On calcule seulement NBarreR pour pouvoir selectionner une variable sortante */ + SPX_DualCalculerNBarreR( Spx, NON_SPX, &ControlerAdmissibiliteDuale ); + Spx->FactoriserLaBase = NON_SPX; + SPX_DualVerifierErBMoinsUn( Spx ); + if ( Spx->UtiliserLaLuUpdate == NON_SPX ) { + if ( Spx->NombreDeChangementsDeBase == Spx->CycleDeRefactorisation ) Spx->FactoriserLaBase = OUI_SPX; + } + if ( Spx->FactoriserLaBase == OUI_SPX ) { + SPX_FactoriserLaBase( Spx ); + /* Si on est tombe sur un pivot nul, alors ça sent le roussi et on en reste la et on repart sur un simplexe */ + /* On detecte le fait qu'on soit tombe sur un pivot nul en testant la valeur de ChoixDeVariableSortanteAuHasard */ + if ( Spx->ChoixDeVariableSortanteAuHasard == OUI_SPX ) { + *EpurerLaBase = NON_SPX; + *Echec = OUI_SPX; /* Si Echec = OUI on repart sur le simplexe */ + return; + } + SPX_DualCalculerNBarreR( Spx, NON_SPX, &ControlerAdmissibiliteDuale ); + } + + /* Erreur c'est pas la ContrainteDeLaVariableEnBase qu'il faut prendre mais la contrainte de la variable */ + /* Cnt = ContrainteDeLaVariableEnBase[Var]; */ + Cnt = NumeroDeContrainte[Cdeb[Var]]; + + /* On ne peut pas supposer que le dernier terme est toujours celui de la variable basique artificielle */ + /* Oui maintenant on peut */ + /* + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + Amx = VALEUR_DE_PIVOT_ACCEPTABLE - 1.e-12; + while ( il < ilMax ) { + Var1 = Indcol[il]; + if ( PositionDeLaVariable[Var1] != EN_BASE_LIBRE && Var1 != Var ) { + S = fabs( NBarreR[Var1] ); + if ( S > Amx ) { + Spx->VariableEntrante = Var1; + Amx = S; + } + } + il++; + } + */ + /* Il faut tenir compte du type de stockage de NBarreR car si le stockage n'est pas VECTEUR_SPX, + alors il n'y a pas eu de RAZ de NBarreR */ + if ( Spx->TypeDeStockageDeNBarreR == VECTEUR_SPX ) { + iLimite = Spx->NombreDeVariablesHorsBase; + NumerosDesVariables = Spx->NumerosDesVariablesHorsBase; + } + else { + iLimite = Spx->NombreDeValeursNonNullesDeNBarreR; + NumerosDesVariables = Spx->NumVarNBarreRNonNul; + } + Amx = VALEUR_DE_PIVOT_ACCEPTABLE - 1.e-12; + for ( i = 0 ; i < iLimite ; i++ ) { + Var1 = NumerosDesVariables[i]; + S = fabs( NBarreR[Var1] ); + if ( S > Amx ) { + /* On verifie que la variable se trouve dans la contrainte */ + ic = Cdeb[Var1]; + icMax = ic + CNbTerm[Var1]; + Echange = NON_SPX; + while ( ic < icMax ) { + if ( NumeroDeContrainte[ic] == Cnt ) { + Echange = OUI_SPX; + break; + } + ic++; + } + if ( Echange == OUI_SPX ) { + Spx->VariableEntrante = Var1; + Amx = S; + } + } + } + + #if VERBOSE_SPX + printf("Variable sortante %d variable entrante %d Amx %e\n",Spx->VariableSortante,Spx->VariableEntrante,Amx); + #endif + + if ( Spx->VariableEntrante >= 0 ) { + EpurationFaite = OUI_SPX; + SPX_CalculerABarreS( Spx ); /* C'est pour calculer le spike et la maj du steepest edge */ + Spx->FactoriserLaBase = NON_SPX; + SPX_MajPoidsDualSteepestEdge( Spx ); /* Car utilise par le Strong Branching */ + SPX_FaireLeChangementDeBase( Spx ); + } + + } + /* Maintenant il faut recalculer les couts reduits */ + if ( EpurationFaite == OUI_SPX ) { + SPX_CalculerPi( Spx ); /* Calcul de Pi = c_B * B^{-1} */ + SPX_CalculerLesCoutsReduits( Spx ); /* Calcul de CBarre = c_N - < Pi , N > */ + SPX_CalculerBBarre( Spx ); + } + +} + +/* Si on ne vient pas immediatement de factoriser la base, on le fait afin de + l'utiliser dans le strong branching */ + +if ( Spx->NombreDeChangementsDeBase > 0 && Spx->ExplorationRapideEnCours == NON_SPX ) { + #if VERBOSE_SPX + printf("Factorisation necessaire avant sauvegardes pour le strong branching ou les coupes de Gomory\n"); + #endif + /* Remarque: il faudrait aussi verifier qu'on va effectivement faire du strong branching + car il se peut que non et qu'on calcule des coupes a la place */ + SPX_FactoriserLaBase( Spx ); + if ( Spx->ChoixDeVariableSortanteAuHasard == OUI_SPX ) { + *NombreDeCyclagesApresOptimalite = *NombreDeCyclagesApresOptimalite + 1; + if ( *NombreDeCyclagesApresOptimalite < NOMBRE_MAX_DE_CYCLAGE_APRES_OPTIMALITE ) { + *Echec = OUI_SPX; /* Si Echec = OUI on repart sur le simplexe */ + return; + } + else { + Spx->YaUneSolution = NON_SPX; + /* Il faut remettre toute les bornes natives car en cas de branch and bound cela peut faire + faire planter les simplexes suivants puisqu'on ne reinitialise pas le statut des bornes + sup courantes */ + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( StatutBorneSupCourante[Var] == BORNE_NATIVE ) continue; + SPX_SupprimerUneBorneAuxiliaire( Spx, Var ); + } + return; + } + } +} + +/* On peut maintenant supprimer toutes les variables BASIQUE_ARTIFICIELLE qui sont hors base */ +if ( Spx->PremierSimplexe == OUI_SPX ) { + #if VERBOSE_SPX + printf("Suppression des variables basiques artificielles qui ne sont plus dans la base \n"); + #endif + Var1 = Spx->NombreDeVariables; + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( OrigineDeLaVariable[Var] == BASIQUE_ARTIFICIELLE ) { + Var1 = Var; + break; + } + } + /* On suppose que l'on va pouvoir enlever toutes les variables basiques artificielles */ + NombreDeVariables = Var1; + for ( Var = Var1 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( PositionDeLaVariable[Var] == EN_BASE_LIBRE ) continue; + #if VERBOSE_SPX + printf("Variable basique artificielle %d supprimee\n",Var); + #endif + /* La variable artificielle est hors base: on l'enleve des donnees. Pour cela on l'enleve simplement des contraintes. + Les variables seront retassees ensuite */ + C[Var] = 0.0; + Cnt = NumeroDeContrainte[Cdeb[Var]]; + /* On ne peut pas supposer que le dernier terme est toujours celui de la variable basique artificielle */ + /* Attention: la correspondance ligne vers colonne et colonne vers ligne ne sera plus exploitable, pour la + reconstruire il faut appeler InitMatriceDeStockageDesContraintesParLigne */ + /* Maintenant que InitMatriceDeStockageDesContraintesParLigne n'existe plus pon peut supposer que le dernier + terme correspond a la variable d'ecart */ + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt] - 1; + while ( il < ilMax ) { + if ( Indcol[il] == Var ) { + A [il] = A[ilMax]; + Indcol[il] = Indcol[ilMax]; + break; + } + il++; + } + NbTerm[Cnt]--; + } + /* On remet dans la bonne numerotation les variables BASIQUE_ARTIFICIELLE qui sont + restees dans la base */ + for ( Var = Var1 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( OrigineDeLaVariable[Var] != BASIQUE_ARTIFICIELLE ) continue; + if ( PositionDeLaVariable[Var] != EN_BASE_LIBRE ) continue; + #if VERBOSE_SPX + printf("La variable basique artificielle %d reste dans les donnees du probleme avec le numero %d\n", + Var,NombreDeVariables); + #endif + + TypeDeVariable[NombreDeVariables] = BORNEE; + C[NombreDeVariables] = 1.0; + X[NombreDeVariables] = 0.; + XminEntree[NombreDeVariables] = 0.; + Xmin [NombreDeVariables] = 0.; + XmaxEntree[NombreDeVariables] = 0.; + Xmax [NombreDeVariables] = 0.; + + /* Pas besoin de toucher OrigineDeLaVariable, StatutBorneSupCourante, StatutBorneSupAuxiliaire */ + + Csv[NombreDeVariables] = C[NombreDeVariables]; + + SeuilDeViolationDeBorne[NombreDeVariables] = SeuilDeViolationDeBorne[Var]; + PositionDeLaVariable [NombreDeVariables] = PositionDeLaVariable[Var]; + CBarre [NombreDeVariables] = 0.; + + InDualFramework [NombreDeVariables] = InDualFramework[Var]; + ContrainteDeLaVariableEnBase[NombreDeVariables] = ContrainteDeLaVariableEnBase[Var]; + VariableEnBaseDeLaContrainte[ContrainteDeLaVariableEnBase[NombreDeVariables]] = NombreDeVariables; + + ic = Cdeb[Var]; + /* Matrice des contraintes par ligne */ + Cnt = NumeroDeContrainte[ic]; + /* Il faut rechercher la variable artificielle: normalement c'est la derniere */ + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( Indcol[il] == Var ) { + Indcol[il] = NombreDeVariables; + break; + } + il++; + } + + /* Matrice des contraintes par colonne */ + Cdeb [NombreDeVariables] = ic; + CNbTerm [NombreDeVariables] = 1; + CNbTermSansCoupes [NombreDeVariables] = 1; + ACol [ic] = 1.; + NumeroDeContrainte[ic] = Cnt; + + /* Comme la variable reste en base, il faut changer la base */ + CdebBase [ContrainteDeLaVariableEnBase[NombreDeVariables]] = Cdeb[NombreDeVariables]; + NbTermesDesColonnesDeLaBase[ContrainteDeLaVariableEnBase[NombreDeVariables]] = CNbTerm[NombreDeVariables]; + + NombreDeVariables++; + } + Spx->NombreDeVariables = NombreDeVariables; + Spx->NombreDeVariablesDuProblemeSansCoupes = Spx->NombreDeVariables; + +} + +return; + +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_calculer_v.c b/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_calculer_v.c new file mode 100644 index 0000000000..faccaf9635 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_calculer_v.c @@ -0,0 +1,103 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Phase 1 de l'algorithme dual. + Calcul de V = B^{-1} * a^tilde + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_DualPhase1CalculerV( PROBLEME_SPX * Spx ) +{ +int Var; int il; int ilMax; char Save; char SecondMembreCreux; int i; +int * NumerosDesVariablesHorsBase; char * FaisabiliteDeLaVariable; double * V; +int * Cdeb; int * CNbTerm; double * ACol; int * NumeroDeContrainte; +char TypeDEntree; char TypeDeSortie; char CalculEnHyperCreux; + +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +FaisabiliteDeLaVariable = Spx->FaisabiliteDeLaVariable; +V = Spx->V; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +ACol = Spx->ACol; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +/* Calcul du vecteur ATilde */ +memset( (char *) V , 0 , Spx->NombreDeContraintes * sizeof( double ) ); + +/* Boucle sur les variables hors base */ + +for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_NEGATIF ) { + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + V[NumeroDeContrainte[il]]+= ACol[il]; + il++; + } + continue; + } + + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_POSITIF ) { + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + V[NumeroDeContrainte[il]]-= ACol[il]; + il++; + } + continue; + } + +} + +TypeDEntree = VECTEUR_LU; +TypeDeSortie = VECTEUR_LU; +CalculEnHyperCreux = NON_SPX; +Save = NON_LU; +SecondMembreCreux = OUI_LU; + +SPX_ResoudreBYegalA( Spx, TypeDEntree, Spx->V, NULL, NULL, &TypeDeSortie, + CalculEnHyperCreux, Save, SecondMembreCreux ); + +/* Traces */ +/* +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + printf(" Variable en base %d V %lf ",Spx->VariableEnBaseDeLaContrainte[Cnt],Spx->V[Cnt]); + if ( Spx->TypeDeVariable[Spx->VariableEnBaseDeLaContrainte[Cnt]] == BORNEE ) printf(" variable BORNEE\n"); + if ( Spx->TypeDeVariable[Spx->VariableEnBaseDeLaContrainte[Cnt]] == BORNEE_INFERIEUREMENT ) printf(" variable BORNEE_INFERIEUREMENT\n"); + if ( Spx->TypeDeVariable[Spx->VariableEnBaseDeLaContrainte[Cnt]] == NON_BORNEE ) printf(" variable NON_BORNEE\n"); +} +*/ +/* */ + +return; +} + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_choix_variable_entrante.c b/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_choix_variable_entrante.c new file mode 100644 index 0000000000..e7c0417457 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_choix_variable_entrante.c @@ -0,0 +1,417 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Algorithme dual: choix de la variable qui entre en base. + + Rappel: dans l'alogrithme dual le test du ratio sert a determiner + la variable hors base qui entre en base alors que dans + l'algorithme primal c'est l'inverse + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define TOLERANCE_POUR_LE_TEST_DE_HARRIS_PHASE_1 SEUIL_ADMISSIBILITE_DUALE_1 /*SEUIL_ADMISSIBILITE_DUALE_2*/ + +# define NOMBRE_DE_FOIS_SCALING_SI_INVERSION_DE_TYPE_DE_SORTIE 0 /*5*/ + +/*----------------------------------------------------------------------------*/ + +void SPX_DualPhase1TestDuRatio( PROBLEME_SPX * Spx ) +{ +int Var ; double T; double SeuilDePivot; double Tmin; double * CBarre; +double SeuilHarris ; double MxNBarreR ; double XnR; double Tmax; +int * NumerosDesVariablesHorsBase; char * TypeDeVariable; double * NBarreR; +int i; char * FaisabiliteDeLaVariable; int * NumerosDesVariables; int iLimite; + +Tmin = LINFINI_SPX; +SeuilDePivot = Spx->SeuilDePivotDual; + +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +TypeDeVariable = Spx->TypeDeVariable; +NBarreR = Spx->NBarreR; +FaisabiliteDeLaVariable = Spx->FaisabiliteDeLaVariable; +CBarre = Spx->CBarre; + +if ( Spx->TypeDeStockageDeNBarreR == VECTEUR_SPX ) { + iLimite = Spx->NombreDeVariablesHorsBase; + NumerosDesVariables = Spx->NumerosDesVariablesHorsBase; +} +else { + iLimite = Spx->NombreDeValeursNonNullesDeNBarreR; + NumerosDesVariables = Spx->NumVarNBarreRNonNul; +} + +if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMAX ) { + /* La variable en base doit sortir de la base vers sa borne sup. pour etre duale realisable (T>=0) */ + for ( i = 0 ; i < iLimite ; i++ ) { + Var = NumerosDesVariables[i]; + + if ( TypeDeVariable[Var] == BORNEE ) continue; /* Pas de point de cassure */ + + /* Les variables entrantes doivent satisfaire la condition CBarre et NBarreR de meme signe */ + + if ( NBarreR[Var] > SeuilDePivot ) { + /* La variable sortante fait diminuer CBarre */ + if ( FaisabiliteDeLaVariable[Var] == DUALE_FAISABLE ) { + if ( TypeDeVariable[Var] == NON_BORNEE ) { + T = fabs( TOLERANCE_POUR_LE_TEST_DE_HARRIS_PHASE_1 / NBarreR[Var] ); + if ( T < Tmin ) { Tmin = T; Spx->VariableEntrante = Var; } + continue; + } + else { + /* La variable est faisable BORNEE_INFERIEUREMENT son cout reduit est >= - le seuil d'admissibilite duale */ + if ( CBarre[Var] < 0. ) { + T = fabs( TOLERANCE_POUR_LE_TEST_DE_HARRIS_PHASE_1 / NBarreR[Var] ); + if ( T < Tmin ) { Tmin = T; Spx->VariableEntrante = Var; } + continue; + } + } + } + if ( CBarre[Var] >= 0. ) { + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_POSITIF /* Donc non bornee */ || + TypeDeVariable [Var] == BORNEE_INFERIEUREMENT /* La variable est donc faisable */ ) { + /* On a un point de cassure */ + T = fabs( ( CBarre[Var] + TOLERANCE_POUR_LE_TEST_DE_HARRIS_PHASE_1 ) / NBarreR[Var] ); + if ( T < Tmin ) { Tmin = T; Spx->VariableEntrante = Var; } + continue; + } + } + } + + if ( NBarreR[Var] < -SeuilDePivot ) { + /* La variable sortante fait augmenter CBarre */ + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) continue; + /* La variable est donc non bornee */ + if ( FaisabiliteDeLaVariable[Var] == DUALE_FAISABLE ) { + T = fabs( TOLERANCE_POUR_LE_TEST_DE_HARRIS_PHASE_1 / NBarreR[Var] ); + if ( T < Tmin ) { Tmin = T; Spx->VariableEntrante = Var; } + continue; + } + if ( CBarre[Var] <= 0. ) { + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_NEGATIF ) { + /* La variable est donc non bornee infaisable */ + /* On a un point de cassure */ + T = fabs( ( CBarre[Var] - TOLERANCE_POUR_LE_TEST_DE_HARRIS_PHASE_1 ) / NBarreR[Var] ); + if ( T < Tmin ) { Tmin = T; Spx->VariableEntrante = Var; } + continue; + } + } + } + + } +} + +else if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + /* La variable en base doit sortir de la base vers sa borne inf. pour etre duale realisable (T<=0) */ + for ( i = 0 ; i < iLimite ; i++ ) { + Var = NumerosDesVariables[i]; + + if ( TypeDeVariable[Var] == BORNEE ) continue; /* Pas de point de cassure */ + + /* Les variables entrantes doivent satisfaire la condition CBarre et NBarreR de signe contrainte */ + + if ( NBarreR[Var] > SeuilDePivot ) { + /* La variable sortante fait augmenter CBarre */ + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) continue; + /* La variable est donc non bornee */ + if ( FaisabiliteDeLaVariable[Var] == DUALE_FAISABLE ) { + T = fabs( TOLERANCE_POUR_LE_TEST_DE_HARRIS_PHASE_1 / NBarreR[Var] ); + if ( T < Tmin ) { Tmin = T; Spx->VariableEntrante = Var; } + continue; + } + if ( CBarre[Var] <= 0. ) { + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_NEGATIF ) { + /* La variable est donc non bornee infaisable */ + T = fabs( ( CBarre[Var] - TOLERANCE_POUR_LE_TEST_DE_HARRIS_PHASE_1 ) / NBarreR[Var] ); + if ( T < Tmin ) { Tmin = T; Spx->VariableEntrante = Var; } + continue; + } + } + } + + if ( NBarreR[Var] < -SeuilDePivot ) { + /* La variable sortante fait diminuer CBarre */ + if ( FaisabiliteDeLaVariable[Var] == DUALE_FAISABLE ) { + if ( TypeDeVariable[Var] == NON_BORNEE ) { + T = fabs( TOLERANCE_POUR_LE_TEST_DE_HARRIS_PHASE_1 / NBarreR[Var] ); + if ( T < Tmin ) { Tmin = T; Spx->VariableEntrante = Var; } + continue; + } + else { /* La variable est faisable BORNEE_INFERIEUREMENT son cout reduit est >= -Seuil */ + if ( CBarre[Var] < 0. ) { + T = fabs( TOLERANCE_POUR_LE_TEST_DE_HARRIS_PHASE_1 / NBarreR[Var] ); + if ( T < Tmin ) { Tmin = T; Spx->VariableEntrante = Var; } + continue; + } + } + } + if ( CBarre[Var] >= 0. ) { + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_POSITIF /* Donc non bornee */ || + TypeDeVariable [Var] == BORNEE_INFERIEUREMENT /* La variable est donc faisable */ ) { + T = fabs( ( CBarre[Var] + TOLERANCE_POUR_LE_TEST_DE_HARRIS_PHASE_1 ) / NBarreR[Var] ); + if ( T < Tmin ) { Tmin = T; Spx->VariableEntrante = Var; } + continue; + } + } + } + + } +} + +/* Deuxieme passe sans les tolerance Harris */ +SeuilHarris = Tmin; +MxNBarreR = -LINFINI_SPX; + +if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMAX ) { + /* La variable en base doit sortir de la base vers sa borne sup. pour etre duale realisable (T>=0) */ + for ( i = 0 ; i < iLimite ; i++ ) { + Var = NumerosDesVariables[i]; + + if ( TypeDeVariable[Var] == BORNEE ) continue; /* Pas de point de cassure */ + + /* Les variables entrantes doivent satisfaire la condition CBarre et NBarreR de meme signe */ + + if ( NBarreR[Var] > SeuilDePivot ) { + XnR = NBarreR[Var]; + /* La variable sortante fait diminuer CBarre */ + if ( FaisabiliteDeLaVariable[Var] == DUALE_FAISABLE ) { + if ( TypeDeVariable[Var] == NON_BORNEE ) { + T = 0.; + if ( T <= SeuilHarris /*&& XnR > MxNBarreR*/ ) { + Spx->VariableEntrante = Var; MxNBarreR = XnR; + return; /* Priorite aux variables non bornees */ + } + continue; + } + else { /* La variable est faisable BORNEE_INFERIEUREMENT son cout reduit est >= - le seuil d'admissibilite duale */ + if ( CBarre[Var] < 0. ) { + T = 0.; + if ( T <= SeuilHarris && XnR > MxNBarreR ) { Spx->VariableEntrante = Var; MxNBarreR = XnR; } + continue; + } + } + } + if ( CBarre[Var] >= 0. ) { + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_POSITIF /* Donc non bornee */ || + TypeDeVariable [Var] == BORNEE_INFERIEUREMENT /* La variable est donc faisable */ ) { + /* On a un point de cassure */ + T = fabs( CBarre[Var] / NBarreR[Var] ); + if ( T <= SeuilHarris ) { + if ( TypeDeVariable[Var] == NON_BORNEE ) { + Spx->VariableEntrante = Var; MxNBarreR = XnR; + return; /* Priorite aux variables non bornees */ + } + if ( XnR > MxNBarreR ) { + Spx->VariableEntrante = Var; MxNBarreR = XnR; + } + } + continue; + } + } + } + + if ( NBarreR[Var] < -SeuilDePivot ) { + XnR = -NBarreR[Var]; + /* La variable sortante fait augmenter CBarre */ + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) continue; + /* La variable est donc non bornee */ + if ( FaisabiliteDeLaVariable[Var] == DUALE_FAISABLE ) { + T = 0.; + if ( T <= SeuilHarris /*&& XnR > MxNBarreR*/ ) { + Spx->VariableEntrante = Var; MxNBarreR = XnR; + return; /* Priorite aux variables non bornees */ + } + continue; + } + if ( CBarre[Var] <= 0. ) { + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_NEGATIF ) { + /* La variable est donc non bornee infaisable */ + /* On a un point de cassure */ + T = fabs( CBarre[Var] / NBarreR[Var] ); + if ( T <= SeuilHarris /*&& XnR > MxNBarreR*/ ) { + Spx->VariableEntrante = Var; MxNBarreR = XnR; + return; /* Priorite aux variables non bornees */ + } + continue; + } + } + } + + } +} + +else if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + /* La variable en base doit sortir de la base vers sa borne inf. pour etre duale realisable (T<=0) */ + for ( i = 0 ; i < iLimite ; i++ ) { + Var = NumerosDesVariables[i]; + + if ( TypeDeVariable[Var] == BORNEE ) continue; /* Pas de point de cassure */ + + /* Les variables entrantes doivent satisfaire la condition CBarre et NBarreR de signe contrainte */ + + if ( NBarreR[Var] > SeuilDePivot ) { + XnR = NBarreR[Var]; + /* La variable sortante fait augmenter CBarre */ + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) continue; + /* La variable est donc non bornee */ + if ( FaisabiliteDeLaVariable[Var] == DUALE_FAISABLE ) { + T = 0.; + if ( T <= SeuilHarris /*&& XnR > MxNBarreR*/ ) { + Spx->VariableEntrante = Var; MxNBarreR = XnR; + return; /* Priorite aux variables non bornees */ + } + continue; + } + if ( CBarre[Var] <= 0. ) { + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_NEGATIF ) { + /* La variable est donc non bornee infaisable */ + T = fabs( CBarre[Var] / NBarreR[Var] ); + if ( T <= SeuilHarris /*&& XnR > MxNBarreR*/ ) { + Spx->VariableEntrante = Var; MxNBarreR = XnR; + return; /* Priorite aux variables non bornees */ + } + continue; + } + } + } + + if ( NBarreR[Var] < -SeuilDePivot ) { + XnR = -NBarreR[Var]; + /* La variable sortante fait diminuer CBarre */ + if ( FaisabiliteDeLaVariable[Var] == DUALE_FAISABLE ) { + if ( TypeDeVariable[Var] == NON_BORNEE ) { + T = 0.; + if ( T <= SeuilHarris /*&& XnR > MxNBarreR*/ ) { + Spx->VariableEntrante = Var; MxNBarreR = XnR; + return; /* Priorite aux variables non bornees */ + } + continue; + } + else { /* La variable est faisable BORNEE_INFERIEUREMENT son cout reduit est >= -Seuil */ + if ( CBarre[Var] < 0. ) { + T = 0.; + if ( T <= SeuilHarris && XnR > MxNBarreR ) { Spx->VariableEntrante = Var; MxNBarreR = XnR; } + continue; + } + } + } + if ( CBarre[Var] >= 0. ) { + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_POSITIF /* Donc non bornee */ || + TypeDeVariable [Var] == BORNEE_INFERIEUREMENT /* La variable est donc faisable */ ) { + T = fabs( CBarre[Var] / NBarreR[Var] ); + if ( T <= SeuilHarris ) { + if ( TypeDeVariable[Var] == NON_BORNEE ) { + Spx->VariableEntrante = Var; MxNBarreR = XnR; + return; /* Priorite aux variables non bornees */ + } + if ( XnR > MxNBarreR ) { + Spx->VariableEntrante = Var; MxNBarreR = XnR; + } + } + continue; + } + } + } + + } +} + +if ( Spx->VariableEntrante >= 0 ) return; + +/* Il se peut qu'en entrant en base, la variable ne crée pas de nouvelle infaisabilité duale. + Cela signifie que soit elle fait diminuer le nombre de variables infaisables, soit elle ne + le change pas, mais tout ceci sans créer de nouvelles infaisabilités. Ceci ne peut se produire + que si toutes les infaisabilités sont de type DUALE_INFAISABLE_PAR_COUT_REDUIT_NEGATIF sur + des variables bornées inferieurement. Dans ce cas on choisit d'echanger avec la derniere + variable qui devient duale réalisable */ + +Tmax = -LINFINI_SPX; + +if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMAX ) { + /* La variable en base doit sortir de la base vers sa borne sup. pour etre duale realisable (T>=0) */ + for ( i = 0 ; i < iLimite ; i++ ) { + Var = NumerosDesVariables[i]; + if ( NBarreR[Var] < -SeuilDePivot ) { + /* La variable sortante fait augmenter CBarre */ + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_NEGATIF ) { + /* Remarque: la variable est donc bornée inférieurement */ + T = fabs( CBarre[Var] / NBarreR[Var] ); + if ( T > Tmax ) { Tmax = T; Spx->VariableEntrante = Var; } + } + } + } +} + +else if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + /* La variable en base doit sortir de la base vers sa borne inf. pour etre duale realisable (T<=0) */ + for ( i = 0 ; i < iLimite ; i++ ) { + Var = NumerosDesVariables[i]; + if ( NBarreR[Var] >= SeuilDePivot ) { + /* La variable sortante fait augmenter CBarre */ + if ( FaisabiliteDeLaVariable[Var] == DUALE_INFAISABLE_PAR_COUT_REDUIT_NEGATIF ) { + /* Remarque: la variable est donc bornée inférieurement */ + T = fabs( CBarre[Var] / NBarreR[Var] ); + if ( T > Tmax ) { Tmax = T; Spx->VariableEntrante = Var; } + } + } + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_DualPhase1ChoixDeLaVariableEntrante( PROBLEME_SPX * Spx ) +{ + +Spx->VariableEntrante = -1; +SPX_DualPhase1TestDuRatio( Spx ); + +/* Recherche de la variable entrante */ +if ( Spx->VariableEntrante < 0 ) { + /* Problemes numerique: en désespoir de cause, si la variables sortante est bornee, + on tente le changement de borne inverse */ + if ( Spx->TypeDeVariable[Spx->VariableSortante] == BORNEE ) { + if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) Spx->SortSurXmaxOuSurXmin = SORT_SUR_XMAX; + else Spx->SortSurXmaxOuSurXmin = SORT_SUR_XMIN; + printf("Phase 1 iter %d: inversion du type de sortie de la variable sortante \n",Spx->Iteration); + + Spx->FaireScalingLU = NOMBRE_DE_FOIS_SCALING_SI_INVERSION_DE_TYPE_DE_SORTIE; + + SPX_DualPhase1TestDuRatio( Spx ); + if ( Spx->VariableEntrante >= 0 ) { + printf("variable sortante %d poids de la variable sortante %lf contrainte %d\n", + Spx->VariableSortante,Spx->DualPoids[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]], + Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]); + } + else { + printf("pas de variable entrante malgre l'inversion\n"); + } + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_choix_variable_sortante.c b/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_choix_variable_sortante.c new file mode 100644 index 0000000000..effc5a8dd7 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_choix_variable_sortante.c @@ -0,0 +1,193 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Phase 1 de l'algorithme dual, choix de la variable + sortante. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_fonctions.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void SPX_DualPhase1ChoixDeLaVariableSortante( PROBLEME_SPX * Spx ) + +{ +int Cnt; int Var; double AbsV; double MxAbsV; double * V; double * DualPoids; +char * TypeDeVariable; int * VariableEnBaseDeLaContrainte; +int VariableSortante; int SortSurXmaxOuSurXmin; +int NombreDeContraintes; + +Spx->VariableSortante = -1; +MxAbsV = -1.; +V = Spx->V; +DualPoids = Spx->DualPoids; +TypeDeVariable = Spx->TypeDeVariable; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +NombreDeContraintes = Spx->NombreDeContraintes; + +VariableSortante = -1; +SortSurXmaxOuSurXmin = SORT_PAS; + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + + Var = VariableEnBaseDeLaContrainte[Cnt]; + + /* Une variable non bornee ne sort pas de la base */ + if ( TypeDeVariable[Var] == NON_BORNEE ) continue; + + + /* Si une variable est non bornee superieurement, elle ne peut pas sortir de la base + si Spx->V est negatif. En effet cela conduirait a un cout reduit negatif pour + cette variable et il faudrait qu'elle sorte sur borne max. ce qui n'est pas possible */ + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + if ( V[Cnt] <= 0. ) continue; + } + + /* La variable est donc bornee ( des 2 cotes ou seulement bornee inferieurement ) */ + AbsV = fabs( V[Cnt] ); + AbsV = AbsV * AbsV / DualPoids[Cnt]; + if ( AbsV > MxAbsV ) { + VariableSortante = Var; + MxAbsV = AbsV; + if ( V[Cnt] >= 0. ) SortSurXmaxOuSurXmin = SORT_SUR_XMIN; + else SortSurXmaxOuSurXmin = SORT_SUR_XMAX; + } + +} + +Spx->VariableSortante = VariableSortante; +Spx->SortSurXmaxOuSurXmin = SortSurXmaxOuSurXmin; + +/* Traces */ +/* +if ( Spx->VariableSortante >= 0 ) { + if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + printf(" -> Iter %d variable sortante %d poids %lf contrainte associee %d V %lf SORT_SUR_XMIN", + Spx->Iteration, + Spx->VariableSortante, + Spx->DualPoids[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]], + Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante], + MxAbsV ); + } + else if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMAX ) { + printf(" -> Iter %d variable sortante %d poids %lf contrainte associee %d V %lf SORT_SUR_XMAX", + Spx->Iteration, + Spx->VariableSortante, + Spx->DualPoids[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]], + Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante], + -MxAbsV ); + } + else { + printf("Bug dans l algorithme dual, sous-programme SPX_DualChoixDeLaVariableKiKitLaBase\n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx, Spx->AnomalieDetectee ); + } + if ( Spx->TypeDeVariable[Spx->VariableSortante] == BORNEE ) + printf(" type variable sortante: BORNEE min %e max %e\n",Spx->Xmin[Spx->VariableSortante],Spx->Xmax[Spx->VariableSortante]); + if ( Spx->TypeDeVariable[Spx->VariableSortante] == BORNEE_INFERIEUREMENT ) + printf(" type de la variable sortante: BORNEE_INFERIEUREMENT\n"); + fflush(stdout); +} +*/ +/* Fin traces */ + +return; + +} + +/*----------------------------------------------------------------------------*/ + +void SPX_DualPhase1ChoixDeLaVariableSortanteAuHasard( PROBLEME_SPX * Spx ) + +{ +int Cnt; int Var; int NombreDeVariablesCandidates; int Nombre; double X; +int * VariableCandidate; + +VariableCandidate = (int *) malloc( Spx->NombreDeContraintes * sizeof( int ) ); +if ( VariableCandidate == NULL ) { + printf(" Simplexe: memoire insuffisante dans SPX_DualPhase1ChoixDeLaVariableSortanteAuHasard\n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); +} + +Spx->VariableSortante = -1; +NombreDeVariablesCandidates = 0; + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + Var = Spx->VariableEnBaseDeLaContrainte[Cnt]; + + if ( Spx->TypeDeVariable[Var] == NON_BORNEE ) continue; /* Une variable libre ne sort pas de la base */ + + /* Si une variable est non bornee superieurement, elle ne peut pas sortir de la base + si Spx->V est negatif. En effet cela conduirait a un cout reduit negatif pour + cette variable et il faudrait qu'elle sorte sur borne max. ce qui n'est pas possible */ + if ( Spx->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + if ( Spx->V[Cnt] <= 0. ) continue; + } + + if ( fabs( Spx->V[Cnt] ) < 1.e-7/*6*/ ) continue; + + VariableCandidate[NombreDeVariablesCandidates] = Var; + NombreDeVariablesCandidates++; +} + +#if VERBOSE_SPX + printf("SPX_DualPhase1ChoixDeLaVariableSortanteAuHasard NombreDeVariablesCandidates %d\n",NombreDeVariablesCandidates); +#endif + +if ( NombreDeVariablesCandidates > 0 ) { + /* On tire un nombre au hasard compris entre 0 et NombreDeVariablesCandidates - 1 */ + + # if UTILISER_PNE_RAND == OUI_SPX + Spx->A1 = PNE_Rand( Spx->A1 ); + X = Spx->A1 * (NombreDeVariablesCandidates - 1); + # else + X = rand() * Spx->UnSurRAND_MAX * (NombreDeVariablesCandidates - 1); + # endif + + Nombre = (int) X; + if ( Nombre >= NombreDeVariablesCandidates - 1 ) Nombre = NombreDeVariablesCandidates - 1; + + Spx->VariableSortante = VariableCandidate[Nombre]; + + Cnt = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; + if ( Spx->V[Cnt] >= 0. ) Spx->SortSurXmaxOuSurXmin = SORT_SUR_XMIN; + else Spx->SortSurXmaxOuSurXmin = SORT_SUR_XMAX; +} +/* +printf("Nouveau choix de variable sortante %d Spx->V[Cnt] %lf \n",Spx->VariableSortante,Spx->V[Cnt]); +*/ +free( VariableCandidate ); + +return; + +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_positionner_les_variables.c b/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_positionner_les_variables.c new file mode 100644 index 0000000000..fff760e450 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_positionner_les_variables.c @@ -0,0 +1,266 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Phase 1 dans le cas ou la base de depart n'est pas fournie. + On positionne correctement les variables hors base compte + tenu de la crash base que l'on a determinee ou bien des + valeurs de couts reduits a la fin d'une iteration de phase 1. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define CYCLE_DAFFICHAGE 100 + +/*----------------------------------------------------------------------------*/ + +void SPX_DualPhase1PositionnerLesVariablesHorsBase( PROBLEME_SPX * Spx ) +{ +int Var; double SommeDesInfaisabilites; char * PositionDeLaVariable; int i; +int * NumerosDesVariablesHorsBase; char * FaisabiliteDeLaVariable; char * TypeDeVariable; +double * CBarre; int NbInfaisabilitesDuales; double * SeuilDAmissibiliteDuale; +# if VERBOSE_SPX + int NN; +# endif + +NbInfaisabilitesDuales = 0; +SommeDesInfaisabilites = 0.0; + +if ( Spx->LaBaseDeDepartEstFournie == NON_SPX ) SeuilDAmissibiliteDuale = Spx->SeuilDAmissibiliteDuale1; +else SeuilDAmissibiliteDuale = Spx->SeuilDAmissibiliteDuale2; + +PositionDeLaVariable = Spx->PositionDeLaVariable; +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +FaisabiliteDeLaVariable = Spx->FaisabiliteDeLaVariable; +TypeDeVariable = Spx->TypeDeVariable; +CBarre = Spx->CBarre; + +/* Boucle sur les variables hors base */ +for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + + FaisabiliteDeLaVariable[Var] = DUALE_FAISABLE; + + /* Examen des couts reduits pour chaque type de variable */ + if ( TypeDeVariable[Var] == BORNEE ) { + if ( CBarre[Var] > SeuilDAmissibiliteDuale[Var] ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + } + else if ( CBarre[Var] < -SeuilDAmissibiliteDuale[Var] ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_SUP; + } + /* Remarque importante: lorsque la base de depart n'est pas fournie, on met initialement toutes les variables hors base + a HORS_BASE_SUR_BORNE_INF donc si les 2 tests ci-dessus ne positionne pas la variable c'est qu'elle est bien + positionnee */ + continue; + } + + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + if ( CBarre[Var] < -SeuilDAmissibiliteDuale[Var] ) { + SommeDesInfaisabilites+= CBarre[Var]; + PositionDeLaVariable [Var] = HORS_BASE_SUR_BORNE_SUP; + FaisabiliteDeLaVariable[Var] = DUALE_INFAISABLE_PAR_COUT_REDUIT_NEGATIF; + NbInfaisabilitesDuales++; + } + continue; + } + + if ( TypeDeVariable[Var] == NON_BORNEE ) { + PositionDeLaVariable[Var] = HORS_BASE_A_ZERO; + /* La variable est duale realisable si son cout reduit est nul */ + if ( CBarre[Var] < -SeuilDAmissibiliteDuale[Var] ) { + SommeDesInfaisabilites+= CBarre[Var]; + PositionDeLaVariable [Var] = HORS_BASE_SUR_BORNE_SUP; /* Donc infaisable */ + FaisabiliteDeLaVariable[Var] = DUALE_INFAISABLE_PAR_COUT_REDUIT_NEGATIF; + NbInfaisabilitesDuales++; + continue; + } + if ( CBarre[Var] > SeuilDAmissibiliteDuale[Var] ) { + SommeDesInfaisabilites-= CBarre[Var]; + PositionDeLaVariable [Var] = HORS_BASE_SUR_BORNE_INF; /* Donc infaisable */ + FaisabiliteDeLaVariable[Var] = DUALE_INFAISABLE_PAR_COUT_REDUIT_POSITIF; + NbInfaisabilitesDuales++; + continue; + } + } + +} + +Spx->SommeDesInfaisabilitesDuales = -SommeDesInfaisabilites; +Spx->NbInfaisabilitesDuales = NbInfaisabilitesDuales; + +if ( Spx->Iteration == 1 ) Spx->NbInfaisabilitesDualesALaPremiereIteration = NbInfaisabilitesDuales; + +/* Traces */ +if ( Spx->NbCycles == 0 || Spx->NbCycles >= CYCLE_DAFFICHAGE ) { + #if VERBOSE_SPX + if ( Spx->LaBaseDeDepartEstFournie == OUI_SPX ) { + printf("Base de depart fournie, nombre d'infaisabilites %6d , somme des infaisabilites duales %15.8lf\n",Spx->NbInfaisabilitesDuales,-SommeDesInfaisabilites); + } + else { + printf("Iteration %6d nombre d'infaisabilites %6d , somme des infaisabilites duales %15.8lf\n",Spx->Iteration,Spx->NbInfaisabilitesDuales, + -SommeDesInfaisabilites); + } + #else + /* Cas non verbose */ + if ( Spx->LaBaseDeDepartEstFournie == NON_SPX && Spx->AffichageDesTraces == OUI_SPX ) { /* Premier simplexe */ + if ( Spx->EcrireLegendePhase1 == OUI_SPX ) { + Spx->EcrireLegendePhase1 = NON_SPX; + Spx->EcrireLegendePhase2 = OUI_SPX; + printf(" "); + printf(" | Phase |"); + printf(" Iteration |"); + printf(" Dual infeas. count |"); + printf(" Dual infeas. |"); + printf("\n"); + } + printf(" "); + printf(" | I |"); + printf(" %6d |",Spx->Iteration); + printf(" %7d |",Spx->NbInfaisabilitesDuales); + printf(" %15.8e |",-SommeDesInfaisabilites); + printf("\n"); + } + #endif + Spx->NbCycles = 0; + + # if VERBOSE_SPX + if ( Spx->NbInfaisabilitesDuales == 1 ) { + NN = 0; + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if (Spx->PositionDeLaVariable[Var] == EN_BASE_LIBRE ) continue; + if ( FaisabiliteDeLaVariable[Var] != DUALE_FAISABLE ) { + NN++; + printf("positionner variables Iteration %d Var %d CNbTerm %d CBarre %e Xmin %e Xmax %e\n", + Spx->Iteration, Var,Spx->CNbTerm[Var],CBarre[Var],Spx->Xmin[Var],Spx->Xmax[Var]); + } + } + } + # endif + +} +Spx->NbCycles++; + +/* Fin traces */ + +return; +} + +# ifdef UTILISER_BORNES_AUXILIAIRES + +/*----------------------------------------------------------------------------*/ +/* Utilisation de bornes auxilaires pour forcer l'admissibilite duale */ +void SPX_DualPhase1UtiliserLesBornesAuxiliaires( PROBLEME_SPX * Spx ) +{ +int Var; char * PositionDeLaVariable; int i; double * CBarre; +int * NumerosDesVariablesHorsBase; char * FaisabiliteDeLaVariable; double * Xmax; +char * TypeDeVariable; char * StatutBorneSupCourante; double * Xmin; +double * SeuilDAmissibiliteDuale; + +if ( Spx->LaBaseDeDepartEstFournie == NON_SPX ) SeuilDAmissibiliteDuale = Spx->SeuilDAmissibiliteDuale1; +else SeuilDAmissibiliteDuale = Spx->SeuilDAmissibiliteDuale2; + +PositionDeLaVariable = Spx->PositionDeLaVariable; +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +FaisabiliteDeLaVariable = Spx->FaisabiliteDeLaVariable; +TypeDeVariable = Spx->TypeDeVariable; +CBarre = Spx->CBarre; + +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +Xmax = Spx->Xmax; +Xmin = Spx->Xmin; + +/* Boucle sur les variables hors base */ +for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + + FaisabiliteDeLaVariable[Var] = DUALE_FAISABLE; + + /* Examen des couts reduits pour chaque type de variable */ + if ( TypeDeVariable[Var] == BORNEE ) { + if ( CBarre[Var] > SeuilDAmissibiliteDuale[Var] ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + } + else if ( CBarre[Var] < -SeuilDAmissibiliteDuale[Var] ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_SUP; + } + /* Remarque importante: lorsque la base de part n'est pas fournie, on met initialement toutes les variables hors base + a HORS_BASE_SUR_BORNE_INF donc si les 2 tests ci-dessus ne positionne pas la variable c'est qu'elle est bien + positionnee */ + continue; + } + + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + /* La variable est duale realisable si son cout reduit est positif */ + if ( CBarre[Var] < -SeuilDAmissibiliteDuale[Var] ) { + PositionDeLaVariable [Var] = HORS_BASE_SUR_BORNE_SUP; + TypeDeVariable [Var] = BORNEE; + StatutBorneSupCourante[Var] = BORNE_AUXILIAIRE_DE_VARIABLE_BORNEE_INFERIEUREMENT; + Xmax [Var] = SPX_CalculerUneBorneAuxiliaire( Spx, Var ); + Spx->NombreDeBornesAuxiliairesUtilisees++; + } + continue; + } + + if ( TypeDeVariable[Var] == NON_BORNEE ) { + PositionDeLaVariable[Var] = HORS_BASE_A_ZERO; + /* La variable est duale realisable si son cout reduit est nul */ + if ( CBarre[Var] < -SeuilDAmissibiliteDuale[Var] ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_SUP; + TypeDeVariable [Var] = BORNEE; + StatutBorneSupCourante[Var] = BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE; + Xmax [Var] = SPX_CalculerUneBorneAuxiliaire( Spx, Var ); + Xmin[Var] = 0.; + Spx->NombreDeBornesAuxiliairesUtilisees++; + continue; + } + if ( CBarre[Var] > SeuilDAmissibiliteDuale[Var] ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + TypeDeVariable [Var] = BORNEE; + StatutBorneSupCourante[Var] = BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE; + Xmax[Var] = SPX_CalculerUneBorneAuxiliaire( Spx, Var ); + Xmin[Var] = 0.; + Spx->NombreDeBornesAuxiliairesUtilisees++; + continue; + } + } +} + +Spx->SommeDesInfaisabilitesDuales = 0.0; +Spx->NbInfaisabilitesDuales = 0; + +#if VERBOSE_SPX + printf("Nombre de bornes auxiliaires utilisees %d\n",Spx->NombreDeBornesAuxiliairesUtilisees); +#endif + +return; +} + +# endif + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_simplexe.c b/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_simplexe.c new file mode 100644 index 0000000000..f282172609 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_phase_1_simplexe.c @@ -0,0 +1,308 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Phase 1 de l'algorithme dual du simplexe: recherche d'une + solution duale admissible. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_DualPhase1Simplexe( PROBLEME_SPX * Spx ) + +{ +char ModifCoutsAutorisee; int CntBase; double MoyenneSommeDesInfaisabilites; +double BufferSommeDesInfaisabilites; int CycleDeCalculDeLaMoyenne; int NbCycles; +char PositionDeLaVariable; char FactoriserLaBase; int Var; +char ControlerAdmissibiliteDuale; + +#if VERBOSE_SPX + printf("Entree dans la phase 1 de l algorithme dual du simplexe\n"); +#endif + +Spx->SeuilDePivotDual = VALEUR_DE_PIVOT_ACCEPTABLE; + +Spx->PhaseEnCours = PHASE_1; + +Spx->EcrireLegendePhase1 = OUI_SPX; + +ModifCoutsAutorisee = Spx->ModifCoutsAutorisee; +/* Attention remettre ensuite la valeur d'origine */ +Spx->ModifCoutsAutorisee = NON_SPX; + +Spx->LaBaseEstDualeAdmissible = NON_SPX; +Spx->Iteration = 0; +/*Spx->NombreDeChangementsDeBase = 0;*/ +/*Spx->LastEta = -1;*/ + +Spx->CalculerCBarre = OUI_SPX; + +Spx->ChoixDeVariableSortanteAuHasard = NON_SPX; +Spx->NombreMaxDeChoixAuHasard = 5; +Spx->NombreDeChoixFaitsAuHasard = 0; +Spx->FaireDuRaffinementIteratif = 0; +MoyenneSommeDesInfaisabilites = -LINFINI_SPX; +BufferSommeDesInfaisabilites = 0.; + +NbCycles = 0; +CycleDeCalculDeLaMoyenne = 5/*6*/; + +while ( 1 ) { + + Debut: + Spx->Iteration++; + Spx->FaireChangementDeBase = OUI_SPX; + Spx->NbBoundFlip = 0; + + if ( Spx->FaireDuRaffinementIteratif > 0 ) Spx->FaireDuRaffinementIteratif--; + + /* + printf("*** Iteration %d dans la phase 1 l'algorithme dual\n",Spx->Iteration); + */ + + if ( Spx->DureeMaxDuCalcul > 0 ) SPX_ControleDuTempsEcoule( Spx ); + + if ( Spx->Iteration > Spx->NombreMaxDIterations ) { /* Clause de sortie */ + Spx->LaBaseEstDualeAdmissible = NON_SPX; + break; + } + + if ( Spx->CalculerCBarre == OUI_SPX ) { + SPX_CalculerPi( Spx ); /* Calcul de Pi = c_B * B^{-1} */ + SPX_CalculerLesCoutsReduits( Spx ); /* Calcul de CBarre = c_N - < Pi , N > */ + Spx->CalculerCBarre = NON_SPX; + } + + /* On positionne les variables bornees en fonction de leur cout reduit et on + on determine les infaisabilites sur les variables non bornees d'un seul + ou des deux cotes */ + SPX_DualPhase1PositionnerLesVariablesHorsBase( Spx ); + if ( Spx->NbInfaisabilitesDuales == 0 ) { + /* La solution est duale admissible */ + #if VERBOSE_SPX + printf( "Simplexe dual phase 1: admissibilite duale atteint en %d iterations\n",Spx->Iteration-1); + #endif + Spx->LaBaseEstDualeAdmissible = OUI_SPX; + break; + } + + # ifdef UTILISER_BORNES_AUXILIAIRES + if ( Spx->Iteration > Spx->IterationPourBornesAuxiliaires ) { + /* On utilise les bornes auxiliaires pour obtenir l'admissibilite duale */ + SPX_DualPhase1UtiliserLesBornesAuxiliaires( Spx ); + if ( Spx->NbInfaisabilitesDuales == 0 ) { + /* La solution est duale admissible */ + #if VERBOSE_SPX + printf( "Simplexe dual phase 1: admissibilite duale atteint en %d iterations\n",Spx->Iteration-1); + #endif + Spx->LaBaseEstDualeAdmissible = OUI_SPX; + break; + } + } + # endif + + NbCycles++; + BufferSommeDesInfaisabilites+= Spx->SommeDesInfaisabilitesDuales; + if ( NbCycles == CycleDeCalculDeLaMoyenne ) { + BufferSommeDesInfaisabilites/= (double) NbCycles; + if ( fabs ( MoyenneSommeDesInfaisabilites - BufferSommeDesInfaisabilites ) < 1.e-6 && 0 ) { + /* Cyclage */ + #if VERBOSE_SPX + printf( "Simplexe dual phase 1: suspiscion de cyclage => on initialise une phase de tirages au hasard\n"); + printf( "MoyenneSommeDesInfaisabilites %e BufferSommeDesInfaisabilites %e\n",MoyenneSommeDesInfaisabilites,BufferSommeDesInfaisabilites); + #endif + + printf( "Simplexe dual phase 1: suspiscion de cyclage => on initialise une phase de tirages au hasard\n"); + printf( "MoyenneSommeDesInfaisabilites %e BufferSommeDesInfaisabilites %e\n",MoyenneSommeDesInfaisabilites,BufferSommeDesInfaisabilites); + + Spx->ChoixDeVariableSortanteAuHasard = OUI_SPX; + Spx->NombreMaxDeChoixAuHasard = 2; + Spx->NombreDeChoixFaitsAuHasard = 0; + } + NbCycles = 0; + MoyenneSommeDesInfaisabilites = BufferSommeDesInfaisabilites; + BufferSommeDesInfaisabilites = 0.; + } + + /* Calcul du vecteur V servant a determiner la variable sortante */ + SPX_DualPhase1CalculerV( Spx ); + /* Choix de la variable sortante */ + if ( Spx->ChoixDeVariableSortanteAuHasard == OUI_SPX ) { + SPX_DualPhase1ChoixDeLaVariableSortanteAuHasard( Spx ); + Spx->NombreDeChoixFaitsAuHasard++; + } + else { + SPX_DualPhase1ChoixDeLaVariableSortante( Spx ); + } + if ( Spx->VariableSortante < 0 ) { + /* Le probleme n'a pas de solution duale admissible */ + #if VERBOSE_SPX + printf("Somme des infaisabilites duales %e\n",Spx->SommeDesInfaisabilitesDuales); + #endif + + # ifdef UTILISER_BORNES_AUXILIAIRES + printf("NbInfaisabilitesDuales %d NbInfaisabilitesDualesALaPremiereIteration %d\n", + Spx->NbInfaisabilitesDuales, Spx->NbInfaisabilitesDualesALaPremiereIteration); + if ( Spx->NbInfaisabilitesDuales < Spx->NbInfaisabilitesDualesALaPremiereIteration ) { + /* On utilise les bornes auxiliaires pour obtenir l'admissibilite duale */ + SPX_DualPhase1UtiliserLesBornesAuxiliaires( Spx ); + if ( Spx->NbInfaisabilitesDuales == 0 ) { + /* La solution est duale admissible */ + #if VERBOSE_SPX + printf( "Simplexe dual phase 1: admissibilite duale atteint en %d iterations\n",Spx->Iteration-1); + #endif + Spx->LaBaseEstDualeAdmissible = OUI_SPX; + } + } + else Spx->LaBaseEstDualeAdmissible = NON_SPX; + # else + Spx->LaBaseEstDualeAdmissible = NON_SPX; + # endif + + break; + } + + if ( Spx->NombreDeChoixFaitsAuHasard >= Spx->NombreMaxDeChoixAuHasard ) { + Spx->ChoixDeVariableSortanteAuHasard = NON_SPX; + Spx->NombreDeChoixFaitsAuHasard = 0; + } + + /* Calcul de la ligne du tableau pour la variable sortante */ + SPX_DualCalculerNBarreR( Spx, NON_SPX, &ControlerAdmissibiliteDuale ); + /* On verifie s'il faut refactoriser la base */ + FactoriserLaBase = Spx->FactoriserLaBase; /* Sauvegarde du verdict en cours */ + Spx->FactoriserLaBase = NON_SPX; + SPX_DualVerifierErBMoinsUn( Spx ); + if ( Spx->FactoriserLaBase == OUI_SPX ) { + SPX_FactoriserLaBase( Spx ); + Spx->CalculerCBarre = OUI_SPX; + goto Debut; + } + Spx->FactoriserLaBase = FactoriserLaBase; + + /* Choix de la variable entrante */ + SPX_DualPhase1ChoixDeLaVariableEntrante( Spx ); + if ( Spx->VariableEntrante < 0 && Spx->SommeDesInfaisabilitesDuales < SEUIL_ADMISSIBILITE_DUALE_2 ) { + /* Mais il faut tout de meme positionner correctement les variables */ + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + PositionDeLaVariable = Spx->PositionDeLaVariable[Var]; + if ( PositionDeLaVariable == HORS_BASE_SUR_BORNE_INF || + PositionDeLaVariable == HORS_BASE_SUR_BORNE_SUP || + PositionDeLaVariable == HORS_BASE_A_ZERO ) { + if ( Spx->TypeDeVariable[Var] == NON_BORNEE ) Spx->PositionDeLaVariable[Var] = HORS_BASE_A_ZERO; + else if ( Spx->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) Spx->PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + } + } + /* On accepte quand meme la solution */ + Spx->LaBaseEstDualeAdmissible = OUI_SPX; + break; + } + else if ( Spx->VariableEntrante < 0 ) { + #if VERBOSE_SPX + printf("Probleme de precision dans la phase 1 iteration %d de l'algorithme dual: il doit toujours y avoir une variable entrante\n",Spx->Iteration); + #endif + + # ifdef UTILISER_BORNES_AUXILIAIRES + /* Si on utilise les bornes auxilaires, on modifie le numero d'iteration et on repart au + debit d'une afin d'activer la creation de bornes */ + SPX_FactoriserLaBase( Spx ); + Spx->CalculerCBarre = OUI_SPX; + Spx->Iteration = Spx->IterationPourBornesAuxiliaires; + goto Debut; + # else + /* Attention, il faut controler la precision: on tente au hasard 2 fois */ + /* Le choix au hasard n'est pas la bonne solution, le mieux est de choisir une autre variable + sortante parmis celles qui le peuvent, et ceci dans l'ordre de préséance */ + SPX_FactoriserLaBase( Spx ); + Spx->ChoixDeVariableSortanteAuHasard = OUI_SPX; + Spx->NombreMaxDeChoixAuHasard = 2; + Spx->NombreDeChoixFaitsAuHasard = 0; + Spx->CalculerCBarre = OUI_SPX; /* Pour affiner le calcul des couts reduits */ + goto Debut; + # endif + + } + + if ( Spx->UtiliserLaLuUpdate == NON_SPX ) { + if ( Spx->NombreDeChangementsDeBase == Spx->CycleDeRefactorisation ) Spx->FactoriserLaBase = OUI_SPX; + } + + SPX_CalculerABarreS( Spx ); /* Car on en a aussi besoin pour faire le changement de base et pour le steepest edge */ + /* On verifie s'il faut refactoriser la base */ + SPX_VerifierABarreS( Spx ); + if ( Spx->FactoriserLaBase == NON_SPX ) { + /* Si la factoristion de la base n'est pas encore prévue, on fait ici la mise a jour + des couts reduits. En effet, si une factorisation de la base est effectuee lors + du changement de base effectif, l'indicateur Spx->CalculerCBarre est positionne + a OUI_SPX ce qui provoque un calcul de couts reduits au debut du while */ + + SPX_DualComparerABarreSEtNBarreR( Spx ); + if ( Spx->FaireChangementDeBase == NON_SPX ) goto Debut; + + /* Mise a jour des couts reduits */ + CntBase = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; + SPX_MettreAJourLesCoutsReduits( Spx ); + } + + /* Mise a jour des poids de la methode projected steepest edge */ + SPX_MajPoidsDualSteepestEdge( Spx ); + + /* On effectue le changement de base et eventuellement un refactorisation de la base */ + SPX_FaireLeChangementDeBase( Spx ); + + /* Apres chaque chagement de base reussi on essaie de revenir au seuil de pivotage initial */ + if ( Spx->SeuilDePivotDual > VALEUR_DE_PIVOT_ACCEPTABLE ) { + Spx->SeuilDePivotDual /= DIVISEUR_VALEUR_DE_PIVOT_ACCEPTABLE; + if ( Spx->SeuilDePivotDual < VALEUR_DE_PIVOT_ACCEPTABLE ) Spx->SeuilDePivotDual = VALEUR_DE_PIVOT_ACCEPTABLE; + } + +} + +Spx->ModifCoutsAutorisee = ModifCoutsAutorisee; + +/* Remarque: si, a ce stade, on stocke la base courante pour en faire une base de redemarrage + en cas de pivot nul, on n'est pas certain qu'elle soit inversible. On prefere conserver + la derniere base inversible obtenue meme si elle n'est pas completement duale realisable. + De toute facon, il y a le controle cyclique d'admissibilite duale dans la phase 2 du + simplexe dual */ +/* Mais attention, il faut quand meme mettre l'indicateur de PositionDeLaVariable d'aplomb */ + +/* En realite c'est surtout utile pour le cas des bornes auxiliaires */ + +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + PositionDeLaVariable = Spx->PositionDeLaVariableSV[Var]; + if ( PositionDeLaVariable == HORS_BASE_SUR_BORNE_INF || + PositionDeLaVariable == HORS_BASE_SUR_BORNE_SUP || + PositionDeLaVariable == HORS_BASE_A_ZERO ) goto OnCalcule; + continue; + /* La variable est hors base */ + OnCalcule: + if ( Spx->TypeDeVariable[Var] == NON_BORNEE ) Spx->PositionDeLaVariableSV[Var] = HORS_BASE_A_ZERO; + else if ( Spx->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) Spx->PositionDeLaVariableSV[Var] = HORS_BASE_SUR_BORNE_INF; +} + +return; + +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_pivotages_complementaires.c b/src/ext/Sirius_Solver/simplexe/spx_dual_pivotages_complementaires.c new file mode 100644 index 0000000000..94e6930c01 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_pivotages_complementaires.c @@ -0,0 +1,389 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On fait des pivotages supplementaires pour essayer de + sortir de la base le plus grand nombre possible de + variables entieres. Ce n'est interessant que s'il y a + beaucoup de variables hors base avec un cout reduit nul. + Dans ce cas on peut esperer faire des pivotages sans faire + varier la fonction cout. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# define SEUIL_VARIABLES_DEGENEREES 50.0 +# define VALEUR_DE_ZERO 1.e-9 + +# ifdef PIVOTAGES_COMPLEMENTAIRES + +/*----------------------------------------------------------------------------*/ + +void SPX_DualPivotagesComplementaires( PROBLEME_SPX * Spx ) +{ +int Var; int Var1; double Amx; int Cnt; int il ; int ilMax; double S; +int ic ;int NombreDeVariables; int NbVarACoutReduitNul; +char * PositionDeLaVariable; double * CBarre; double Xs; int NombreDeContraintes; +int NombreDeVariablesEntieres; double * Xmin; double * Xmax; char * VariableEntiere; +double * ScaleX; int j; int i; int Count; +int * NumerosDesVariablesHorsBase; int * NumeroDesVariableATester; +double * NBarreRHorsBase; double * BBarre; double SupXmax; +int VariableSortante; char SortSurXmaxOuSurXmin; double Ec; double X; +int * VariableEnBaseDeLaContrainte; double Ecart; double SeuilHarris; int iChoisi; +char * TypeDeVariable; double NBarreRMx; double * ABarreS; +double BBarreDeCntBase; int CntBase; int * ContrainteDeLaVariableEnBase; +char * SortieDeBasePossible; int NbPivotages; double NBarreR; char Position; int CountVarEnt; +double FractionnaliteMoyenne; int Nn; int * CntDeABarreSNonNuls; + + +printf("DualPivotagesComplementaires a revoir en fonction de base reduite ou complete\n"); +return; + + +NombreDeVariables = Spx->NombreDeVariables; +NombreDeContraintes = Spx->NombreDeContraintes; +PositionDeLaVariable = Spx->PositionDeLaVariable; +CBarre = Spx->CBarre; + +/* Detection presence de variables entieres */ +NbVarACoutReduitNul = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( PositionDeLaVariable[Var] == EN_BASE_LIBRE ) continue; + if ( fabs( CBarre[Var] ) < SEUIL_DE_DEGENERESCENCE_DUAL ) NbVarACoutReduitNul++; +} + +Xs = (double) NbVarACoutReduitNul * 100./ (double) (NombreDeVariables - NombreDeContraintes); +if ( Xs < SEUIL_VARIABLES_DEGENEREES) return; + +printf("Pourcentage de variables hors base degenerees %f\n",Xs); + +TypeDeVariable = Spx->TypeDeVariable; +NBarreRHorsBase = &Spx->NBarreRHorsBase[1]; +BBarre = Spx->BBarre; +ABarreS = Spx->ABarreS; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; + +NumeroDesVariableATester = Spx->NumeroDesVariableATester; +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; + +/* On repere les variables entieres */ + +VariableEntiere = (char *) malloc( NombreDeVariables * sizeof( char ) ); +SortieDeBasePossible = (char *) malloc( NombreDeVariables * sizeof( char ) ); +Xmin = Spx->Xmin; +Xmax = Spx->Xmax; +ScaleX = Spx->ScaleX; +SupXmax = Spx->SupXmax; +NombreDeVariablesEntieres = 0; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + VariableEntiere[Var] = NON_SPX; + if ( Xmin[Var] != 0.0 ) continue; + if ( fabs( (Xmax[Var] * ScaleX[Var] * SupXmax) - 1.0 ) < VALEUR_DE_ZERO ) { + VariableEntiere[Var] = OUI_SPX; + NombreDeVariablesEntieres++; + } +} + +printf(" NombreDeVariablesEntieres %d\n",NombreDeVariablesEntieres); + +NbPivotages = 0; + +RECHERCHE_VARIABLE_SORTANTE_1: +printf("************** Debut recherche Phase 1 *****************\n"); + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) SortieDeBasePossible[Var] = OUI_SPX; + +RECHERCHE_VARIABLE_SORTANTE_2: +printf("---> Debut recherche Phase 2\n"); +/* On recherche une variable entiere basique eloignee de ses bornes */ +VariableSortante = -1; +Ec = LINFINI_SPX; +FractionnaliteMoyenne = 0.0; +Nn = 0; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + Var = VariableEnBaseDeLaContrainte[Cnt]; + if ( VariableEntiere[Var] == NON_SPX ) continue; + if ( SortieDeBasePossible[Var] == NON_SPX ) continue; + X = BBarre[Cnt]; + if ( fabs( X - Xmin[Var] ) < VALEUR_DE_ZERO ) continue; + if ( fabs( Xmax[Var] - X ) < VALEUR_DE_ZERO ) continue; + + + if ( X < Xmin[Var] - 1.e-6 ) {printf(" X %e Xmin %e Xmax %e\n",X,Xmin[Var],Xmax[Var] ); exit(0);} + if ( X > Xmax[Var] + 1.e-6 ) {printf(" X %e Xmin %e Xmax %e\n",X,Xmin[Var],Xmax[Var] ); exit(0);} + + + Xs = 0.5 * ( Xmax[Var] + Xmin[Var] ); + + + Xs*= ScaleX[Var] * SupXmax; + X*= ScaleX[Var] * SupXmax; + + if ( X < Xs ) FractionnaliteMoyenne+= X - (Xmin[Var] * ScaleX[Var] * SupXmax); + else FractionnaliteMoyenne+= (Xmax[Var] * ScaleX[Var] * SupXmax) - X; + Nn++; + + Ecart = fabs( X - Xs ); + if ( Ecart < Ec ) { + VariableSortante = Var; + if ( X < Xs ) SortSurXmaxOuSurXmin = SORT_SUR_XMIN; + else SortSurXmaxOuSurXmin = SORT_SUR_XMAX; + Ec = Ecart; + } +} + +if ( VariableSortante < 0 ) { + printf(" Pas de variable sortante\n"); + goto FIN_PIVOTAGES; + return; +} +Spx->VariableSortante = VariableSortante; +Spx->SortSurXmaxOuSurXmin = SortSurXmaxOuSurXmin; +SortieDeBasePossible[VariableSortante] = NON_SPX; + +CntBase = ContrainteDeLaVariableEnBase[VariableSortante]; +BBarreDeCntBase = BBarre[CntBase]; +printf("Variable sortante %d valeur %e min %e max %e", + VariableSortante,BBarreDeCntBase * ScaleX[VariableSortante] * SupXmax, + Xmin[VariableSortante] * ScaleX[VariableSortante] * SupXmax, + Xmax[VariableSortante] * ScaleX[VariableSortante] * SupXmax); +if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) printf(" SORT_SUR_XMIN\n"); +else printf(" SORT_SUR_XMAX\n"); + +printf("Fractionnalite moyenne %e\n",FractionnaliteMoyenne/Nn); + +/* On fait un test du ratio */ + +SPX_DualCalculerNBarreR( Spx , NON_SPX ); + +/* Construction des candidats */ +j = 0; +for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + if ( fabs( NBarreRHorsBase[i] ) < VALEUR_DE_PIVOT_ACCEPTABLE ) continue; + Var = NumerosDesVariablesHorsBase[i]; + /* On ne fait pas entrer de variables entieres dans la base */ + if ( VariableEntiere[Var] == OUI_SPX ) continue; + /* On ne veut que des variables degenerees */ + if ( fabs( CBarre[Var] ) > SEUIL_DE_DEGENERESCENCE_DUAL ) continue; + Position = PositionDeLaVariable[Var]; + NBarreR = NBarreRHorsBase[i]; + /* On ne recherche que les positions degenerees pour lesquelles le deplacement a des + chances de rester admissible */ + if ( SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + if ( Position == HORS_BASE_SUR_BORNE_INF && NBarreR < 0.0 ) continue; + if ( Position == HORS_BASE_SUR_BORNE_SUP && NBarreR > 0.0 ) continue; + } + else { /* La variable sort sur XMAX */ + if ( Position == HORS_BASE_SUR_BORNE_INF && NBarreR > 0.0 ) continue; + if ( Position == HORS_BASE_SUR_BORNE_SUP && NBarreR < 0.0 ) continue; + } + if ( Position == HORS_BASE_SUR_BORNE_INF || Position == HORS_BASE_SUR_BORNE_SUP ) { + NumeroDesVariableATester[j] = i; + j++; + } + else { + /* On est dans la cas d'une variable non bornee */ + NumeroDesVariableATester[0] = i; + j = 1; + break; + } +} + +Spx->NombreDeVariablesATester = j; + +if ( Spx->NombreDeVariablesATester <= 0 ) { + printf("echec sur NombreDeVariablesATester\n"); + goto RECHERCHE_VARIABLE_SORTANTE_2; + return; /* On risque de perdre du temps */ +} + +/* Choix de la variable entrante */ +CountVarEnt = -1; + +RECHERCHE_VARIABLE_ENTRANTE: +CountVarEnt++; +if ( CountVarEnt > 20 /* Spx->NombreDeVariablesATester */ ) Spx->NombreDeVariablesATester = 0; + +iChoisi = -1; +NBarreRMx = -LINFINI_SPX; +for ( j = 0 ; j < Spx->NombreDeVariablesATester ; j++ ) { + i = NumeroDesVariableATester[j]; + if ( i < 0 ) continue; + if ( fabs( NBarreRHorsBase[i] ) > NBarreRMx ) { + NBarreRMx = fabs( NBarreRHorsBase[i] ); + iChoisi = j; + Spx->VariableEntrante = i; + } +} + +if ( iChoisi < 0 ) { + printf("echec pivot variable entrante instable\n"); + goto RECHERCHE_VARIABLE_SORTANTE_2; +} +NumeroDesVariableATester[iChoisi] = -1; + +NBarreR = NBarreRHorsBase[Spx->VariableEntrante]; +Spx->VariableEntrante = NumerosDesVariablesHorsBase[Spx->VariableEntrante]; + +printf("Variable entrante %d CBarre %e",Spx->VariableEntrante,Spx->CBarre[Spx->VariableEntrante]); +if ( PositionDeLaVariable[Spx->VariableEntrante] == HORS_BASE_SUR_BORNE_INF ) printf(" position HORS_BASE_SUR_BORNE_INF\n"); +if ( PositionDeLaVariable[Spx->VariableEntrante] == HORS_BASE_SUR_BORNE_SUP ) printf(" position HORS_BASE_SUR_BORNE_SUP\n"); +if ( PositionDeLaVariable[Spx->VariableEntrante] == HORS_BASE_A_ZERO ) printf(" position HORS_BASE_A_ZERO\n"); + +/* Calcul du deplacement primal sur la variable entrante */ +Spx->ChangementDeBase = OUI_SPX; + +if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + /* La variable en base diminue */ + Spx->DeltaXSurLaVariableHorsBase = BBarreDeCntBase / NBarreR; +} +else { /* SORT_SUR_XMAX */ + /* La variable en base augmente */ + Spx->DeltaXSurLaVariableHorsBase = ( BBarreDeCntBase - Xmax[Spx->VariableSortante] ) / NBarreR; +} + +if ( PositionDeLaVariable[Spx->VariableEntrante] == HORS_BASE_SUR_BORNE_INF ) { + if ( Spx->DeltaXSurLaVariableHorsBase < 0.0 ) { + printf("echec variable entrante HORS_BASE_SUR_BORNE_INF devient infaisable DeltaXSurLaVariableHorsBase %e\n", + Spx->DeltaXSurLaVariableHorsBase); + goto RECHERCHE_VARIABLE_SORTANTE_2; + } + else if ( TypeDeVariable[Spx->VariableEntrante] == BORNEE ) { + if ( Spx->DeltaXSurLaVariableHorsBase > Xmax[Spx->VariableEntrante] ) { + printf("echec bound flip\n"); + goto RECHERCHE_VARIABLE_SORTANTE_2; + } + } +} +if ( PositionDeLaVariable[Spx->VariableEntrante] == HORS_BASE_SUR_BORNE_SUP ) { + if ( Spx->DeltaXSurLaVariableHorsBase > 0.0 ) { + printf("echec variable entrante HORS_BASE_SUR_BORNE_SUP devient infaisable DeltaXSurLaVariableHorsBase %e\n", + Spx->DeltaXSurLaVariableHorsBase); + goto RECHERCHE_VARIABLE_SORTANTE_2; + } + else if ( -Spx->DeltaXSurLaVariableHorsBase > Xmax[Spx->VariableEntrante] ) { + printf("echec bound flip\n"); + goto RECHERCHE_VARIABLE_SORTANTE_2; + } +} + +printf(" VariableEntrante %d pivot %e\n",Spx->VariableEntrante,NBarreRMx); + +SPX_CalculerABarreS( Spx ); /* C'est pour calculer le spike et la maj du steepest edge */ + +/* On verifie si on ne cree pas de contraintes */ + +if ( Spx->TypeDeStockageDeABarreS == VECTEUR_SPX ) { + for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + if ( Cnt == CntBase ) continue; + X = BBarre[Cnt] - ( Spx->DeltaXSurLaVariableHorsBase * ABarreS[Cnt] ); + Var = VariableEnBaseDeLaContrainte[Cnt]; + if ( X < Xmin[Var] - 1.e-7 ) { + printf("Erreur: Spx->DeltaXSurLaVariableHorsBase = %e \n", Spx->DeltaXSurLaVariableHorsBase); + printf(" Var %d X = %e Xmin %e valeur avant %e\n",Var,X,Xmin[Var],BBarre[Cnt]); + goto RECHERCHE_VARIABLE_ENTRANTE; + } + if ( X > Xmax[Var] + 1.e-7 ) { + printf("Erreur: Spx->DeltaXSurLaVariableHorsBase = %e \n", Spx->DeltaXSurLaVariableHorsBase); + printf(" Var %d X = %e Xmax %e valeur avant %e\n",Var,X,Xmax[Var],BBarre[Cnt]); + goto RECHERCHE_VARIABLE_ENTRANTE; + } + } +} +else { + CntDeABarreSNonNuls = Spx->CntDeABarreSNonNuls; + for ( i = 0 ; i < Spx->NbABarreSNonNuls ; i++ ) { + Cnt = CntDeABarreSNonNuls[i]; + if ( Cnt == CntBase ) continue; + X = BBarre[Cnt] - ( Spx->DeltaXSurLaVariableHorsBase * ABarreS[i] ); + Var = VariableEnBaseDeLaContrainte[Cnt]; + if ( X < Xmin[Var] - 1.e-7 ) { + printf("Erreur: Spx->DeltaXSurLaVariableHorsBase = %e \n", Spx->DeltaXSurLaVariableHorsBase); + printf(" Var %d X = %e Xmin %e valeur avant %e\n",Var,X,Xmin[Var],BBarre[Cnt]); + goto RECHERCHE_VARIABLE_ENTRANTE; + } + if ( X > Xmax[Var] + 1.e-7 ) { + printf("Erreur: Spx->DeltaXSurLaVariableHorsBase = %e \n", Spx->DeltaXSurLaVariableHorsBase); + printf(" Var %d X = %e Xmax %e valeur avant %e\n",Var,X,Xmax[Var],BBarre[Cnt]); + goto RECHERCHE_VARIABLE_ENTRANTE; + } + + } +} + +Spx->FactoriserLaBase = NON_SPX; +SPX_MajPoidsDualSteepestEdge( Spx ); /* Car utilise par le Strong Branching */ +SPX_FaireLeChangementDeBase( Spx ); + +/* Maintenant il faut recalculer les couts reduits */ +SPX_CalculerPi( Spx ); /* Calcul de Pi = c_B * B^{-1} */ +SPX_CalculerLesCoutsReduits( Spx ); /* Calcul de CBarre = c_N - < Pi , N > */ +SPX_CalculerBBarre( Spx ); + +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + Var = VariableEnBaseDeLaContrainte[Cnt]; + X = BBarre[Cnt]; + if ( X < Xmin[Var] - 1.e-6 ) { + printf("Erreur: Spx->DeltaXSurLaVariableHorsBase = %e \n", Spx->DeltaXSurLaVariableHorsBase); + printf(" Var %d X = %e Xmin %e\n",Var,X,Xmin[Var]); + exit(0); + } + if ( X > Xmax[Var] + 1.e-6 ) { + printf("Erreur: Spx->DeltaXSurLaVariableHorsBase = %e \n", Spx->DeltaXSurLaVariableHorsBase); + printf(" Var %d X = %e Xmax %e\n",Var,X,Xmax[Var]); + exit(0); + } +} + + +NbPivotages++; + +goto RECHERCHE_VARIABLE_SORTANTE_1; + +FIN_PIVOTAGES: +/* Si on ne vient pas immediatement de factoriser la base, on le fait afin de + l'utiliser dans le strong branching */ +if ( Spx->NombreDeChangementsDeBase > 0 && Spx->ExplorationRapideEnCours == NON_SPX ) { + #if VERBOSE_SPX + printf("Factorisation necessaire avant sauvegardes pour le strong branching ou les coupes de Gomory\n"); + #endif + printf("Factorisation necessaire avant sauvegardes pour le strong branching ou les coupes de Gomory\n"); + /* Remarque: il faudrait aussi verifier qu'on va effectivement faire du strong branching + car il se peut que non et qu'on calcule des coupes a la place */ + SPX_FactoriserLaBase( Spx ); + if ( Spx->ChoixDeVariableSortanteAuHasard == OUI_SPX ) { + printf("Attention probleme a la factorisation, prevoir qq chose \n"); + } +} + +printf("NOMBRE DE PIVOTAGES REUSSIS: %d\n",NbPivotages); +exit(0); + +return; +} + +# endif diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_reconstruire_une_base.c b/src/ext/Sirius_Solver/simplexe/spx_dual_reconstruire_une_base.c new file mode 100644 index 0000000000..c1b41e0fb6 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_reconstruire_une_base.c @@ -0,0 +1,112 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On reconstruit une base de depart a l'aide de la base optimale + du noeud racine sans coupes. + Pour les coupes du probleme en cours, on met toutes les + variables d'ecart en base. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "bb_define.h" + +# include "pne_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_DualReconstruireUneBase( PROBLEME_SPX * Spx , char * Echec ) +{ +PROBLEME_PNE * Pne; BB * Bb; NOEUD * Noeud; int * VariableEnBaseDeLaContrainte; +int * ContrainteDeLaVariableEnBase; int Cnt; int Var; int il; +char * PositionDeLaVariable; int * Mdeb; int * NbTerm; int * Indcol; +# ifdef UTILISER_BORNES_AUXILIAIRES + char * StatutBorneSupCourante; +# endif + +*Echec = OUI_PNE; + +Pne = (PROBLEME_PNE *) Spx->ProblemePneDeSpx; +if ( Pne != NULL ) { + Bb = (BB *) Pne->ProblemeBbDuSolveur; +} +else return; + +if ( Pne->YaDesVariablesEntieres != OUI_PNE ) return; +/* En particulier il n'y a pas de base dispo a la premiere resolution du noeud racine */ +if ( Bb->BaseDisponibleAuNoeudRacine == NON ) return; + +Noeud = Bb->NoeudRacine; + +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +PositionDeLaVariable = Spx->PositionDeLaVariable; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) VariableEnBaseDeLaContrainte[Cnt] = -1; +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) ContrainteDeLaVariableEnBase[Var] = -1; + +# ifdef UTILISER_BORNES_AUXILIAIRES + /* On enleve toutes les bornes auxiliaires car elles seront retablies si necessaire */ + StatutBorneSupCourante = Spx->StatutBorneSupCourante; + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( StatutBorneSupCourante[Var] != BORNE_NATIVE ) SPX_SupprimerUneBorneAuxiliaire( Spx, Var ); + } + if ( Spx->NombreDeBornesAuxiliairesUtilisees != 0 ) { + #if VERBOSE_SPX + printf("Attention probleme dans SPX_DualReconstruireUneBase: le nombre de bornes auxiliaires n'est pas nul (valeur = %d)\n", + Spx->NombreDeBornesAuxiliairesUtilisees); + #endif + return; + } +# endif + +/* Construction de la base de depart (hors coupes) */ +SPX_ConstruireLaBaseDuProblemeModifie( Spx, Bb->NombreDeVariablesDuProbleme, + Noeud->PositionDeLaVariableSansCoupes, + Noeud->NbVarDeBaseComplementairesSansCoupes, + Noeud->ComplementDeLaBaseSansCoupes ); + +SPX_CompleterLaBaseDuProblemeModifie( Spx, Bb->NombreDeVariablesDuProbleme, + Bb->NombreDeContraintesDuProbleme, + Noeud->PositionDeLaVariableSansCoupes ); +/* On ajoute les variables basiques pour les coupes */ +for ( Cnt = Spx->NombreDeContraintesDuProblemeSansCoupes ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + /* Recherche de la variable d'ecart */ + il = Mdeb[Cnt] + NbTerm[Cnt] - 1; + Var = Indcol[il]; + PositionDeLaVariable[Var] = EN_BASE_LIBRE; + ContrainteDeLaVariableEnBase[Var] = Cnt; + VariableEnBaseDeLaContrainte[Cnt] = Var; +} + +*Echec = NON_PNE; + +/* Il est important de le mettre la car utilise dans SPX_InitialiserLeTableauDesVariablesHorsBase */ +Spx->LeSteepestEdgeEstInitilise = NON_SPX; + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_simplexe.c b/src/ext/Sirius_Solver/simplexe/spx_dual_simplexe.c new file mode 100644 index 0000000000..a660296cf9 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_simplexe.c @@ -0,0 +1,746 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution de Min c x sous contrainte Ax = b par un + simplexe dual (forme revisee du simplexe) en matrices + creuses + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# include "pne_define.h" + +# define MX_DUAL_NON_BORNE 2 /*5*/ + +# define VERBOSE_SPX 0 + +/*----------------------------------------------------------------------------*/ + +void SPX_DualSimplexe( PROBLEME_SPX * Spx ) +{ +int Var; char ControleSolutionFait ; char BaseReconstruite; int AdmissibiliteRestauree; +int NbCyclesSansVerifDuale; char ConfirmationDualNonBorneEnCours; int FoisVerifDualNonBorne; +int NbControlesFinaux; int NombreDeCyclagesApresOptimalite; char EpurerLaBase; char Echec; +char OptimaliteRencontree; int NbIterDeFinition; char Reoptimiser; char VerificationCyclage; +int IterationStockageCout1; int IterationStockageCout2; int DeltaIterationDeStockage; +double StockageCout1; double StockageCout2; double DeltaStockageCout; int SeuilPourRedemarrageBaseRacine; +char ControlerAdmissibiliteDuale; PROBLEME_PNE * Pne; BB * Bb; int i; char PresenceSeuilPourRedemarrageBaseRacine; +int NeutralisationVerificationDuCyclage; + +#if VERBOSE_SPX + printf("Entree dans l algorithme dual du simplexe\n"); +#endif + +/* Ensuite Bs sera toujours remis a 0 des qu'on aura fini de s'en servir */ +memset( (char *) Spx->Bs , 0 , Spx->NombreDeContraintes * sizeof( double ) ); + +SeuilPourRedemarrageBaseRacine = Spx->NombreMaxDIterations << 1; +PresenceSeuilPourRedemarrageBaseRacine = NON_SPX; +Pne = (PROBLEME_PNE *) Spx->ProblemePneDeSpx; +if ( Pne != NULL ) { + Bb = (BB *) Pne->ProblemeBbDuSolveur; + if ( Pne->YaDesVariablesEntieres == OUI_PNE ) { + if ( Bb->BaseDisponibleAuNoeudRacine == OUI ) { + if ( Bb->NombreDeSimplexes != 0 ) { + SeuilPourRedemarrageBaseRacine = (int) ceil( (double) Bb->SommeDuNombreDIterations / (double) Bb->NombreDeSimplexes ); + SeuilPourRedemarrageBaseRacine *= 10; + PresenceSeuilPourRedemarrageBaseRacine = OUI_SPX; + } + } + } +} + +SPX_InitialiserLesIndicateursHyperCreux( Spx ); + +Spx->FaireDuRaffinementIteratif = 0; + +DeltaIterationDeStockage = 150 /*100*/; +NeutralisationVerificationDuCyclage = 1000; +DeltaStockageCout = 1.e-6; +StockageCout1 = 0.0; +StockageCout1 = 0.0; +VerificationCyclage = NON_SPX; +IterationStockageCout1 = -1; +IterationStockageCout2 = -1; +BaseReconstruite = NON_SPX; + +Spx->SeuilDePivotDual = VALEUR_DE_PIVOT_ACCEPTABLE; + +Spx->NbBoundFlipIterationPrecedente = 0; + +Spx->TypeDeStockageDeABarreS = VECTEUR_SPX; + +Spx->NombreDeBornesAuxiliairesUtilisees = 0; +Spx->IterationPourBornesAuxiliaires = ITERATION_POUR_BORNES_AUXILIAIRES; +Spx->CoeffMultiplicateurDesBornesAuxiliaires = 1; + +Spx->LesCoutsOntEteModifies = NON_SPX; +Spx->ModifCoutsAutorisee = OUI_SPX; +Spx->CoefficientPourLaValeurDePerturbationDeCoutAPosteriori = 1.; + +OptimaliteRencontree = NON_SPX; +Reoptimiser = NON_SPX; + +Spx->NbCyclesSansControleDeDegenerescence = (int) floor( 0.5 * Spx->CycleDeControleDeDegenerescence ); +/* En mode branching il faut faire le controle rapidement */ +Spx->NbCyclesSansControleDeDegenerescence = Spx->CycleDeControleDeDegenerescence - 1; + +/* Initialisation des poids de la methode projected steepest edge */ +if ( Spx->LeSteepestEdgeEstInitilise == NON_SPX ) SPX_InitDualPoids( Spx ); + +/* Que la base soit fournie ou non, on appelle toujours ce sous-programme. S'il s'avere + que la base fournie etait duale realisable, il se contente de repositionner + les variables et se termine tout de suite */ +SPX_DualPhase1Simplexe( Spx ); +if ( Spx->LaBaseEstDualeAdmissible == NON_SPX ) { + #if VERBOSE_SPX + printf("Pas de base duale admissible disponible\n"); + #endif + Spx->YaUneSolution = NON_SPX; + return; +} + +ControleSolutionFait = NON_SPX; + +/* Et c'est parti dans les iterations */ + +Spx->EcrireLegendePhase2 = OUI_SPX; + +Spx->CalculerBBarre = OUI_SPX; /* OUI_SPX pour la premiere iteration */ + +Spx->PhaseEnCours = PHASE_2; +Spx->Iteration = 0; +NbCyclesSansVerifDuale = 0; + +Spx->ChoixDeVariableSortanteAuHasard = NON_SPX; +Spx->NombreMaxDeChoixAuHasard = 1; +Spx->NombreDeChoixFaitsAuHasard = 0; + +Spx->ProchaineIterationDeReinitDesCouts = 1000; + +ConfirmationDualNonBorneEnCours = NON_SPX; +NombreDeCyclagesApresOptimalite = 0; + +NbControlesFinaux = 0; + +EpurerLaBase = OUI_SPX; + +NbIterDeFinition = 0; + +Spx->YaUneSolution = NON_SPX; + +FoisVerifDualNonBorne = 0; + +while ( 1 ) { + + Debut: + + Spx->Iteration++; + Spx->FaireChangementDeBase = OUI_SPX; + Spx->NbBoundFlip = 0; + + if ( Spx->FaireDuRaffinementIteratif > 0 ) { + Spx->FaireDuRaffinementIteratif--; + + if ( Spx->FaireDuRaffinementIteratif > 0 ) { + Spx->CalculErBMoinsUnEnHyperCreux = NON_SPX; + Spx->CountEchecsErBMoins = 0; + Spx->CalculABarreSEnHyperCreux = NON_SPX; + Spx->CountEchecsABarreS = 0; + } + else { + SPX_InitialiserLesIndicateursHyperCreux( Spx ); + } + + } + + #if VERBOSE_SPX + if ( Spx->FaireDuRaffinementIteratif > 0 ) { + printf("RaffinementIteratif %d demande a l'iteration %d\n",Spx->FaireDuRaffinementIteratif,Spx->Iteration); + } + # endif + + if ( Spx->DureeMaxDuCalcul > 0 ) SPX_ControleDuTempsEcoule( Spx ); + + if ( Spx->Iteration > Spx->NombreMaxDIterations ) { /* Clause de sortie */ + if ( OptimaliteRencontree == OUI_SPX ) { + /* Si on a deja trouve un optimum mais avec bruitage, cela veut dire qu'on a du mal a + se sortir de la degenerescence mais qu'on a une solution realisable et presque optimale. + On verifie alors que la solution n'est pas trop mauvaise. Si c'est le cas, on dit qu'il + y a une solution */ + /* Calcul des couts reduits */ + SPX_CalculerPi( Spx ); + SPX_CalculerLesCoutsReduits( Spx ); + /* Calcul de BBarre */ + SPX_CalculerBBarre( Spx ); + /* Choix de la variable sortante */ + SPX_DualChoixDeLaVariableSortante( Spx ); + if ( Spx->VariableSortante < 0 ) Spx->YaUneSolution = OUI_SPX; + else if ( VerificationCyclage == NON_SPX ) { + Var = Spx->VariableSortante; + if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMAX ) { + if ( Spx->BBarre[Spx->ContrainteDeLaVariableEnBase[Var]] - Spx->Xmax[Var] < 100. * SEUIL_DE_VIOLATION_DE_BORNE ) Spx->YaUneSolution = OUI_SPX; + else Spx->YaUneSolution = NON_SPX; + } + else if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + if ( Spx->Xmin[Var] - Spx->BBarre[Spx->ContrainteDeLaVariableEnBase[Var]] < 100. * SEUIL_DE_VIOLATION_DE_BORNE ) Spx->YaUneSolution = OUI_SPX; + else Spx->YaUneSolution = NON_SPX; + } + else Spx->YaUneSolution = NON_SPX; + } + break; + } + else if ( Spx->Iteration > (Spx->NombreMaxDIterations << 3) && 0 ) { + /* Ailleurs on met Spx->Iteration = 10 * Spx->NombreMaxDIterations pour forcer l'arret */ + Spx->YaUneSolution = NON_SPX; + break; + } + else if ( VerificationCyclage == NON_SPX ) { + # if VERBOSE_SPX + printf("On positionne VerificationCyclage a OUI_SPX iteration %d NombreMaxDIterations %d\n",Spx->Iteration,Spx->NombreMaxDIterations); + # endif + /* On verifie qu'il n'y a aucun progres dans la fonction cout. S'il y en a, on continue les iterations. + Pour cela, on calcule le cout entre k iterations */ + VerificationCyclage = OUI_SPX; + IterationStockageCout1 = Spx->Iteration; + IterationStockageCout2 = IterationStockageCout1 + DeltaIterationDeStockage; + /* Spx->ModifCoutsAutorisee = NON_SPX; */ /* Il vaut mieux ne pas le faire car alors on favorise le cyclage */ + } + } + + /* Si on est dans les controles finaux et qu'on a du mal a converger, on reactive le bruitage + anti degenerescence */ + if ( NbControlesFinaux > 0 ) { + NbIterDeFinition++; + i = 0.1 * Spx->NombreDeContraintes; + if ( i < 1000 ) i = 1000; + if ( NbIterDeFinition > i && Spx->ModifCoutsAutorisee == NON_SPX && 0 ) { + + printf(" Reactivation du bruitage apres convergence car trop d'iterations CoefficientPourLaValeurDePerturbationDeCoutAPosteriori %e\n", + Spx->CoefficientPourLaValeurDePerturbationDeCoutAPosteriori); + printf(" **************************************************************** \n"); + + NbIterDeFinition = 0; + /*NbControlesFinaux = 0;*/ /* Non car risque de cyclage */ + ControleSolutionFait = NON_SPX; + Spx->ModifCoutsAutorisee = OUI_SPX; + /* + Spx->CoefficientPourLaValeurDePerturbationDeCoutAPosteriori *= 0.1; + if ( Spx->CoefficientPourLaValeurDePerturbationDeCoutAPosteriori < 1.e-3 ) { + Spx->ModifCoutsAutorisee = NON_SPX; + } + */ + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) Spx->CorrectionDuale[Var] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + } + } + + /* Calcul des couts reduits */ + if ( Spx->CalculerCBarre == OUI_SPX ) { + SPX_CalculerPi( Spx ); /* Calcul de Pi = c_B * B^{-1} */ + SPX_CalculerLesCoutsReduits( Spx ); /* Calcul de CBarre = c_N - < Pi , N > */ + Spx->CalculerCBarre = NON_SPX; + } + + /* On essaie cycliquement de restaurer les couts initiaux */ + SPX_ReinitialiserLesCoutsNatifSiCestPossible( Spx ); + + /* S'il y a des bornes auxiliaires, on essaie cycliquement de remettre les bornes initiales tout + en restant dual realisable */ + # ifdef UTILISER_BORNES_AUXILIAIRES + if ( Spx->NombreDeBornesAuxiliairesUtilisees > 0 ) { + if ( Spx->Iteration % CYCLE_POUR_SUPPRESSION_DES_BORNES_AUXILIAIRES == 0 ) { + SPX_DualSupprimerLesBornesAuxiliaires( Spx ); + } + } + # endif + + /* Calcul de BBarre c'est a dire B^{-1} * b */ + if ( Spx->CalculerBBarre == OUI_SPX ) { + SPX_CalculerBBarre( Spx ); + Spx->CalculerBBarre = NON_SPX; + } + + NbCyclesSansVerifDuale++; + if ( NbCyclesSansVerifDuale == CYCLE_DE_VERIF_ADMISSIBILITE_DUALE ) { + /* Ici l'utilite du calcul du cout et le calcul de X en fonction de la position est de permettre l'affichage + du deroulement du calcul */ + SPX_CalculDuCout( Spx ); + /* On verifie l'admissibilite avec les couts courants i.e. perturbes */ + SPX_VerifierAdmissibiliteDuale( Spx , &AdmissibiliteRestauree ); + NbCyclesSansVerifDuale = 0; + if ( AdmissibiliteRestauree == OUI_SPX ) { + # if VERBOSE_SPX + printf( "Controle d'admissibilite duale iteration %d : la base n'etait pas duale realisable\n",Spx->Iteration); + # endif + Spx->CalculerBBarre = OUI_SPX; + Spx->CalculerCBarre = OUI_SPX; + goto Debut; + } + } + + /* Verification: si le cout courant depasse le cout max fourni, alors on + arrete les calculs car le cout courant est un minorant du cout optimal */ + if ( Spx->UtiliserCoutMax == OUI_SPX && Spx->Iteration > 1 ) { + + /*SPX_CalculDuCout( Spx );*/ + /* Test d'une autre methode de calcul du cout */ + SPX_CalculDuCoutSimplifie( Spx ); + /* Fin test d'une autre methode de calcul du cout */ + if ( Spx->Cout > Spx->CoutMax ) { + if ( Spx->LesCoutsOntEteModifies == OUI_SPX ) { + /* Si le flag a ete leve, on restaure les couts et on refait un calcul */ + memcpy( (char *) Spx->C, (char *) Spx->Csv, Spx->NombreDeVariables * sizeof( double ) ); + + /* Il faut controler l'admissibilite duale de la solution. Si elle n'est pas duale admissible on repositionne + les variables hors base pour que ce soit le cas et on repart dans les iteration */ + Spx->ModifCoutsAutorisee = NON_SPX; + Spx->LesCoutsOntEteModifies = NON_SPX; + SPX_CalculerPi( Spx ); + SPX_CalculerLesCoutsReduits( Spx ); + SPX_CalculerBBarre( Spx ); + Spx->CalculerCBarre = NON_SPX; + } + + /* Dans tous les cas on reverifie a nouveau le depassement de CoutMax */ + /*SPX_CalculDuCout( Spx );*/ + SPX_CalculDuCoutSimplifie( Spx ); + if ( Spx->Cout <= Spx->CoutMax ) goto FinTestDepassementCoutMax; + + /* Controle d'admissibilite duale */ + if ( NbControlesFinaux < NOMBRE_MAX_DE_CONTROLES_FINAUX ) { /* C'est pour eviter un cyclages pour des questions d'epsilon */ + NbControlesFinaux++; + SPX_VerifierAdmissibiliteDuale( Spx , &AdmissibiliteRestauree ); + NbCyclesSansVerifDuale = 0; + if ( AdmissibiliteRestauree == OUI_SPX ) { + Spx->CalculerBBarre = OUI_SPX; + Spx->CalculerCBarre = OUI_SPX; + goto Debut; + } + } + + Spx->YaUneSolution = NON_SPX; + + Pne = (PROBLEME_PNE *) Spx->ProblemePneDeSpx; + if ( Pne != NULL ) { + Bb = (BB *) Pne->ProblemeBbDuSolveur; + BB_LeverLeFlagDeSortieDuSimplexeParDepassementDuCoutMax( Bb ); + #if VERBOSE_SPX + printf( "Arret du Simplexe dual par depassement du cout max, iterations %d Cout %e CoutMax %e\n",Spx->Iteration-1,Spx->Cout,Spx->CoutMax); + #endif + } + break; + } + } + FinTestDepassementCoutMax: + /* On a depasse le nombre max d'iteration et on est en train de verifier s'il y a cyclage */ + if ( VerificationCyclage == OUI_SPX ) { + if ( Spx->Iteration == IterationStockageCout1 ) { + /*SPX_CalculDuCout( Spx );*/ + SPX_CalculDuCoutSimplifie( Spx ); + StockageCout1 = Spx->Cout; + } + else if ( Spx->Iteration == IterationStockageCout2 ) { + /*SPX_CalculDuCout( Spx );*/ + SPX_CalculDuCoutSimplifie( Spx ); + StockageCout2 = Spx->Cout; + if ( StockageCout2 < StockageCout1 + DeltaStockageCout ) { + /* Arret confirme */ + Spx->YaUneSolution = NON_SPX; + break; + } + else { + /* L'arret est en sursis */ + VerificationCyclage = NON_SPX; + Spx->NombreMaxDIterations += NeutralisationVerificationDuCyclage; /* Afin de neutraliser la verification du cycale pendant un certain temps */ + # if VERBOSE_SPX + printf("On positionne VerificationCyclage a NON_SPX iteration %d\n",Spx->Iteration); + # endif + } + } + } + + /* Si on est en mode branch and bound et qu'on a du mal a trouver l'optimum, on repart + de la base optimale du noeud racine sans les coupes (les variables d'ecart des coupes + sont alors positionnees en base */ + if ( Spx->Iteration > SeuilPourRedemarrageBaseRacine && PresenceSeuilPourRedemarrageBaseRacine == OUI_SPX ) { + if ( BaseReconstruite == NON_SPX ) { + #if VERBOSE_SPX + printf(" \n"); + printf("------> Convergence lente, on tente de repartir d'une BASE du noeud racine\n"); + printf(" \n"); + #endif + /* Attention il faut avoir resolu le noeud racine sans coupes */ + SPX_DualReconstruireUneBase( Spx , &Echec ); + if ( Echec == OUI_SPX ) { + /* On continue avec la base courante car on ne peut pas faire mieux */ + goto Debut; + } + BaseReconstruite = OUI_SPX; + SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); + SPX_InitialiserLesIndicateursHyperCreux( Spx ); + + printf("\n 1- On autorise a nouveau le bruitage des couts !!!!! \n"); + + Spx->ModifCoutsAutorisee = OUI_SPX; + Spx->CoefficientPourLaValeurDePerturbationDeCoutAPosteriori = 1.; + + /* On remet les vrais couts */ + + memcpy( (char *) Spx->C, (char *) Spx->Csv, Spx->NombreDeVariables * sizeof( double ) ); + Spx->LesCoutsOntEteModifies = NON_SPX; + + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) Spx->CorrectionDuale[Var] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + + Spx->YaUneSolution = OUI_SPX; /* Car c'est positionne a NON_SPX en cas de probleme */ + SPX_FactoriserLaBase( Spx ); + if ( Spx->YaUneSolution == NON_SPX ) { + #if VERBOSE_SPX + printf("Base non inversible ou probleme pour trouver une base duale admissible\n"); + #endif + break; + } + Spx->YaUneSolution = NON_SPX; /* Car le positionnement a OUI_SPX n'etait que pour la factorisation */ + SPX_InitDualPoids( Spx ); + SPX_DualPhase1Simplexe( Spx ); + if ( Spx->LaBaseEstDualeAdmissible == NON_SPX ) { + #if VERBOSE_SPX + printf("Pas de base duale admissible disponible\n"); + #endif + Spx->YaUneSolution = NON_SPX; + break; + } + Spx->CalculerBBarre = OUI_SPX; + Spx->CalculerCBarre = OUI_SPX; + goto Debut; + } + } + + RechercheVariableSortante: + + /* Choix de la variable sortante */ + if ( Spx->ChoixDeVariableSortanteAuHasard == OUI_SPX ) { + SPX_DualChoixDeLaVariableSortanteAuHasard( Spx ); + Spx->NombreDeChoixFaitsAuHasard++; + if ( Spx->VariableSortante < 0 ) { + Spx->ChoixDeVariableSortanteAuHasard = NON_SPX; + Spx->NombreDeChoixFaitsAuHasard = 0; + goto RechercheVariableSortante; + } + } + else { + SPX_DualChoixDeLaVariableSortante( Spx ); + } + + if ( Spx->NombreDeChoixFaitsAuHasard >= Spx->NombreMaxDeChoixAuHasard ) { + Spx->ChoixDeVariableSortanteAuHasard = NON_SPX; + Spx->NombreDeChoixFaitsAuHasard = 0; + } + + if ( Spx->VariableSortante < 0 ) { + /* Si on est dans un contexte de base reduite, il faut controler les variables basiques hors base reduite. + Si elle sont toutes admissible, c'est gagne. + Si certaines ne sont pas admissibles on les reintegre dans une base reduite et on recommence */ + # if VERBOSE_SPX == 1 + printf("Plus de variable sortante Spx->UtiliserLaBaseReduite %d\n",Spx->UtiliserLaBaseReduite); + # endif + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + SPX_TestPassageBaseReduiteBaseComplete( Spx ); + goto Debut; + } + + OptimaliteAtteinte: + /* Optimalite atteinte */ + OptimaliteRencontree = OUI_SPX; + SPX_DualControlerOptimalite( Spx, &NbControlesFinaux, &ControleSolutionFait ); + if ( Spx->YaUneSolution == OUI_SPX ) break; + /* Sinon on repart dans les iterations */ + NbCyclesSansVerifDuale = 0; + + /* Au bout d'un certain nombre d'echecs, on repart de la base racine */ + if ( NbControlesFinaux == SEUIL_POUR_RECONSTRUCTION_BASE && BaseReconstruite == NON_SPX ) { + #if VERBOSE_SPX + printf(" \n"); + printf("------> On repart d'une BASE du noeud racine\n"); + printf(" \n"); + #endif + /* Attention il faut avoir resolu le noeud racine sans coupes */ + SPX_DualReconstruireUneBase( Spx , &Echec ); + if ( Echec == OUI_SPX ) { + /* On continue avec la base courante car on ne peut pas faire mieux */ + goto Debut; + } + BaseReconstruite = OUI_SPX; + SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); + SPX_InitialiserLesIndicateursHyperCreux( Spx ); + + Spx->ModifCoutsAutorisee = OUI_SPX; + Spx->CoefficientPourLaValeurDePerturbationDeCoutAPosteriori *= 0.1; + + /* On remet les vrais couts */ + /* + memcpy( (char *) Spx->C, (char *) Spx->Csv, Spx->NombreDeVariables * sizeof( double ) ); + Spx->LesCoutsOntEteModifies = NON_SPX; + */ + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) Spx->CorrectionDuale[Var] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + + Spx->YaUneSolution = OUI_SPX; /* Car c'est positionne a NON_SPX en cas de probleme */ + SPX_FactoriserLaBase( Spx ); + if ( Spx->YaUneSolution == NON_SPX ) { + #if VERBOSE_SPX + printf("Base non inversible ou probleme pour trouver une base duale admissible\n"); + #endif + break; + } + Spx->YaUneSolution = NON_SPX; + SPX_InitDualPoids( Spx ); + SPX_DualPhase1Simplexe( Spx ); + if ( Spx->LaBaseEstDualeAdmissible == NON_SPX ) { + #if VERBOSE_SPX + printf("Pas de base duale admissible disponible\n"); + #endif + Spx->YaUneSolution = NON_SPX; + break; + } + Spx->CalculerBBarre = OUI_SPX; + Spx->CalculerCBarre = OUI_SPX; + } + goto Debut; + + } + + RechercheVariableEntrante: + + SPX_DualCalculerNBarreR( Spx, OUI_SPX, &ControlerAdmissibiliteDuale ); + if ( ControlerAdmissibiliteDuale == OUI_SPX ) { + /* On a constate trop de derive dans les couts reduits */ + /* Ici l'utilite du calcul du cout et le calcul de X en fonction de la position est de permettre l'affichage + du deroulement du calcul */ + /*SPX_CalculDuCout( Spx );*/ + /* On verifie l'admissibilite avec les couts courants i.e. perturbes */ + SPX_VerifierAdmissibiliteDuale( Spx , &AdmissibiliteRestauree ); + NbCyclesSansVerifDuale = 0; + if ( AdmissibiliteRestauree == OUI_SPX ) { + # if VERBOSE_SPX + printf( "Controle d'admissibilite duale iteration %d : la base n'etait pas duale realisable\n",Spx->Iteration); + # endif + Spx->CalculerBBarre = OUI_SPX; + Spx->CalculerCBarre = OUI_SPX; + goto Debut; + } + } + + SPX_DualVerifierErBMoinsUn( Spx ); + if ( Spx->FactoriserLaBase == OUI_SPX ) SPX_FactoriserLaBase( Spx ); + if ( Spx->FaireChangementDeBase == NON_SPX ) { + # if VERBOSE_SPX + printf("Iteration %d Pas de changement de base a cause de DualVerifierErBMoinsUn\n",Spx->Iteration); + # endif + goto Debut; + } + if ( Spx->NombreDeVariablesATester <= 0 ) { + if ( Spx->SeuilDePivotDual > VALEUR_DE_PIVOT_ACCEPTABLE ) { + Spx->SeuilDePivotDual /= DIVISEUR_VALEUR_DE_PIVOT_ACCEPTABLE; + if ( Spx->SeuilDePivotDual < VALEUR_DE_PIVOT_ACCEPTABLE ) Spx->SeuilDePivotDual = VALEUR_DE_PIVOT_ACCEPTABLE; + /* Apres avoir ajuste le seuil, on recherche a nouveau une variable entrante */ + if ( Spx->ChoixDeVariableSortanteAuHasard == OUI_SPX ) goto RechercheVariableSortante; + goto RechercheVariableEntrante; + } + /* On ne cherche pas a confirmer l'absence de solution tant qu'on n'est pas dans une phase normale du simplexe */ + if ( Spx->ChoixDeVariableSortanteAuHasard == OUI_SPX ) goto RechercheVariableSortante; + + if ( FoisVerifDualNonBorne > MX_DUAL_NON_BORNE ) ConfirmationDualNonBorneEnCours = OUI_SPX; + SPX_DualControleDualNonBorne( Spx, &ConfirmationDualNonBorneEnCours ); + /* Il n'est pas clair si on doit ou non remettre les couts initiaux et + desactiver le bruitage anti degenerescence */ + if ( ConfirmationDualNonBorneEnCours == OUI_SPX ) goto Debut; + + if ( Spx->AdmissibilitePossible == OUI_SPX ) { + #if VERBOSE_SPX + printf("Spx->AdmissibilitePossible = OUI_SPX => on considere quand meme qu'il y a une solution admissible\n"); + #endif + /* Mieux vaut restaurer les couts et refaire un calcul */ + Spx->VariableSortante = -1; + goto OptimaliteAtteinte; + } + else { + #if VERBOSE_SPX + printf("Spx->AdmissibilitePossible = NON_SPX\n"); + #endif + Spx->YaUneSolution = NON_SPX; + break; + } + + } + + /* Ci-dessous pour mise au point uniquement */ + /* + if ( Spx->PremierSimplexe != OUI_SPX ) { + if ( Spx->Iteration > 2000 ) { + printf("Ecriture des donnees iteration %d\n",Spx->Iteration); + Spx_EcrireJeuDeDonneesLineaireAuFormatMPS( Spx ); + exit(0); + } + } + */ + + /* Si on etait en train de confirmer un dual non borne, on avait remis les couts initiaux et interdit le bruitage des couts. + Si on en arrive la, c'est qu'on a pu s'en tirer donc on remet le bruitage des couts en service */ + /* Experimentalement, il semble preferable de ne pas re bruiter les couts et d'en reste a la confirmation + du dual non borne */ + if ( ConfirmationDualNonBorneEnCours == OUI_SPX ) { + Spx->ModifCoutsAutorisee = OUI_SPX; + ConfirmationDualNonBorneEnCours = NON_SPX; + FoisVerifDualNonBorne++; + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) Spx->CorrectionDuale[Var] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + } + + /* Choix de la variable entrante */ + SPX_DualChoixDeLaVariableEntrante( Spx ); + if ( Spx->VariableEntrante < 0 ) { + /* Par precaution */ + Spx->YaUneSolution = NON_SPX; + break; + } + + if ( Spx->UtiliserLaLuUpdate == NON_SPX ) { + if ( Spx->NombreDeChangementsDeBase == Spx->CycleDeRefactorisation ) Spx->FactoriserLaBase = OUI_SPX; + } + + SPX_CalculerABarreS( Spx ); /* On en a aussi besoin pour le steepest edge et pour les controles et aussi pour la mise a jour de BBarre */ + /* La verification de ABarreS peut entrainer une demande de factorisation de la base */ + SPX_VerifierABarreS( Spx ); + if ( Spx->FaireChangementDeBase == NON_SPX ) { + # if VERBOSE_SPX + printf("Iteration %d Pas de changement de base a cause de VerifierABarreS\n",Spx->Iteration); + # endif + /* Attention a remettre les bound flip */ + if ( Spx->FactoriserLaBase == OUI_SPX ) SPX_FactoriserLaBase( Spx ); + Spx->CalculerBBarre = OUI_SPX; + Spx->CalculerCBarre = OUI_SPX; + goto Debut; + } + + SPX_DualComparerABarreSEtNBarreR( Spx ); + + #if VERBOSE_SPX + if ( Spx->FaireChangementDeBase == NON_SPX ) { + printf(" changement de base refuse iteration %d \n",Spx->Iteration); + } + #endif + + if ( Spx->FaireChangementDeBase == NON_SPX ) { + # if VERBOSE_SPX + printf("Iteration %d Pas de changement de base a cause de DualComparerABarreSEtNBarreR\n",Spx->Iteration); + #endif + if ( Spx->FactoriserLaBase == OUI_SPX ) SPX_FactoriserLaBase( Spx ); + Spx->CalculerBBarre = OUI_SPX; + Spx->CalculerCBarre = OUI_SPX; + goto Debut; + } + + /* Mise a jour des poids de la methode projected steepest edge */ + SPX_MajPoidsDualSteepestEdge( Spx ); + + if ( Spx->FactoriserLaBase == NON_SPX ) { + SPX_MettreAJourLesCoutsReduits( Spx ); + if ( Spx->FaireMiseAJourDeBBarre == OUI_SPX && ControleSolutionFait == NON_SPX ) { + SPX_MettreAJourBBarre( Spx ); + Spx->CalculerBBarre = NON_SPX; + } + else Spx->CalculerBBarre = OUI_SPX; + } + + SPX_FaireLeChangementDeBase( Spx ); + + /* Apres chaque changement de base reussi on essaie de revenir au seuil de pivotage initial */ + if ( Spx->SeuilDePivotDual > VALEUR_DE_PIVOT_ACCEPTABLE ) { + Spx->SeuilDePivotDual /= DIVISEUR_VALEUR_DE_PIVOT_ACCEPTABLE; + if ( Spx->SeuilDePivotDual < VALEUR_DE_PIVOT_ACCEPTABLE ) Spx->SeuilDePivotDual = VALEUR_DE_PIVOT_ACCEPTABLE; + } + +} + +OptimaliteRencontree = NON_SPX; + +Spx->FaireDuRaffinementIteratif = 0; +Spx->CycleDeRefactorisation = CYCLE_DE_REFACTORISATION_DUAL; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX && Spx->YaUneSolution == OUI_SPX ) { + Spx->YaUneSolution = OUI_SPX; + SPX_TestPassageBaseReduiteBaseComplete( Spx ); + goto Debut; +} + +# ifdef UTILISER_BORNES_AUXILIAIRES + + SPX_DualControlerLesBornesAuxiliaires( Spx, &Reoptimiser ); + if ( Reoptimiser == OUI_SPX ) { + # if VERBOSE_SPX + printf("On relance une phase 2 apres DualControlerLesBornesAuxiliaires\n"); + # endif + ControleSolutionFait = NON_SPX; + NbCyclesSansVerifDuale = 0; + ConfirmationDualNonBorneEnCours = NON_SPX; + NbControlesFinaux = 0; + NbIterDeFinition = 0; + Spx->CycleDeRefactorisation = CYCLE_DE_REFACTORISATION_DUAL; + Spx->CalculerBBarre = OUI_SPX; + Spx->CalculerCBarre = OUI_SPX; + Spx->LesCoutsOntEteModifies = NON_SPX; + Spx->ModifCoutsAutorisee = NON_SPX /*OUI_SPX*/; + Spx->CoefficientPourLaValeurDePerturbationDeCoutAPosteriori = 1.; + + Spx->ForcerUtilisationDeLaBaseComplete = 0; + Spx->InitBaseReduite = OUI_SPX; + + FoisVerifDualNonBorne = 0; + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) Spx->CorrectionDuale[Var] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + goto Debut; + } + +# endif + +if ( Spx->Contexte != SIMPLEXE_SEUL && Spx->YaUneSolution == OUI_SPX ) { + SPX_DualEpurerLaBaseSimplexe( Spx, &NombreDeCyclagesApresOptimalite, &EpurerLaBase, &Echec ); + if ( Echec == OUI_SPX ) goto Debut; +} + +/* A faire si on n'appelle pas DualEpurerLaBaseSimplexe en branch and bound */ +/* +if ( Spx->Contexte != SIMPLEXE_SEUL && Spx->YaUneSolution == OUI_SPX ) { + SPX_FactoriserLaBase( Spx ); +} +*/ +/*printf("Fin a l'iteration %d YaUneSolution %d\n",Spx->Iteration,(int) Spx->YaUneSolution);*/ + +/* En test: pivotages degeneres pour obtenir une solution entiere */ +/*if ( Spx->YaUneSolution == OUI_SPX ) SPX_DualPivotagesComplementaires( Spx );*/ + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_steepest.c b/src/ext/Sirius_Solver/simplexe/spx_dual_steepest.c new file mode 100644 index 0000000000..65f962acbb --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_steepest.c @@ -0,0 +1,405 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +# define SEUIL_CARRE_DE_NORME_TROP_FAIBLE 1.e-4 /*1.e-4*/ +# define DUAL_POIDS_INITIAL 1.0 + +# define VERBOSE_SPX 0 + +/*----------------------------------------------------------------------------*/ +void SPX_InitDualPoids( PROBLEME_SPX * Spx ) +{ +int Var; int Cnt; char * PositionDeLaVariable; char * InDualFramework; +double * DualPoids; double * Tau; + +# if VERBOSE_SPX + printf("SPX_InitDualPoids\n"); +# endif + +PositionDeLaVariable = Spx->PositionDeLaVariable; +InDualFramework = Spx->InDualFramework; + +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( PositionDeLaVariable[Var] == EN_BASE_LIBRE ) InDualFramework[Var] = OUI_SPX; + else InDualFramework[Var] = NON_SPX; +} + +DualPoids = Spx->DualPoids; +Tau = Spx->Tau ; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + DualPoids[Cnt] = DUAL_POIDS_INITIAL; + Tau [Cnt] = 0.0; +} + +Spx->LeSteepestEdgeEstInitilise = OUI_SPX; + +Spx->CalculTauEnHyperCreux = OUI_SPX; +Spx->CalculTauEnHyperCreuxPossible = OUI_SPX; +Spx->CountEchecsTau = 0; +Spx->AvertissementsEchecsTau = 0; +Spx->NbEchecsTau = 0; + +return; +} + +/*----------------------------------------------------------------------------*/ +void SPX_ResetReferenceSpace( PROBLEME_SPX * Spx ) +{ +char A1; char A2; + +A1 = Spx->PositionDeLaVariable[Spx->VariableSortante]; +A2 = Spx->PositionDeLaVariable[Spx->VariableEntrante]; + +Spx->PositionDeLaVariable[Spx->VariableSortante] = HORS_BASE_SUR_BORNE_INF; +Spx->PositionDeLaVariable[Spx->VariableEntrante] = EN_BASE_LIBRE; + +SPX_InitDualPoids( Spx ); + +Spx->PositionDeLaVariable[Spx->VariableSortante] = A1; +Spx->PositionDeLaVariable[Spx->VariableEntrante] = A2; + +return; +} + +/*----------------------------------------------------------------------------*/ +void SPX_DualSteepestGestionIndicateursHyperCreux( PROBLEME_SPX * Spx, char ResolutionEnHyperCreux, + char HyperCreuxInitial, char TypeDeSortie, + char * StockageDeTau, char * ResetRefSpace ) +{ +int il; int i; char * InDualFramework; int * NumerosDesVariablesHorsBase; +if ( ResolutionEnHyperCreux == OUI_SPX ) { + if ( TypeDeSortie == VECTEUR_LU ) { + *StockageDeTau = VECTEUR_SPX; + /* Ca s'est pas bien passe et on s'est forcement retrouve en VECTEUR_LU */ + Spx->NbEchecsTau++; + /*printf("Echec hyper creux Tau iteration %d\n",Spx->Iteration);*/ + if ( Spx->NbEchecsTau >= SEUIL_ECHEC_CREUX_STEEPEST ) { + # if VERBOSE_SPX + printf("Arret de l'hyper creux pour le steepest edge, iteration %d\n",Spx->Iteration); + # endif + Spx->CalculTauEnHyperCreux = NON_SPX; + Spx->CountEchecsTau = 0; + } + } + else Spx->NbEchecsTau = 0; +} +/* Si on est pas en hyper creux, on essaie d'y revenir */ +if ( HyperCreuxInitial == NON_SPX ) { + if ( Spx->CalculABarreSEnHyperCreuxPossible == OUI_SPX ) { + if ( Spx->CalculTauEnHyperCreuxPossible == OUI_SPX ) { + if ( Spx->CalculTauEnHyperCreux == NON_SPX ) { + SPX_TenterRestaurationCalculTauEnHyperCreux( Spx ); + + /* Test: on n'arrive plus a faire de l'hyper creux alors que ce serait possible: on fait un reset + de l'espace de reference pour ameliorer le creux du vecteur Tau */ + InDualFramework = Spx->InDualFramework; + NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; + if ( Spx->CalculTauEnHyperCreuxPossible == NON_SPX ) { + if ( Spx->TypeDeCreuxDeLaBase == BASE_HYPER_CREUSE && Spx->CalculABarreSEnHyperCreux == OUI_SPX && + Spx->CalculErBMoinsUnEnHyperCreux == OUI_SPX ) { + /* On compte les variable HB dans le framework. S'il y en a beaucoup alors il y a peu de chances + qu'on puisse faire de l'hyper creux dans le steepest edge */ + for ( il = 0 , i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + if ( InDualFramework[NumerosDesVariablesHorsBase[i]] == OUI_SPX ) il++; + } + if ( il > ceil ( 0.2 * Spx->NombreDeVariablesHorsBase ) ) { + SPX_ResetReferenceSpace( Spx ); + # if VERBOSE_SPX + printf("Iteration %d reset reference space car on peut plus faire d'hyper creux\n",Spx->Iteration); + # endif + *ResetRefSpace = OUI_SPX; + return; + } + } + } + /* Fin test */ + + } + } + } +} + +return; +} +/*----------------------------------------------------------------------------*/ +void SPX_DualSteepestControleDuPoidsDeCntBase( PROBLEME_SPX * Spx, double BetaP, char * ResetRefSpace ) +{ +int IndexCntBase; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + IndexCntBase = Spx->OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]]; +} +else { + IndexCntBase = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; +} + +if ( Spx->DualPoids[IndexCntBase] > /*2.*/ 4. * BetaP || Spx->DualPoids[IndexCntBase] < /*0.5*/ 0.25 * BetaP ) { + #if VERBOSE_SPX + printf("Iteration %d BetaP %e Spx->DualPoids[CntBase] %e CntBase %d\n",Spx->Iteration,BetaP,Spx->DualPoids[IndexCntBase],IndexCntBase); + printf("VariableSortante %d VariableEntrante %d\n",Spx->VariableSortante,Spx->VariableEntrante); + printf("Iteration %d RESET REFERENCE SPACE par derive excessive des poids\n",Spx->Iteration); + #endif + *ResetRefSpace = OUI_SPX; + SPX_ResetReferenceSpace( Spx ); + return; +} + +return; +} +/*----------------------------------------------------------------------------*/ +void SPX_DualSteepestVariablesDeBornesIdentiques( PROBLEME_SPX * Spx, double * BetaP ) +{ +/* Dynamic steepest edge: si la variable sortante est une variable basique artificielle on l'enleve de + l'espace de reference */ +if ( Spx->Xmin[Spx->VariableSortante] == Spx->Xmax[Spx->VariableSortante] ) { + if ( Spx->InDualFramework[Spx->VariableSortante] == OUI_SPX ) { + Spx->InDualFramework[Spx->VariableSortante] = NON_SPX; + *BetaP = *BetaP - DUAL_POIDS_INITIAL; + } +} + +return; +} +/*----------------------------------------------------------------------------*/ +/* Attention il s'agit de la methode "Projected Steepest Edge" */ + +void SPX_MajPoidsDualSteepestEdge( PROBLEME_SPX * Spx ) +{ +int Index; int IndexCntBase; char ResetRefSpace; double BetaP; double Rapport; double X; +double UnSurABarreSCntBase ; char ResoudreLeSysteme; char * InDualFramework; int i; +double *ArrayABarreS; int VariableEntrante; double ABarreS; double * DualPoids; double * Tau; +int VariableSortante; int * CntDeABarreSNonNuls; char ResolutionEnHyperCreux; +int * IndexTermesNonNulsDeTau; int NbTermesNonNulsDeTau; char StockageDeTau; +int IndexMax; + +if ( Spx->TypeDePricing == PRICING_DANTZIG ) return; + +VariableEntrante = Spx->VariableEntrante; +VariableSortante = Spx->VariableSortante; + +/* Calcul de BetaP */ +InDualFramework = Spx->InDualFramework; +BetaP = 0.; +if ( InDualFramework[VariableSortante] == OUI_SPX ) BetaP = DUAL_POIDS_INITIAL; + +if ( Spx->CalculABarreSEnHyperCreux == OUI_SPX && Spx->CalculTauEnHyperCreux == OUI_SPX ) ResolutionEnHyperCreux = OUI_SPX; +else ResolutionEnHyperCreux = NON_SPX; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + SPX_DualSteepestEdgeResolutionBaseReduite( Spx, &BetaP, ResolutionEnHyperCreux, &ResetRefSpace, &NbTermesNonNulsDeTau, &StockageDeTau, &ResoudreLeSysteme ); +} +else { + SPX_DualSteepestEdgeResolutionAvecBaseComplete( Spx, &BetaP, ResolutionEnHyperCreux, &ResetRefSpace, &NbTermesNonNulsDeTau, &StockageDeTau, &ResoudreLeSysteme ); +} + +if ( ResetRefSpace == OUI_SPX ) return; + +DualPoids = Spx->DualPoids; +ArrayABarreS = Spx->ABarreS; +Tau = Spx->Tau; +IndexTermesNonNulsDeTau = (int *) Spx->ErBMoinsUn; +UnSurABarreSCntBase = 1. / Spx->ABarreSCntBase; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + IndexMax = Spx->RangDeLaMatriceFactorisee; + IndexCntBase = Spx->OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[VariableSortante]]; +} +else { + IndexMax = Spx->NombreDeContraintes; + IndexCntBase = Spx->ContrainteDeLaVariableEnBase[VariableSortante]; +} + +/* On n'aurait pas besoin de calculer DualPoids des contraintes dont la variable en base est + non bornee car ces variables ne sortent jamais de la base */ + +if ( ResoudreLeSysteme == OUI_SPX ) { + if ( Spx->TypeDeStockageDeABarreS == VECTEUR_SPX ) { + if ( StockageDeTau == VECTEUR_SPX ) { + for ( Index = 0 ; Index < IndexMax ; Index++ ) { + ABarreS = ArrayABarreS[Index]; + if ( ABarreS != 0.0 ) { + Rapport = ABarreS * UnSurABarreSCntBase; + X = DualPoids[Index] + ( ( ( -2. * Tau[Index] ) + ( Rapport * BetaP ) ) * Rapport ); + if ( X < SEUIL_CARRE_DE_NORME_TROP_FAIBLE ) { + #if VERBOSE_SPX + printf("Iteration %d Cnt %d X %e => RESET REFERENCE SPACE par carre de norme trop faible\n",Spx->Iteration,Index,X); + #endif + SPX_ResetReferenceSpace( Spx ); + return; + } + DualPoids[Index] = X; + } + Tau[Index] = 0.0; + } + } + else { + for ( Index = 0 ; Index < IndexMax ; Index++ ) { + ABarreS = ArrayABarreS[Index]; + if ( ABarreS != 0.0 ) { + Rapport = ABarreS * UnSurABarreSCntBase; + X = DualPoids[Index] + ( ( ( -2. * Tau[Index] ) + ( Rapport * BetaP ) ) * Rapport ); + if ( X < SEUIL_CARRE_DE_NORME_TROP_FAIBLE ) { + #if VERBOSE_SPX + printf("Iteration %d Cnt %d X %e => RESET REFERENCE SPACE par carre de norme trop faible\n",Spx->Iteration,Index,X); + #endif + SPX_ResetReferenceSpace( Spx ); + return; + } + DualPoids[Index] = X; + } + } + for ( i = 0 ; i < NbTermesNonNulsDeTau ; i++ ) Tau[IndexTermesNonNulsDeTau[i]] = 0.0; + } + } + else { + CntDeABarreSNonNuls = Spx->CntDeABarreSNonNuls; + for ( i = 0 ; i < Spx->NbABarreSNonNuls ; i++ ) { + Rapport = ArrayABarreS[i] * UnSurABarreSCntBase; + Index = CntDeABarreSNonNuls[i]; + DualPoids[Index] += ( ( -2. * Tau[Index] ) + ( Rapport * BetaP ) ) * Rapport; + if ( DualPoids[Index] < SEUIL_CARRE_DE_NORME_TROP_FAIBLE ) { + #if VERBOSE_SPX + printf("Iteration %d Cnt %d X %e => RESET REFERENCE SPACE par carre de norme trop faible\n", + Spx->Iteration,Index,DualPoids[Index]); + #endif + SPX_ResetReferenceSpace( Spx ); + return; + } + } + if ( StockageDeTau != VECTEUR_SPX ) { + for ( i = 0 ; i < NbTermesNonNulsDeTau ; i++ ) Tau[IndexTermesNonNulsDeTau[i]] = 0.0; + } + else { + for ( i = 0 ; i < IndexMax ; i++ ) Tau[i] = 0.0; + } + } +} +else { + if ( Spx->TypeDeStockageDeABarreS == VECTEUR_SPX ) { + for ( Index = 0 ; Index < IndexMax ; Index++ ) { + ABarreS = ArrayABarreS[Index]; + if ( ABarreS != 0.0 ) { + Rapport = ABarreS * UnSurABarreSCntBase; + X = DualPoids[Index] + ( Rapport * BetaP * Rapport ); + if ( X < SEUIL_CARRE_DE_NORME_TROP_FAIBLE ) { + #if VERBOSE_SPX + printf("Iteration %d Cnt %d X %e => RESET REFERENCE SPACE par carre de norme trop faible\n",Spx->Iteration,Index,X); + #endif + SPX_ResetReferenceSpace( Spx ); + return; + } + DualPoids[Index] = X; + } + } + } + else { + CntDeABarreSNonNuls = Spx->CntDeABarreSNonNuls; + for ( i = 0 ; i < Spx->NbABarreSNonNuls ; i++ ) { + Rapport = ArrayABarreS[i] * UnSurABarreSCntBase; + Index = CntDeABarreSNonNuls[i]; + X = DualPoids[Index] + ( Rapport * BetaP * Rapport ); + if ( X < SEUIL_CARRE_DE_NORME_TROP_FAIBLE ) { + #if VERBOSE_SPX + printf("Iteration %d Cnt %d X %e => RESET REFERENCE SPACE par carre de norme trop faible\n",Spx->Iteration,Index,X); + #endif + SPX_ResetReferenceSpace( Spx ); + return; + } + DualPoids[Index] = X; + } + } +} + +DualPoids[IndexCntBase] = BetaP * UnSurABarreSCntBase * UnSurABarreSCntBase; + +/* Dynamic steepest edge: on ajoute la variable entrante dans l'espace de reference */ +if ( InDualFramework[VariableEntrante] == NON_SPX ) { + InDualFramework[VariableEntrante] = OUI_SPX; + DualPoids[IndexCntBase] += DUAL_POIDS_INITIAL; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_TenterRestaurationCalculTauEnHyperCreux( PROBLEME_SPX * Spx ) +{ +int Index; double * Tau; int Count; int IndexMax; + +if ( Spx->CountEchecsTau == 0 ) { + if ( Spx->Iteration % CYCLE_TENTATIVE_HYPER_CREUX == 0 ) { + Spx->NbEchecsTau = SEUIL_REUSSITE_CREUX; + Spx->CountEchecsTau = SEUIL_REUSSITE_CREUX + 2; + } +} +if ( Spx->CountEchecsTau == 0 ) return; + +Spx->CountEchecsTau--; +/* On compte le nombre de termes non nuls du resultat */ +Tau = Spx->Tau; +Count = 0; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + IndexMax = Spx->RangDeLaMatriceFactorisee; +} +else { + IndexMax = Spx->NombreDeContraintes; +} + +for ( Index = 0 ; Index < IndexMax ; Index++ ) if ( Tau[Index] != 0.0 ) Count++; + + +if ( Count < 0.1 * IndexMax ) Spx->NbEchecsTau--; +if ( Spx->NbEchecsTau <= 0 ) { + # if VERBOSE_SPX + printf("Remise en service de l'hyper creux pour le steepest edge, iteration %d\n",Spx->Iteration); + # endif + Spx->AvertissementsEchecsTau = 0; + Spx->CountEchecsTau = 0; + Spx->CalculTauEnHyperCreux = OUI_SPX; +} +else if ( Spx->CountEchecsTau <= 0 ) { + Spx->CountEchecsTau = 0; + if ( Spx->CalculTauEnHyperCreux == NON_SPX ) Spx->AvertissementsEchecsTau++; + if ( Spx->AvertissementsEchecsTau >= SEUIL_ABANDON_HYPER_CREUX ) { + # if VERBOSE_SPX + printf("Arret prolonge de l'hyper creux pour le steepest edge, iteration %d\n",Spx->Iteration); + # endif + Spx->CalculTauEnHyperCreuxPossible = NON_SPX; + } +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_steepest_resolution_avec_base_complete.c b/src/ext/Sirius_Solver/simplexe/spx_dual_steepest_resolution_avec_base_complete.c new file mode 100644 index 0000000000..b297eadfcc --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_steepest_resolution_avec_base_complete.c @@ -0,0 +1,195 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_DualSteepestEdgeResolutionAvecBaseComplete( PROBLEME_SPX * Spx, double * BetaPReturn, + char ResolutionEnHyperCreux, char * ResetRefSpace, + int * NbTermesNonNulsDeTau, char * StockageDeTau, + char * LeSystemeAEteResolu ) +{ +int Var; int il; int ilMax; char Save; double BetaP; double X; char ResoudreLeSysteme; +char SecondMembreCreux; int * Cdeb; int * CNbTerm; double * NBarreR; char * InDualFramework; +int * NumerosDesVariablesHorsBase ; int * NumeroDeContrainte; int i; double * ACol; double * Tau; +char TypeDEntree; char TypeDeSortie; int j; int k; int * NumVarNBarreRNonNul; int * T; +int * IndexTermesNonNulsDeTau; int NbTermesNonNuls; char HyperCreuxInitial; + +*ResetRefSpace = NON_SPX; +BetaP = *BetaPReturn; + +T = Spx->T; +IndexTermesNonNulsDeTau = (int *) Spx->ErBMoinsUn; + +InDualFramework = Spx->InDualFramework; +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +NBarreR = Spx->NBarreR; +Tau = Spx->Tau; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; +ACol = Spx->ACol; + +ResoudreLeSysteme = NON_SPX; +*LeSystemeAEteResolu = ResoudreLeSysteme; +NbTermesNonNuls = 0 ; + +if ( Spx->TypeDeStockageDeNBarreR == ADRESSAGE_INDIRECT_SPX ) { + NumVarNBarreRNonNul = Spx->NumVarNBarreRNonNul; + if ( ResolutionEnHyperCreux == OUI_SPX ) { + *StockageDeTau = ADRESSAGE_INDIRECT_SPX; + /*NbTermesNonNuls = 0;*/ + for ( j = 0 ; j < Spx->NombreDeValeursNonNullesDeNBarreR ; j++ ) { + Var = NumVarNBarreRNonNul[j]; + if ( InDualFramework[Var] == NON_SPX ) continue; + X = NBarreR[Var]; + if ( X == 0.0 ) continue; + /* Calcul sur les variables hors base qui sont dans le framework */ + ResoudreLeSysteme = OUI_SPX; + BetaP += X * X; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + k = NumeroDeContrainte[il]; + if ( T[k] == -1 ) { + T[k] = 1; + IndexTermesNonNulsDeTau[NbTermesNonNuls] = k; + NbTermesNonNuls++; + } + Tau[k] += X * ACol[il]; + il++; + } + } + if ( NbTermesNonNuls != 0 ) ResoudreLeSysteme = OUI_SPX; + for ( j = 0 ; j < NbTermesNonNuls ; j++ ) T[IndexTermesNonNulsDeTau[j]] = -1; + + TypeDEntree = ADRESSAGE_INDIRECT_LU; + TypeDeSortie = ADRESSAGE_INDIRECT_LU; + + } + else { + /* Pas de resolution hyper creux */ + *StockageDeTau = VECTEUR_SPX; + ResolutionEnHyperCreux = NON_SPX; + for ( j = 0 ; j < Spx->NombreDeValeursNonNullesDeNBarreR ; j++ ) { + Var = NumVarNBarreRNonNul[j]; + if ( InDualFramework[Var] == NON_SPX ) continue; + X = NBarreR[Var]; + if ( X == 0.0 ) continue; + /* Calcul sur les variables hors base qui sont dans le framework */ + ResoudreLeSysteme = OUI_SPX; + BetaP+= X * X; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + Tau[NumeroDeContrainte[il]]+= X * ACol[il]; + il++; + } + } + + TypeDEntree = VECTEUR_LU; + TypeDeSortie = VECTEUR_LU; + + } +} +else { + /* Pas de resolution hyper creux */ + *StockageDeTau = VECTEUR_SPX; + ResolutionEnHyperCreux = NON_SPX; + for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + if ( InDualFramework[Var] == NON_SPX ) continue; + if ( NBarreR[Var] == 0.0 ) continue; + X = NBarreR[Var]; + /* Calcul sur les variables hors base qui sont dans le framework */ + ResoudreLeSysteme = OUI_SPX; + BetaP+= X * X; + /* */ + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + Tau[NumeroDeContrainte[il]]+= X * ACol[il]; + il++; + } + } + + TypeDEntree = VECTEUR_LU; + TypeDeSortie = VECTEUR_LU; + +} + +*LeSystemeAEteResolu = ResoudreLeSysteme; +HyperCreuxInitial = ResolutionEnHyperCreux; + +SPX_DualSteepestControleDuPoidsDeCntBase( Spx, BetaP, ResetRefSpace ); +if ( *ResetRefSpace == OUI_SPX ) { + return; +} + +/* Dynamic steepest edge: si la variable sortante est une variable basique artificielle on l'enleve de + l'espace de reference */ +SPX_DualSteepestVariablesDeBornesIdentiques( Spx, &BetaP ); + +*BetaPReturn = BetaP; + +/* Resolution du systeme Tau = B^{-1} Tau */ +if ( ResoudreLeSysteme == OUI_SPX ) { + Save = NON_LU; + SecondMembreCreux = OUI_LU; + + if ( ResolutionEnHyperCreux == OUI_SPX ) { + if ( NbTermesNonNuls >= TAUX_DE_REMPLISSAGE_POUR_VECTEUR_HYPER_CREUX * Spx->NombreDeContraintes ) { + ResolutionEnHyperCreux = NON_SPX; + *StockageDeTau = VECTEUR_SPX; + TypeDeSortie = VECTEUR_LU; + } + } + + SPX_ResoudreBYegalA( Spx, TypeDEntree, Tau, IndexTermesNonNulsDeTau, &NbTermesNonNuls, &TypeDeSortie, + ResolutionEnHyperCreux, Save, SecondMembreCreux ); + + SPX_DualSteepestGestionIndicateursHyperCreux( Spx, ResolutionEnHyperCreux, HyperCreuxInitial, TypeDeSortie, + StockageDeTau, ResetRefSpace ); + if ( *ResetRefSpace == OUI_SPX ) return; +} + +*NbTermesNonNulsDeTau = NbTermesNonNuls; + +if ( TypeDeSortie == ADRESSAGE_INDIRECT_LU ) *StockageDeTau = ADRESSAGE_INDIRECT_SPX; +else if ( TypeDeSortie == VECTEUR_LU ) *StockageDeTau = VECTEUR_SPX; +else { + printf("BUG dans SPX_DualSteepestEdgeResolutionAvecBaseComplete TypeDeSortie = %d est incorrect\n",TypeDeSortie); + exit(0); +} +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_steepest_resolution_avec_base_reduite.c b/src/ext/Sirius_Solver/simplexe/spx_dual_steepest_resolution_avec_base_reduite.c new file mode 100644 index 0000000000..3fbf1aa3f7 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_steepest_resolution_avec_base_reduite.c @@ -0,0 +1,318 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution avec la base reduite. + On ne calcule Tau que pour les contraintes de la base reduite. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +# define DEBUG NON_SPX + +/*----------------------------------------------------------------------------*/ + +void SPX_DualSteepestEdgeResolutionBaseReduite( PROBLEME_SPX * Spx, double * BetaPReturn, + char ResolutionEnHyperCreux, char * ResetRefSpace, + int * NbTermesNonNulsDeTau, char * StockageDeTau, + char * LeSystemeAEteResolu ) +{ +int Var; int il ; int ilMax; char Save; double BetaP; double X; char ResoudreLeSysteme; +char SecondMembreCreux; int * CdebProblemeReduit; int * CNbTermProblemeReduit; double * NBarreR; +char * InDualFramework; int * NumerosDesVariablesHorsBase; int * IndicesDeLigneDesTermesDuProblemeReduit; +int i; double * ValeurDesTermesDesColonnesDuProblemeReduit; double * Tau; char TypeDEntree; +char TypeDeSortie; int j; int * NumVarNBarreRNonNul; int * T; int NbTermesNonNuls; +char HyperCreuxInitial; int * OrdreLigneDeLaBaseFactorisee; int RangDeLaMatriceFactorisee; +int r; int * IndexTermesNonNulsDeTau; + +*ResetRefSpace = NON_SPX; +BetaP = *BetaPReturn; + +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; + +OrdreLigneDeLaBaseFactorisee = Spx->OrdreLigneDeLaBaseFactorisee; + +InDualFramework = Spx->InDualFramework; +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +NBarreR = Spx->NBarreR; + +Tau = Spx->Tau; +IndexTermesNonNulsDeTau = (int *) Spx->ErBMoinsUn; + +CdebProblemeReduit = Spx->CdebProblemeReduit; +CNbTermProblemeReduit = Spx->CNbTermProblemeReduit; +IndicesDeLigneDesTermesDuProblemeReduit = Spx->IndicesDeLigneDesTermesDuProblemeReduit; +ValeurDesTermesDesColonnesDuProblemeReduit = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; + +T = Spx->T; + +ResoudreLeSysteme = NON_SPX; +*LeSystemeAEteResolu = ResoudreLeSysteme; + +NbTermesNonNuls = 0; + +if ( Spx->TypeDeStockageDeNBarreR == ADRESSAGE_INDIRECT_SPX ) { + NumVarNBarreRNonNul = Spx->NumVarNBarreRNonNul; + if ( ResolutionEnHyperCreux == OUI_SPX ) { + *StockageDeTau = ADRESSAGE_INDIRECT_SPX; + for ( j = 0 ; j < Spx->NombreDeValeursNonNullesDeNBarreR ; j++ ) { + Var = NumVarNBarreRNonNul[j]; + if ( InDualFramework[Var] == NON_SPX ) continue; + X = NBarreR[Var]; + if ( X == 0.0 ) continue; + /* Calcul sur les variables hors base qui sont dans le framework */ + BetaP += X * X; + il = CdebProblemeReduit[Var]; + ilMax = il + CNbTermProblemeReduit[Var]; + while ( il < ilMax ) { + r = IndicesDeLigneDesTermesDuProblemeReduit[il]; + if ( T[r] == -1 ) { + T[r] = 1; + IndexTermesNonNulsDeTau[NbTermesNonNuls] = r; + NbTermesNonNuls++; + } + Tau[r] += X * ValeurDesTermesDesColonnesDuProblemeReduit[il]; + il++; + } + } + if ( NbTermesNonNuls != 0 ) ResoudreLeSysteme = OUI_SPX; + /* Raz de T */ + for ( j = 0 ; j < NbTermesNonNuls ; j++ ) T[IndexTermesNonNulsDeTau[j]] = -1; + + TypeDEntree = ADRESSAGE_INDIRECT_LU; + TypeDeSortie = ADRESSAGE_INDIRECT_LU; + + } + else { + /* Pas de resolution hyper creux */ + *StockageDeTau = VECTEUR_SPX; + ResolutionEnHyperCreux = NON_SPX; + /* Base reduite */ + for ( j = 0 ; j < Spx->NombreDeValeursNonNullesDeNBarreR ; j++ ) { + Var = NumVarNBarreRNonNul[j]; + if ( InDualFramework[Var] == NON_SPX ) continue; + X = NBarreR[Var]; + if ( X == 0.0 ) continue; + /* Calcul sur les variables hors base qui sont dans le framework */ + ResoudreLeSysteme = OUI_SPX; + BetaP += X * X; + il = CdebProblemeReduit[Var]; + ilMax = il + CNbTermProblemeReduit[Var]; + while ( il < ilMax ) { + Tau[IndicesDeLigneDesTermesDuProblemeReduit[il]] += X * ValeurDesTermesDesColonnesDuProblemeReduit[il]; + il++; + } + } + TypeDEntree = VECTEUR_LU; + TypeDeSortie = VECTEUR_LU; + } +} +else { + /* Pas de resolution hyper creux */ + *StockageDeTau = VECTEUR_SPX; + ResolutionEnHyperCreux = NON_SPX; + /* Base reduite */ + for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + if ( InDualFramework[Var] == NON_SPX ) continue; + if ( NBarreR[Var] == 0.0 ) continue; + X = NBarreR[Var]; + if ( X == 0.0 ) continue; + /* Calcul sur les variables hors base qui sont dans le framework */ + ResoudreLeSysteme = OUI_SPX; + BetaP += X * X; + /* */ + il = CdebProblemeReduit[Var]; + ilMax = il + CNbTermProblemeReduit[Var]; + while ( il < ilMax ) { + Tau[IndicesDeLigneDesTermesDuProblemeReduit[il]] += X * ValeurDesTermesDesColonnesDuProblemeReduit[il]; + il++; + } + } + TypeDEntree = VECTEUR_LU; + TypeDeSortie = VECTEUR_LU; +} + +*LeSystemeAEteResolu = ResoudreLeSysteme; +HyperCreuxInitial = ResolutionEnHyperCreux; + +SPX_DualSteepestControleDuPoidsDeCntBase( Spx, BetaP, ResetRefSpace ); +if ( *ResetRefSpace == OUI_SPX ) { + return; +} + +/* Dynamic steepest edge: si la variable sortante est une variable basique artificielle on l'enleve de + l'espace de reference */ +SPX_DualSteepestVariablesDeBornesIdentiques( Spx, &BetaP ); + +*BetaPReturn = BetaP; + +/* Resolution du systeme */ + +if ( ResoudreLeSysteme == OUI_SPX ) { + Save = NON_LU; + SecondMembreCreux = OUI_LU; + + if ( ResolutionEnHyperCreux == OUI_SPX ) { + if ( NbTermesNonNuls >= TAUX_DE_REMPLISSAGE_POUR_VECTEUR_HYPER_CREUX * RangDeLaMatriceFactorisee ) { + ResolutionEnHyperCreux = NON_SPX; + *StockageDeTau = VECTEUR_SPX; + TypeDeSortie = VECTEUR_LU; + } + } + + SPX_ResolutionDeSysteme( Spx, TypeDEntree, Tau, IndexTermesNonNulsDeTau, &NbTermesNonNuls, + &TypeDeSortie, ResolutionEnHyperCreux, Save, SecondMembreCreux ); + +} + +/* Eventuellement forme produit de l'inverse */ +if ( ResoudreLeSysteme == OUI_SPX ) { + if ( Spx->UtiliserLaLuUpdate == NON_SPX ) { + SPX_AppliquerLesEtaVecteurs( Spx, Tau, IndexTermesNonNulsDeTau, &NbTermesNonNuls, ResolutionEnHyperCreux, TypeDeSortie ); + } + + + SPX_DualSteepestGestionIndicateursHyperCreux( Spx, ResolutionEnHyperCreux, HyperCreuxInitial, TypeDeSortie, + StockageDeTau, ResetRefSpace ); + if ( *ResetRefSpace == OUI_SPX ) return; + +} + +*NbTermesNonNulsDeTau = NbTermesNonNuls; + +if ( TypeDeSortie == ADRESSAGE_INDIRECT_LU ) *StockageDeTau = ADRESSAGE_INDIRECT_SPX; +else if ( TypeDeSortie == VECTEUR_LU ) *StockageDeTau = VECTEUR_SPX; +else { + printf("BUG dans SPX_DualSteepestEdgeResolutionAvecBaseReduite TypeDeSortie = %d est incorrect\n",TypeDeSortie); + exit(0); +} + +# if VERIFICATION_STEEPEST == OUI_SPX +printf("---------------- DualSteepestEdgeResolutionBaseReduite Spx->NombreDeChangementsDeBase %d -------------\n",Spx->NombreDeChangementsDeBase); +if ( TypeDEntree == VECTEUR_LU ) printf("apres resolution TypeDEntree = VECTEUR_LU"); +if ( TypeDEntree == ADRESSAGE_INDIRECT_LU ) printf("apres resolution TypeDEntree = ADRESSAGE_INDIRECT_LU"); +if ( TypeDeSortie == VECTEUR_LU ) printf(" TypeDeSortie = VECTEUR_LU\n"); +if ( TypeDeSortie == ADRESSAGE_INDIRECT_LU ) printf(" TypeDeSortie = ADRESSAGE_INDIRECT_LU\n"); +{ +double * Buff; int Var; int ic; int icMx; double * Sortie; char Arret; int rr; +Buff = (double *) malloc( RangDeLaMatriceFactorisee * sizeof( double ) ); +Sortie = (double *) malloc( RangDeLaMatriceFactorisee * sizeof( double ) ); +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) Sortie[r]= 0; +if ( TypeDeSortie == ADRESSAGE_INDIRECT_LU ) { + for ( i = 0 ; i < NbTermesNonNuls ; i++ ) { + Sortie[IndexTermesNonNulsDeTau[i]] = Tau[IndexTermesNonNulsDeTau[i]]; + } +} +else if ( TypeDeSortie == VECTEUR_LU ) { + for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) Sortie[r] = Tau[r]; +} +else { + printf("Bug dans DualSteepestEdgeResolutionBaseReduite\n"); + exit(0); +} + +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) Buff[r]= 0; +if ( Spx->TypeDeStockageDeNBarreR == ADRESSAGE_INDIRECT_SPX ) { + NumVarNBarreRNonNul = Spx->NumVarNBarreRNonNul; + for ( j = 0 ; j < Spx->NombreDeValeursNonNullesDeNBarreR ; j++ ) { + Var = NumVarNBarreRNonNul[j]; + if ( InDualFramework[Var] == NON_SPX ) continue; + X = NBarreR[Var]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + r = OrdreLigneDeLaBaseFactorisee[NumeroDeContrainte[il]]; + if ( r < RangDeLaMatriceFactorisee ) { + Buff[r] += X * ACol[il]; + } + il++; + } + } +} +else { + for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + if ( InDualFramework[Var] == NON_SPX ) continue; + X = NBarreR[Var]; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + r = OrdreLigneDeLaBaseFactorisee[NumeroDeContrainte[il]]; + if ( r < RangDeLaMatriceFactorisee ) { + Buff[r]+= X * ACol[il]; + } + il++; + } + } +} + +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + if ( Sortie[r] == 0 ) continue; + Var = Spx->VariableEnBaseDeLaContrainte[Spx->ColonneDeLaBaseFactorisee[r]]; + ic = Spx->Cdeb[Var]; + icMx = ic + Spx->CNbTerm[Var]; + while ( ic < icMx ) { + rr = OrdreLigneDeLaBaseFactorisee[NumeroDeContrainte[ic]]; + if ( rr < RangDeLaMatriceFactorisee ) { + Buff[rr] -= ACol[ic] * Sortie[r]; + } + ic++; + } +} +Arret = NON_SPX; +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + if ( fabs( Buff[r] ) > 1.e-7 ) { + printf("r = %d ecart %e\n",r,Buff[r]); + Var = Spx->VariableEnBaseDeLaContrainte[Spx->ColonneDeLaBaseFactorisee[r]]; + if ( Spx->OrigineDeLaVariable[Var] != NATIVE ) printf(" variable non native\n"); + else printf(" variable native\n"); + Arret = OUI_SPX; + } +} +if ( Arret == OUI_SPX ) { + printf("Verif Tau not OK\n"); + exit(0); +} +printf("Fin verif Tau OK\n"); +free( Buff ); +free( Sortie ); + +} + +SPX_VerifierLesVecteursDeTravail( Spx ); + +printf("VerifierLesVecteursDeTravail OK\n"); + +# endif + + +return; +} + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_strong_branching.c b/src/ext/Sirius_Solver/simplexe/spx_dual_strong_branching.c new file mode 100644 index 0000000000..c5df1926ab --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_strong_branching.c @@ -0,0 +1,405 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Comme son nom l'indique + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_define.h" + +# include "lu_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_DualStrongBranching( + PROBLEME_SPX * Spx , + /* La variable a brancher */ + int VariableSortante , + double CoutDeLaVariableSortante, + double NouvelleBorneMin , + double NouvelleBorneMax , + /* Sortie */ + double * CoutReduitDeLaVariableBranchee, + int * YaUneSolution, + char * TypeDeSolution, + double * X, + int * PositionDeLaVariable, + int * NbVarDeBaseComplementaires, + int * ComplementDeLaBase, + /* Donnees initiales du probleme (elles sont utilisees par SPX_RecupererLaSolution) */ + int NbVar_E, + int * TypeVar_E, + int NbContr_E, + /* Dans le but de recuperer les informations sur les coupes */ + int NombreDeContraintesCoupes, + int * NbTermCoupes, + char * PositionDeLaVariableDEcartCoupes + ) +{ +/*int Var; */ int Cnt; int VariableSortanteSv; int TypeDeSortieSv ; int NbMaxIterations; +char ControleFaitOptimumNonBorne ; int il; int ilMax ; char ArretDemande ; +double XminSV ; double XmaxSV ; double XminEntreeSV ; double DeltaCoutFixe; +char ControlerAdmissibiliteDuale; +/* double S; int ic; int icMax; int NbCntrl; */ + +/* Ensuite Bs sera toujours remis a 0 des qu'on aura fini de s'en servir */ +memset( (char *) Spx->Bs , 0 , Spx->NombreDeContraintes * sizeof( double ) ); + +CoutDeLaVariableSortante = 0; /* Pour ne pas avoir de warning a la compilation */ + +Spx->SeuilDePivotDual = VALEUR_DE_PIVOT_ACCEPTABLE; + +Spx->StrongBranchingEnCours = OUI_SPX; +Spx->UtiliserLaLuUpdate = NON_SPX; +Spx->FaireDuRaffinementIteratif = 0; + +/* Le numero fourni ne peut pas etre dans la numerotation interne au simplexe car l'appelant n'y a + pas acces */ +Spx->VariableSortante = Spx->CorrespondanceVarEntreeVarSimplexe[VariableSortante]; +VariableSortanteSv = Spx->VariableSortante; + +if ( Spx->PositionDeLaVariable[Spx->VariableSortante] == HORS_BASE_SUR_BORNE_INF || + Spx->PositionDeLaVariable[Spx->VariableSortante] == HORS_BASE_SUR_BORNE_SUP || + Spx->PositionDeLaVariable[Spx->VariableSortante] == HORS_BASE_A_ZERO ) { + printf("Bug dans SPX_DualStrongBranching, la variable sortante %d n'est pas basique. ",Spx->VariableSortante); + if ( Spx->PositionDeLaVariable[Spx->VariableSortante] == HORS_BASE_SUR_BORNE_INF ) { + printf("Elle est HORS_BASE_SUR_BORNE_INF\n"); + } + else if ( Spx->PositionDeLaVariable[Spx->VariableSortante] == HORS_BASE_SUR_BORNE_SUP ) { + printf("Elle est HORS_BASE_SUR_BORNE_SUP\n"); + } + else if ( Spx->PositionDeLaVariable[Spx->VariableSortante] == HORS_BASE_A_ZERO ) { + printf("elle est HORS_BASE_A_ZERO\n"); + } + printf("Valeur calculee par le simplexe: %lf valeur min: %lf valeur max: %lf\n", + Spx->X[Spx->VariableSortante],Spx->Xmin[Spx->VariableSortante],Spx->Xmin[Spx->VariableSortante]); + exit(0); +} + +XminEntreeSV = Spx->XminEntree[Spx->VariableSortante]; /* XminEntree n'a pas subi de scaling */ +Spx->XminEntree[Spx->VariableSortante] = NouvelleBorneMin; + +XminSV = Spx->Xmin[Spx->VariableSortante]; +XmaxSV = Spx->Xmax[Spx->VariableSortante]; + +/* En comparant la valeur de X a ses nouvelles bornes, on en deduit le type de sortie de la base */ +/* Scaling des bornes externes */ +Spx->Xmin[Spx->VariableSortante] = NouvelleBorneMin; +Spx->Xmax[Spx->VariableSortante] = NouvelleBorneMax; +if ( Spx->TypeDeVariable[Spx->VariableSortante] != NON_BORNEE ) { + Spx->Xmin[Spx->VariableSortante] = Spx->Xmin[Spx->VariableSortante] / Spx->ScaleX[Spx->VariableSortante]; +} +if ( Spx->TypeDeVariable[Spx->VariableSortante] == BORNEE ) { + Spx->Xmax[Spx->VariableSortante] = Spx->Xmax[Spx->VariableSortante] / Spx->ScaleX[Spx->VariableSortante]; +} + +if ( Spx->X[Spx->VariableSortante] >= Spx->Xmax[Spx->VariableSortante] ) Spx->SortSurXmaxOuSurXmin = SORT_SUR_XMAX; +else if ( Spx->X[Spx->VariableSortante] <= Spx->Xmin[Spx->VariableSortante] ) Spx->SortSurXmaxOuSurXmin = SORT_SUR_XMIN; +else { + printf("Bug dans SPX_StrongBranching, demande de branchement sur la variable %d or elle a deja une valeur entiere\n", + VariableSortante); + exit(0); +} + +if ( Spx->TypeDeVariable[Spx->VariableSortante] == BORNEE && + Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN) { + DeltaCoutFixe = ( Spx->C[Spx->VariableSortante] * XmaxSV ) / Spx->ScaleLigneDesCouts; +} +else DeltaCoutFixe = 0.; + +TypeDeSortieSv = Spx->SortSurXmaxOuSurXmin; + +/* On simule la translation des bornes */ +Spx->Xmin[Spx->VariableSortante] = 0.; +Spx->Xmax[Spx->VariableSortante] = 0.; + +if( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + /* Faire un passage a XmaxEntree c'est imposer XminEntree = XmaxEntree . La translation des bornes ayant pour + effet de modifier le second membre, il faut mettre a jour BBarre */ + Cnt = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; + Spx->BBarre[Cnt] = ( XmaxSV - Spx->BBarre[Cnt] ) * -1.; + Spx->X[Spx->VariableSortante] = Spx->BBarre[Cnt]; + + /* Dans les calculs qui suivent on est amene calculer entierement le vecteur BBarre. Il faut donc + tenir compte de la modification du second membre B qui decoulerait du fait que la variable + dont on simule l'instanciation se retrouve avec Xmin = Xmax */ + il = Spx->Cdeb[Spx->VariableSortante]; + ilMax = il + Spx->CNbTerm[Spx->VariableSortante]; + while ( il < ilMax ) { + Spx->B[Spx->NumeroDeContrainte[il]]-= Spx->ACol[il] * XmaxSV; + il++; + } +} + +/* La base factorisee est la base courante et on s'arrete des qu'il faut factoriser + la base */ + +Spx->LastEta = -1; +Spx->NombreDeChangementsDeBase = 0; + +*YaUneSolution = OUI_SPX; +*TypeDeSolution = STRONG_BRANCHING_NON_DEFINI; +Spx->FactoriserLaBase = NON_SPX; +Spx->ModifCoutsAutorisee = NON_SPX; +Spx->NbCyclesSansControleDeDegenerescence = (int) floor( 0.5 * Spx->CycleDeControleDeDegenerescence ); +Spx->Iteration = 0; +ControleFaitOptimumNonBorne = NON_SPX; +ArretDemande = NON_SPX; +NbMaxIterations = NOMBRE_DITERATIONS_DE_STRONG_BRANCHING; + +if ( NbMaxIterations > CYCLE_DE_REFACTORISATION_DUAL - 1 ) NbMaxIterations = CYCLE_DE_REFACTORISATION_DUAL - 1; + +/* Inutile de calculer BBarre a la premiere iteration */ +Spx->CalculerBBarre = NON_SPX; + +/* Inutile de calculer CBarre a la premiere iteration */ +Spx->CalculerCBarre = NON_SPX; + +SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); +/* Car au depart CalculerBBarre est egal a NON_SPX */ +SPX_InitialiserLesVariablesEnBaseAControler( Spx ); + +Spx->PhaseEnCours = PHASE_2; + +while ( 1 ) { + + Spx->Iteration++; + /* + printf("Strong branching iteration de simplexe numero %d\n",Spx->Iteration); + */ + /* Calcul de BBarre c'est a dire B^{-1} * b */ + if ( Spx->CalculerBBarre == OUI_SPX ) { + SPX_CalculerBBarre( Spx ); + Spx->CalculerBBarre = NON_SPX; + } + if ( Spx->Iteration >= NbMaxIterations || ArretDemande == OUI_SPX ) { + /* Clause de sortie */ + *YaUneSolution = OUI_SPX; + *TypeDeSolution = STRONG_BRANCHING_MXITER_OU_REFACT; + #if VERBOSE_SPX + if( Spx->Iteration >= NbMaxIterations ) printf(" Fin strong branching par nombre max d'iterations atteint\n"); + if( ArretDemande == OUI_SPX ) printf(" Fin strong branching par refactorisation demandee \n"); + #endif + break; + } + + /* Verification: si le cout courant depasse le cout max fourni, alors on + arrete les calculs car le cout courant est un minorant du cout optimal. + Remarque on peut tout a fait reprendre l'indicateur Spx->UtiliserCoutMax + et la valeur Spx->CoutMax utilisee a la resolution precedente */ + if ( Spx->UtiliserCoutMax == OUI_SPX && Spx->Iteration > 1 ) { + /*SPX_CalculDuCout( Spx );*/ + SPX_CalculDuCoutSimplifie( Spx ); + if ( Spx->Cout + DeltaCoutFixe > Spx->CoutMax ) { + *YaUneSolution = NON_SPX; + *TypeDeSolution = STRONG_BRANCHING_COUT_MAX_DEPASSE; + #if VERBOSE_SPX + printf(" Fin strong branching par depassement du cout max \n"); + #endif + break; + } + } + + /* Choix de la variable qui quitte la base: attention, a la premiere iteration la variable sortante + a deja ete choisie */ + if ( Spx->Iteration > 1 ) SPX_DualChoixDeLaVariableSortante( Spx ); + if ( Spx->VariableSortante < 0 ) { + /* Optimalite atteinte */ + #if VERBOSE_SPX + printf(" Fin strong branching par optimalite\n"); + #endif + *YaUneSolution = OUI_SPX; + *TypeDeSolution = STRONG_BRANCHING_OPTIMALITE; + break; /* Fin du while car optimum atteint */ + } + + SPX_DualCalculerNBarreR( Spx, OUI_SPX, &ControlerAdmissibiliteDuale ); + SPX_DualVerifierErBMoinsUn( Spx ); + + if ( Spx->FactoriserLaBase == OUI_SPX ) { + #if VERBOSE_SPX + printf(" Fin strong branching par FactoriserLaBase = OUI \n"); + #endif + *YaUneSolution = OUI_SPX; + *TypeDeSolution = STRONG_BRANCHING_REFACTORISATION; + break; + } + + if ( Spx->NombreDeVariablesATester <= 0 ) { + /* Mise a jour de l'indicateur: Spx->AdmissibilitePossible (on s'en sert plus tard) */ + SPX_DualConfirmerDualNonBorne( Spx ); + } + + /* Choix de la variable entrante */ + SPX_DualChoixDeLaVariableEntrante( Spx ); + if ( Spx->VariableEntrante < 0 ) { + if ( Spx->AdmissibilitePossible == OUI_SPX ) { + #if VERBOSE_SPX + printf("Spx->AdmissibilitePossible = OUI_SPX => on considere quand meme qu'il y a une solution admissible\n"); + #endif + *YaUneSolution = OUI_SPX; + *TypeDeSolution = STRONG_BRANCHING_OPTIMALITE; + break; + } + else { + #if VERBOSE_SPX + printf("Spx->AdmissibilitePossible = NON_SPX\n"); + #endif + } + + #if VERBOSE_SPX + printf(" Fin strong branching par dual non borne \n"); + #endif + + *YaUneSolution = NON_SPX; + *TypeDeSolution = STRONG_BRANCHING_PAS_DE_SOLUTION; + break; + } + + if ( Spx->FactoriserLaBase == OUI_SPX ) { + #if VERBOSE_SPX + printf(" Fin strong branching par FactoriserLaBase = OUI \n"); + #endif + /* On ne peut pas s'arreter brutalement car il a pu y avoir des bound flip ce qui fait + que les valeurs des variables en base doivent etre recalculees */ + Spx->FactoriserLaBase = NON_SPX; + ArretDemande = OUI_SPX; + } + else { + SPX_CalculerABarreS( Spx ); /* On en a aussi besoin pour le steepest edge et pour les controles */ + /*SPX_VerifierABarreS( Spx );*/ + + /* On fait toujours le changement de base meme s'il y a une imprecision */ + Spx->FaireChangementDeBase = OUI_SPX; + + /* Mise a jour des poids de la methode projected steepest edge */ + SPX_MajPoidsDualSteepestEdge( Spx ); + if ( Spx->FactoriserLaBase == OUI_SPX ) { + #if VERBOSE_SPX + printf(" Fin strong branching par FactoriserLaBase = OUI \n"); + #endif + Spx->FactoriserLaBase = NON_SPX; + ArretDemande = OUI_SPX; + } + } + + SPX_MettreAJourLesCoutsReduits( Spx ); + + if ( Spx->FaireMiseAJourDeBBarre == OUI_SPX ) { + SPX_MettreAJourBBarre( Spx ); + Spx->CalculerBBarre = NON_SPX; + } + else Spx->CalculerBBarre = OUI_SPX; + + SPX_FaireLeChangementDeBase( Spx ); + + /* Apres chaque chagement de base reussi on essaie de revenir au seuil de pivotage initial */ + if ( Spx->SeuilDePivotDual > VALEUR_DE_PIVOT_ACCEPTABLE ) { + Spx->SeuilDePivotDual /= DIVISEUR_VALEUR_DE_PIVOT_ACCEPTABLE; + if ( Spx->SeuilDePivotDual < VALEUR_DE_PIVOT_ACCEPTABLE ) Spx->SeuilDePivotDual = VALEUR_DE_PIVOT_ACCEPTABLE; + } + + /* Si la factorisation s'est mal passee */ + if ( Spx->FactoriserLaBase == OUI_SPX ) ArretDemande = OUI_SPX; + +} + +*CoutReduitDeLaVariableBranchee = 0.0; +if ( *YaUneSolution == OUI_SPX ) { + if ( Spx->PositionDeLaVariable[VariableSortanteSv] != EN_BASE_LIBRE ) { + *CoutReduitDeLaVariableBranchee = fabs( Spx->CBarre[VariableSortanteSv] ); + } +} + +/* Maintenant on peut recuperer la valeur du critere correspondant a la solution courante ainsi + que la base puisqu'elle est duale realisable et qu'elle pourra etre reutilisee lors d'une optimisation + complete */ + +SPX_FixerXEnFonctionDeSaPosition( Spx ); + +SPX_RecupererLaSolution( + Spx, + NbVar_E, + X, + TypeVar_E, + NbContr_E, + PositionDeLaVariable, + NbVarDeBaseComplementaires, + ComplementDeLaBase +/* + InDualFramework, + DualPoids +*/ + ); + +if ( NombreDeContraintesCoupes > 0 ) { + SPX_RecupererLaSolutionSurLesCoupes( Spx , NombreDeContraintesCoupes , NbTermCoupes , PositionDeLaVariableDEcartCoupes ); +} + +Spx->Xmin[VariableSortanteSv] = XminSV; +Spx->Xmax[VariableSortanteSv] = XmaxSV; + +Spx->XminEntree[VariableSortanteSv] = XminEntreeSV; + +if( TypeDeSortieSv == SORT_SUR_XMIN ) { + il = Spx->Cdeb[VariableSortanteSv]; + ilMax = il + Spx->CNbTerm[VariableSortanteSv]; + while ( il < ilMax ) { + Spx->B[Spx->NumeroDeContrainte[il]]+= Spx->ACol[il] * XmaxSV; + il++; + } +} + +#if VERBOSE_SPX + printf(" Iteration de sortie du strong branching %d\n",Spx->Iteration); fflush(stdout); +#endif + +/* On remet les donnees internes du simplexe dans l'etat initial */ +il = Spx->NombreDeVariables * sizeof( double ); +memcpy( (char *) Spx->X, (char *) Spx->XSV, il ); +memcpy( (char *) Spx->CBarre, (char *) Spx->CBarreSV, il ); +memcpy( (char *) Spx->C, (char *) Spx->Csv, il ); +il = Spx->NombreDeVariables * sizeof( int ); +memcpy( (char *) Spx->ContrainteDeLaVariableEnBase, (char *) Spx->ContrainteDeLaVariableEnBaseSV, il ); +il = Spx->NombreDeVariables * sizeof( char ); +memcpy( (char *) Spx->PositionDeLaVariable, (char *) Spx->PositionDeLaVariableSV, il ); +memcpy( (char *) Spx->InDualFramework, (char *) Spx->InDualFrameworkSV, il ); + +il = Spx->NombreDeContraintes * sizeof( double ); +memcpy( (char *) Spx->BBarre, (char *) Spx->BBarreSV, il ); +memcpy( (char *) Spx->DualPoids, (char *) Spx->DualPoidsSV, il ); +il = Spx->NombreDeContraintes * sizeof( int ); +memcpy( (char *) Spx->VariableEnBaseDeLaContrainte, (char *) Spx->VariableEnBaseDeLaContrainteSV, il ); +memcpy( (char *) Spx->CdebBase, (char *) Spx->CdebBaseSV, il ); +memcpy( (char *) Spx->NbTermesDesColonnesDeLaBase, (char *) Spx->NbTermesDesColonnesDeLaBaseSV, il ); + +Spx->LastEta = -1; +Spx->NombreDeChangementsDeBase = 0; +Spx->Iteration = 0; + +return; + +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_strong_branching_GUB.c b/src/ext/Sirius_Solver/simplexe/spx_dual_strong_branching_GUB.c new file mode 100644 index 0000000000..65318dfc37 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_strong_branching_GUB.c @@ -0,0 +1,312 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Strong Branching pour les GUB. + Remarque: que l'on instancie a gauche ou a droite, on + instancie toujours a 0 + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_define.h" + +# include "lu_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_DualStrongBranchingGUB( + PROBLEME_SPX * Spx, + /* Les variables a brancher */ + int NombreDeVariablesABrancher , + int * NumerosDesVariablesABrancher, + double * XmaxSV, /* Tableau de sauvegarde dimension NombreDeVariablesABrancher */ + /* Sortie */ + int * YaUneSolution , + char * TypeDeSolution , + double * X , + int * PositionDeLaVariable , + int * NbVarDeBaseComplementaires, + int * ComplementDeLaBase , + /* Donnees initiales du probleme (elles sont utilisees par SPX_RecupererLaSolution) */ + int NbVar_E, + int * TypeVar_E, + int NbContr_E, + /* Dans le but de recuperer les informations sur les coupes */ + int NombreDeContraintesCoupes, + int * NbTermCoupes, + char * PositionDeLaVariableDEcartCoupes + ) +{ +int Var; int Cnt; int VarSpx ; int Nb; int NbMaxIterations; char ControleFaitOptimumNonBorne; +char ArretDemande ; int CntBase; char ControlerAdmissibiliteDuale; + +/* Ensuite Bs sera toujours remis a 0 des qu'on aura fini de s'en servir */ +memset( (char *) Spx->Bs , 0 , Spx->NombreDeContraintes * sizeof( double ) ); + +Spx->SeuilDePivotDual = VALEUR_DE_PIVOT_ACCEPTABLE; + +Spx->StrongBranchingEnCours = OUI_SPX; +Spx->UtiliserLaLuUpdate = NON_SPX; + +for ( Nb = 0 ; Nb < NombreDeVariablesABrancher ; Nb++ ) { + +/* Le numero fourni ne peut pas etre dans la numerotation interne au simplexe car l'appelant n'y a + pas acces */ + Var = NumerosDesVariablesABrancher[Nb]; + VarSpx = Spx->CorrespondanceVarEntreeVarSimplexe[Var]; + + XmaxSV [Nb] = Spx->Xmax[VarSpx]; + Spx->Xmax[VarSpx] = Spx->Xmin[VarSpx]; +} + +/* La base factorisee est la base courante et on s'arrete des qu'il faut factoriser + la base */ + +Spx->LastEta = -1; +Spx->NombreDeChangementsDeBase = 0; + +*YaUneSolution = OUI_SPX; +*TypeDeSolution = STRONG_BRANCHING_NON_DEFINI; +Spx->FactoriserLaBase = NON_SPX; +Spx->ModifCoutsAutorisee = NON_SPX; +Spx->NbCyclesSansControleDeDegenerescence = (int) floor( 0.5 * Spx->CycleDeControleDeDegenerescence ); +Spx->Iteration = 0; +ControleFaitOptimumNonBorne = NON_SPX; +ArretDemande = NON_SPX; +NbMaxIterations = NOMBRE_DITERATIONS_DE_STRONG_BRANCHING; +if ( NbMaxIterations > CYCLE_DE_REFACTORISATION_DUAL - 1 ) NbMaxIterations = CYCLE_DE_REFACTORISATION_DUAL - 1; + +Spx->NombreDeBornesAuxiliairesUtilisees = 0; + +/* Inutile de calculer BBarre a la premiere iteration */ +Spx->CalculerBBarre = OUI_SPX; + +/* Inutile de calculer CBarre a la premiere iteration */ +Spx->CalculerCBarre = NON_SPX; + +SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); +/*SPX_InitMatriceDeStockageDesContraintesParLigne( Spx );*/ + +while ( 1 ) { + + Spx->Iteration++; + /* + printf("Strong branching iteration de simplexe numero %d\n",Spx->Iteration); + */ + /* S'il y a des bornes auxiliaires, on essaie cycliquement de remettre les bornes initiales tout + en restant dual realisable */ + # ifdef UTILISER_BORNES_AUXILIAIRES + if ( Spx->NombreDeBornesAuxiliairesUtilisees > 0 ) { + if ( Spx->Iteration % CYCLE_POUR_SUPPRESSION_DES_BORNES_AUXILIAIRES == 0 ) { + SPX_DualSupprimerLesBornesAuxiliaires( Spx ); + } + } + # endif + + /* Calcul de BBarre c'est a dire B^{-1} * b */ + if ( Spx->CalculerBBarre == OUI_SPX ) { + SPX_CalculerBBarre( Spx ); + Spx->CalculerBBarre = NON_SPX; + } + if ( Spx->Iteration >= NbMaxIterations || ArretDemande == OUI_SPX ) { + /* Clause de sortie */ + *YaUneSolution = OUI_SPX; + *TypeDeSolution = STRONG_BRANCHING_MXITER_OU_REFACT; + #if VERBOSE_SPX + if( Spx->Iteration >= NbMaxIterations ) printf(" Fin strong branching par nombre max d'iterations atteint\n"); + if( ArretDemande == OUI_SPX ) printf(" Fin strong branching par refactorisation demandee \n"); + #endif + break; + } + + /* Verification: si le cout courant depasse le cout max fourni, alors on + arrete les calculs car le cout courant est un minorant du cout optimal. + Remarque on peut tout a fait reprendre l'indicateur Spx->UtiliserCoutMax + et la valeur Spx->CoutMax utilisee a la resolution precedente */ + if ( Spx->UtiliserCoutMax == OUI_SPX && Spx->Iteration > 1 ) { + SPX_CalculDuCout( Spx ); + if ( Spx->Cout > Spx->CoutMax ) { + *YaUneSolution = NON_SPX; + #if VERBOSE_SPX + printf(" Fin strong branching par depassement du cout max \n"); + #endif + break; + } + } + /* Choix de la variable qui quitte la base */ + SPX_DualChoixDeLaVariableSortante( Spx ); + if ( Spx->VariableSortante < 0 ) { + /* Optimalite atteinte */ + #if VERBOSE_SPX + printf(" Fin strong branching par optimalite\n"); + #endif + *YaUneSolution = OUI_SPX; + *TypeDeSolution = STRONG_BRANCHING_OPTIMALITE; + break; /* Fin du while car optimum atteint */ + } + + SPX_DualCalculerNBarreR( Spx, OUI_SPX, &ControlerAdmissibiliteDuale ); + SPX_DualVerifierErBMoinsUn( Spx ); + + if ( Spx->FactoriserLaBase == OUI_SPX ) { + #if VERBOSE_SPX + printf(" Fin strong branching par FactoriserLaBase = OUI \n"); + #endif + *YaUneSolution = OUI_SPX; + *TypeDeSolution = STRONG_BRANCHING_REFACTORISATION; + break; + } + + /* SPX_DualCalculerCBarreSurNBarreR(); car c'est calcule dans SPX_DualCalculerNBarreR */ + if ( Spx->NombreDeVariablesATester <= 0 ) { + /* Mise a jour de l'indicateur: Spx->AdmissibilitePossible */ + SPX_DualConfirmerDualNonBorne( Spx ); + } + + /* Choix de la variable entrante */ + SPX_DualChoixDeLaVariableEntrante( Spx ); + if ( Spx->VariableEntrante < 0 ) { + if ( Spx->AdmissibilitePossible == OUI_SPX ) { + #if VERBOSE_SPX + printf("Spx->AdmissibilitePossible = OUI_SPX => on considere quand meme qu'il y a une solution admissible\n"); + #endif + *YaUneSolution = OUI_SPX; + *TypeDeSolution = STRONG_BRANCHING_OPTIMALITE; + break; + } + else { + #if VERBOSE_SPX + printf("Spx->AdmissibilitePossible = NON_SPX\n"); + #endif + } + + #if VERBOSE_SPX + printf(" Fin strong branching par dual non borne \n"); + #endif + *YaUneSolution = NON_SPX; + break; + } + + if ( Spx->FactoriserLaBase == OUI_SPX ) { + #if VERBOSE_SPX + printf(" Fin strong branching par FactoriserLaBase = OUI \n"); + #endif + /* On ne peut pas s'arreter brutalement car il a pu y avoir des bound flip ce qui fait + que les valeurs des variables en base doivent etre recalculees */ + Spx->FactoriserLaBase = NON_SPX; + ArretDemande = OUI_SPX; + } + else { + SPX_CalculerABarreS( Spx ); /* On en a aussi besoin pour le steepest edge et pour les controles */ + SPX_VerifierABarreS( Spx ); + CntBase = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; + SPX_MettreAJourLesCoutsReduits( Spx ); + if ( Spx->FaireMiseAJourDeBBarre == OUI_SPX ) { + SPX_MettreAJourBBarre( Spx ); + Spx->CalculerBBarre = NON_SPX; + } + else Spx->CalculerBBarre = OUI_SPX; + + /* Mise a jour des poids de la methode projected steepest edge */ + SPX_MajPoidsDualSteepestEdge( Spx ); + if ( Spx->FactoriserLaBase == OUI_SPX ) { + #if VERBOSE_SPX + printf(" Fin strong branching par FactoriserLaBase = OUI \n"); + #endif + Spx->FactoriserLaBase = NON_SPX; + ArretDemande = OUI_SPX; + } + } + + SPX_FaireLeChangementDeBase( Spx ); + + /* Apres chaque chagement de base reussi on essaie de revenir au seuil de pivotage initial */ + if ( Spx->SeuilDePivotDual > VALEUR_DE_PIVOT_ACCEPTABLE ) { + Spx->SeuilDePivotDual /= DIVISEUR_VALEUR_DE_PIVOT_ACCEPTABLE; + if ( Spx->SeuilDePivotDual < VALEUR_DE_PIVOT_ACCEPTABLE ) Spx->SeuilDePivotDual = VALEUR_DE_PIVOT_ACCEPTABLE; + } + + /* Si la factorisation s'est mal passee */ + if ( Spx->FactoriserLaBase == OUI_SPX ) ArretDemande = OUI_SPX; + +} + +/* Maintenant on peut recuperer la valeur du critere correspondant a la solution courante ainsi + que la base puisqu'elle est duale realisable et qu'elle pourra servir lors d'une optimisation + complete */ + +SPX_FixerXEnFonctionDeSaPosition( Spx ); + +SPX_RecupererLaSolution( + Spx, + NbVar_E, + X, + TypeVar_E, + NbContr_E, + PositionDeLaVariable, + NbVarDeBaseComplementaires, + ComplementDeLaBase +/* + InDualFramework, + DualPoids +*/ + ); + +if ( NombreDeContraintesCoupes > 0 ) { + SPX_RecupererLaSolutionSurLesCoupes( Spx , NombreDeContraintesCoupes , NbTermCoupes , PositionDeLaVariableDEcartCoupes ); +} + +for ( Nb = 0 ; Nb < NombreDeVariablesABrancher ; Nb++ ) { + Var = NumerosDesVariablesABrancher[Nb]; + VarSpx = Spx->CorrespondanceVarEntreeVarSimplexe[Var]; + Spx->Xmax[VarSpx] = XmaxSV[Nb]; +} + +#if VERBOSE_SPX + printf(" Iteration de sortie du strong branching %d\n",Spx->Iteration); fflush(stdout); +#endif + +/* On remet les donnees internes du simplexe dans l'etat initial */ + +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + Spx->X [Var] = Spx->XSV[Var]; + Spx->PositionDeLaVariable [Var] = Spx->PositionDeLaVariableSV[Var]; + Spx->CBarre [Var] = Spx->CBarreSV[Var]; + Spx->InDualFramework [Var] = Spx->InDualFrameworkSV[Var]; + Spx->ContrainteDeLaVariableEnBase[Var] = Spx->ContrainteDeLaVariableEnBaseSV[Var]; +} + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + Spx->BBarre [Cnt] = Spx->BBarreSV[Cnt]; + Spx->DualPoids [Cnt] = Spx->DualPoidsSV[Cnt]; + Spx->VariableEnBaseDeLaContrainte[Cnt] = Spx->VariableEnBaseDeLaContrainteSV[Cnt]; +} + +Spx->LastEta = -1; +Spx->NombreDeChangementsDeBase = 0; +Spx->Iteration = 0; + +return; + +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_dual_supprimer_les_bornes_auxilaires.c b/src/ext/Sirius_Solver/simplexe/spx_dual_supprimer_les_bornes_auxilaires.c new file mode 100644 index 0000000000..4101124d41 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_dual_supprimer_les_bornes_auxilaires.c @@ -0,0 +1,81 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On essai de remettre les bornes initiales tout en restant + dual realisable + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# ifdef UTILISER_BORNES_AUXILIAIRES +/*----------------------------------------------------------------------------*/ + +void SPX_DualSupprimerLesBornesAuxiliaires( PROBLEME_SPX * Spx ) +{ +int Var; int i; int * NumerosDesVariablesHorsBase; double * CBarre; +char * StatutBorneSupCourante; char * PositionDeLaVariable; +int NombreDeBornesAuxilairesAuDepart; double * SeuilDAmissibiliteDuale; + +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +CBarre = Spx->CBarre; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +PositionDeLaVariable = Spx->PositionDeLaVariable; + +NombreDeBornesAuxilairesAuDepart = Spx->NombreDeBornesAuxiliairesUtilisees; + +SeuilDAmissibiliteDuale = Spx->SeuilDAmissibiliteDuale2; + +/* Boucle sur les variables hors base */ +for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + if ( StatutBorneSupCourante[Var] == BORNE_NATIVE ) continue; + + if ( StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_BORNEE_INFERIEUREMENT ) { + /* Si la variable est devenue duale admissible avec sa borne native on peut la passer sur borne inf + et remettre son type de borne initial */ + if ( CBarre[Var] > -SeuilDAmissibiliteDuale[Var] ) { + SPX_SupprimerUneBorneAuxiliaire( Spx, Var ); + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + } + } + else if ( StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) { + if ( fabs( CBarre[Var] ) < SeuilDAmissibiliteDuale[Var] ) { + SPX_SupprimerUneBorneAuxiliaire( Spx, Var ); + PositionDeLaVariable[Var] = HORS_BASE_A_ZERO; + } + } +} + +if ( Spx->NombreDeBornesAuxiliairesUtilisees != NombreDeBornesAuxilairesAuDepart ) { + Spx->CalculerBBarre = OUI_SPX; + # if VERBOSE_SPX + printf("Iteration %d Nombre de bornes auxiliaires utilisees %d\n",Spx->Iteration,Spx->NombreDeBornesAuxiliairesUtilisees); + # endif +} + +return; +} + +# endif + diff --git a/src/ext/Sirius_Solver/simplexe/spx_ecrire_probleme_mps.c b/src/ext/Sirius_Solver/simplexe/spx_ecrire_probleme_mps.c new file mode 100644 index 0000000000..86492f0352 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_ecrire_probleme_mps.c @@ -0,0 +1,274 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Ecrire du probleme au format MPS utilise QUE POUR FAIRE + DE LA MISE AU POINT + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "bb_define.h" +# include "bb_fonctions.h" + +# include "pne_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_EcrireProblemeAuFormatMPS( PROBLEME_SIMPLEXE Probleme ) +{ +SPX_EcrireJeuDeDonneesLineaireAuFormatMPS(Probleme.NombreDeVariables,Probleme.TypeDeVariable,Probleme.Xmax,Probleme.Xmin,Probleme.CoutLineaire, + Probleme.NombreDeContraintes,Probleme.SecondMembre,Probleme.Sens,Probleme.IndicesDebutDeLigne, + Probleme.NombreDeTermesDesLignes,Probleme.CoefficientsDeLaMatriceDesContraintes,Probleme.IndicesColonnes); +} + + +void SPX_EcrireProblemeSpxAuFormatMPS( PROBLEME_SPX * Spx ) +{ + int i; + int * TypeDeBorne; + char * Sens; + Sens = (char*) malloc( Spx->NombreDeContraintes * sizeof( char ) ); + for (i=0; iNombreDeContraintes; i++) Sens[i] = '='; // uniquement des contraintes d'égalité + TypeDeBorne = (int*) malloc ( Spx->NombreDeVariables * sizeof (int) ); + for (i=0; iNombreDeVariables; i++) TypeDeBorne[i] = Spx->TypeDeVariable[i]; // conversion des types de borne + + SPX_EcrireJeuDeDonneesLineaireAuFormatMPS(Spx->NombreDeVariables,TypeDeBorne,Spx->Xmax,Spx->Xmin,Spx->C, + Spx->NombreDeContraintes,Spx->B,Sens,Spx->Mdeb,Spx->NbTerm,Spx->A,Spx->Indcol); + + free ( TypeDeBorne ); + free ( Sens ); +} + + +void SPX_EcrireJeuDeDonneesLineaireAuFormatMPS(int NombreDeVariables, int * TypeDeBorneDeLaVariable, + double * Xmax, double * Xmin, double * CoutLineaire, int NombreDeContraintes, + double * SecondMembre, char * Sens, int * IndicesDebutDeLigne, + int * NombreDeTermesDesLignes, double * CoefficientsDeLaMatriceDesContraintes, + int * IndicesColonnes) +{ + +FILE * Flot; +int Cnt; int Var; int il; int ilk; int ilMax; char * Nombre; +int * Cder; int * Cdeb; int * NumeroDeContrainte; int * Csui; + +/* Chainage de la transposee */ +for ( ilMax = -1 , Cnt = 0 ; Cnt < NombreDeContraintes; Cnt++ ) { + if ( ( IndicesDebutDeLigne[Cnt] + NombreDeTermesDesLignes[Cnt] - 1 ) > ilMax ) { + ilMax = IndicesDebutDeLigne[Cnt] + NombreDeTermesDesLignes[Cnt] - 1; + } +} +ilMax+= NombreDeContraintes; /* Marge */ + +Cder = (int *) malloc( NombreDeVariables * sizeof( int ) ); +Cdeb = (int *) malloc( NombreDeVariables * sizeof( int ) ); +NumeroDeContrainte = (int *) malloc( ilMax * sizeof( int ) ); +Csui = (int *) malloc( ilMax * sizeof( int ) ); +Nombre = (char *) malloc( 1024 ); +if ( Cder == NULL || Cdeb == NULL || NumeroDeContrainte == NULL || Csui == NULL || Nombre == NULL ) { + printf("Memoire insuffisante pour ecrire le probleme\n"); + exit(0); +} + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) Cdeb[Var] = -1; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = IndicesDebutDeLigne[Cnt]; + ilMax = il + NombreDeTermesDesLignes[Cnt]; + while ( il < ilMax ) { + Var = IndicesColonnes[il]; + if ( Cdeb[Var] < 0 ) { + Cdeb [Var] = il; + NumeroDeContrainte[il] = Cnt; + Csui [il] = -1; + Cder [Var] = il; + } + else { + ilk = Cder[Var]; + Csui [ilk] = il; + NumeroDeContrainte[il] = Cnt; + Csui [il] = -1; + Cder [Var] = il; + } + il++; + } +} +free( Cder ); +/* Fin chainage de la transposee */ + +/* Fichier qui contiendra le jeu de donnees */ +printf("***************************************************************************\n"); +printf("*** Vous avez demande la creation d'un fichier contenant la description ***\n"); +printf("*** du probleme en cours de resolution. Le fichier de donnees se trouve ***\n"); +printf("*** dans le repertoire d'execution. Il s'appelle: ***\n"); +printf("*** ***\n"); +printf("*** Donnees_Probleme_Solveur.mps ***\n"); +printf("*** ***\n"); +printf("*** Si un fichier de ce nom existait deja, il sera ecrase par avec les ***\n"); +printf("*** nouvelles donnees. ***\n"); +printf("***************************************************************************\n"); + +Flot = fopen( "Donnees_Probleme_Solveur.mps", "w" ); +if( Flot == NULL ) { + printf("Erreur ouverture du fichier pour l'ecriture du jeu de donnees \n"); + return; +} + +/* Ecrire du titre */ +fprintf(Flot,"* Number of variables: %d\n",NombreDeVariables); +fprintf(Flot,"* Number of constraints: %d\n",NombreDeContraintes); + +/* + Les champs du format MPS +Champ1 : 2- 3 +Champ2 : 5-12 +Champ3 : 15-22 +Champ4 : 25-36 +Champ5 : 40-47 +Champ6 : 50-61 +*/ + +/* NAME */ +fprintf(Flot,"NAME Pb Solve\n"); + +/* ROWS */ +fprintf(Flot,"ROWS\n"); +/* +In this section all the row labels are defined, as well as the row type. The row +type is entered in field 1 (in column 2 or 3) and the row label is entered in +field 2 (columns 5-12). Row type: +E : egalité +L : inferieur ou egal +G : superieur ou egal +N : objectif +N : free ?? +*/ +/* Objectif */ +fprintf(Flot," N OBJECTIF\n"); +/* Ecriture de toutes les contraintes */ +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( Sens[Cnt] == '=' ) { + fprintf(Flot," E R%07d\n",Cnt); + } + else if ( Sens[Cnt] == '<' ) { + fprintf(Flot," L R%07d\n",Cnt); + } + else if ( Sens[Cnt] == '>' ) { + fprintf(Flot," G R%07d\n",Cnt); + } + else { + fprintf(Flot,"SPX_EcrireJeuDeDonneesLineaireAuFormatMPS : le sens de la contrainte %c ne fait pas partie des sens reconnus\n", + Sens[Cnt]); + exit(0); + } +} + +/* COLUMNS */ +fprintf(Flot,"COLUMNS\n"); +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( CoutLineaire[Var] != 0.0 ) { + sprintf(Nombre,"%-.10lf",CoutLineaire[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas faire de troncature car il y a un risque de changer un tout petit peu le pb */ + fprintf(Flot," C%07d OBJECTIF %s\n",Var,Nombre); + } + il = Cdeb[Var]; + while ( il >= 0 ) { + sprintf(Nombre,"%-.10lf",CoefficientsDeLaMatriceDesContraintes[il]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas faire de troncature car il y a un risque de changer un tout petit peu le pb */ + fprintf(Flot," C%07d R%07d %s\n",Var,NumeroDeContrainte[il],Nombre); + il = Csui[il]; + } +} + +/* RHS */ +fprintf(Flot,"RHS\n"); +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + if ( SecondMembre[Cnt] != 0.0 ) { + sprintf(Nombre,"%-.9lf",SecondMembre[Cnt]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas faire de troncature car il y a un risque de changer un tout petit peu le pb */ + fprintf(Flot," RHSVAL R%07d %s\n",Cnt,Nombre); + } +} + +/* BOUNDS */ +fprintf(Flot,"BOUNDS\n"); +/* + Field 1 (columns 2-3) specifies the type of bound: + LO lower bound + UP upper bound + LI lower bound integer variable + UI upper bound integer variable + BV binary variable + FX fixed variable + FR free + MI lower bound - infini + PL upper bound + infini +*/ +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + /* Par defaut la variable est PL i.e;. comprise entre 0 et + l'infini */ + if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_FIXE ) { + sprintf(Nombre,"%-.9lf",Xmin[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas ajouter de troncature */ + fprintf(Flot," FX BNDVALUE C%07d %s\n",Var,Nombre); + } + else if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( Xmin[Var] != 0.0 ) { + sprintf(Nombre,"%-.9lf",Xmin[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas faire de troncature car il y a un risque de changer un tout petit peu le pb */ + fprintf(Flot," LO BNDVALUE C%07d %s\n",Var,Nombre); + } + sprintf(Nombre,"%-.9lf",Xmax[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas faire de troncature car il y a un risque de changer un tout petit peu le pb */ + fprintf(Flot," UP BNDVALUE C%07d %s\n",Var,Nombre); + } + else if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( Xmin[Var] != 0.0 ) { + sprintf(Nombre,"%-.9lf",Xmin[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas faire de troncature car il y a un risque de changer un tout petit peu le pb */ + fprintf(Flot," LO BNDVALUE C%07d %s\n",Var,Nombre); + } + } + else if ( TypeDeBorneDeLaVariable[Var] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + fprintf(Flot," MI BNDVALUE C%07d\n",Var); + if ( Xmax[Var] != 0.0 ) { + sprintf(Nombre,"%-.9lf",Xmax[Var]); + /*Nombre[12] = '\0';*/ /* <- On prefere ne pas faire de troncature car il y a un risque de changer un tout petit peu le pb */ + fprintf(Flot," UP BNDVALUE C%07d %s\n",Var,Nombre); + } + } + else if ( (int)TypeDeBorneDeLaVariable[Var] == VARIABLE_NON_BORNEE ) { + fprintf(Flot," FR BNDVALUE C%07d\n",Var); + } +} + +/* ENDDATA */ +fprintf(Flot,"ENDATA\n"); + +free ( Cdeb ); +free ( NumeroDeContrainte ); +free ( Csui ); +free ( Nombre ); + +fclose( Flot ); + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_factoriser_la_base.c b/src/ext/Sirius_Solver/simplexe/spx_factoriser_la_base.c new file mode 100644 index 0000000000..89e1c0c9d7 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_factoriser_la_base.c @@ -0,0 +1,489 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Factorisation LU de la base + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_constantes_externes.h" +# include "lu_definition_arguments.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +# define COEFF_MULTIPLICATEUR_DU_SEUIL 2.0 /*4.0*/ +# define SEUIL_MARKOWITZ_MAX 0.2 /*0.5*/ +# define NOMBRE_DE_FOIS_MODIF_SEUIL 2 /*3*/ +# define SEUIL_INVERSE_ASSEZ_PLEIN 0.25 + +# define DEBUG OUI_SPX + +# define TRACES 0 + +# define VERBOSE_SPX 0 + +# define COMPILE_DM 0 +# if COMPILE_DM == 1 +# include "cs.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_TestDM( PROBLEME_SPX * Spx, MATRICE_A_FACTORISER * Matrice ) +{ +int i; int ilAi; int il; int ilMax; csd * Csd; csi seed; +int Cb; int C1; int C2; int C3; +int R1; int R2; int R3; int Rb; +cs * A; + +A = (cs *) malloc( sizeof( cs ) ); +A->nzmax = 0; +for ( i = 0 ; i < Matrice->NombreDeColonnes ; i++ ) A->nzmax += Matrice->NbTermesDesColonnes[i]; +A->n = Matrice->NombreDeColonnes; +A->m = Matrice->NombreDeColonnes; +A->p = (csi *) malloc( ( A->n + 1 ) * sizeof( csi ) ); +A->i = (csi *) malloc( A->nzmax * sizeof( csi ) ); +A->x = (double *) malloc( A->nzmax * sizeof( double ) ); +A->nz = -1; /* compressed-col */ + +ilAi = 0; +for ( i = 0 ; i < Matrice->NombreDeColonnes ; i++ ) { + il = Matrice->IndexDebutDesColonnes[i]; + ilMax = il + Matrice->NbTermesDesColonnes[i]; + A->p[i] = ilAi; + while ( il < ilMax ) { + A->i[ilAi] = Matrice->IndicesDeLigne[il]; + A->x[ilAi] = Matrice->ValeurDesTermesDeLaMatrice[il]; + ilAi++; + il++; + } +} +A->p[A->n] = ilAi; + +printf("cs_dmperm \n"); + +seed = 0; +Csd = cs_dmperm( A, seed ); + +printf("Nombre de blocs: %d rang %d iteration %d\n",(int) Csd->nb,Matrice->NombreDeColonnes,Spx->Iteration); +for ( i = 0 ; i < (int) Csd->nb ; i++ ) { + if ( Csd->s[i+1] - Csd->s[i] == 1 ) continue; + printf("bloc %d de %d a %d taille %d\n",i,(int) Csd->s[i],(int) Csd->s[i+1],(int) Csd->s[i+1] - (int) Csd->s[i]); + +} + +/* +Cb = Csd->cc[1]; +printf("Nombre d'elements de CBarre : %d\n",Cb); +C1 = Csd->cc[2]-Csd->cc[1]; +printf("Nombre d'elements de C1 : %d\n",C1); +C2 = Csd->cc[3]-Csd->cc[2]; +printf("Nombre d'elements de C2 : %d\n",C2); +C3 = Csd->cc[4]-Csd->cc[3]; +printf("Nombre d'elements de C3 : %d\n",C3); + +printf("\n"); +R1 = Csd->rr[1]; +printf("Nombre d'elements de R1 : %d\n",R1); +R2 = Csd->rr[2]-Csd->rr[1]; +printf("Nombre d'elements de R2 : %d\n",R2); +R3 = Csd->rr[3]-Csd->rr[2]; +printf("Nombre d'elements de R3 : %d\n",R3); +Rb = Csd->rr[4]-Csd->rr[3]; +printf("Nombre d'elements de RBarre : %d\n",Rb); +*/ +return; +} +# endif + +/*----------------------------------------------------------------------------*/ + +void SPX_FactoriserLaBase( PROBLEME_SPX * Spx ) +{ +int Cnt; int Var ; int CodeRetour; char OnRetesteSiPivotNul; int FaireScalingLU; +char SeuilPivotMarkowitzParDefaut ; double Coeff; double NbTrm; int NbTrmCol; +int * CdebBase; int * NbTermesDesColonnesDeLaBase; int * Cdeb; int * CNbTerm; +int * VariableEnBaseDeLaContrainteSV; int * VariableEnBaseDeLaContrainte; +char * PositionDeLaVariableSV; char * PositionDeLaVariable; double SeuilInverseDense; +int * ContrainteDeLaVariableEnBaseSV; int * ContrainteDeLaVariableEnBase; +char RestaurerAdmissibiliteDuale; int Iteration; int NombreMaxDIterations; double N2; +int * IndicesDeLigneDesTermesDeLaBase; double * ValeurDesTermesDesColonnesDeLaBase; +int r; int * NumeroDeContrainte; double * ACol; int RangDeLaMatriceFactorisee; +int * ColonneDeLaBaseFactorisee; MATRICE_A_FACTORISER Matrice; int * CdebProblemeReduit; +int * CNbTermProblemeReduit; + +/* +printf("------- Factorisation de la base iteration %d ------ CoefficientPourLaValeurDePerturbationDeCoutAPosteriori %e \n", + Spx->Iteration,Spx->CoefficientPourLaValeurDePerturbationDeCoutAPosteriori); +*/ + +OnRetesteSiPivotNul = OUI_SPX; +SeuilPivotMarkowitzParDefaut = OUI_LU; +RestaurerAdmissibiliteDuale = NON_SPX; + +Debut: + +CdebBase = Spx->CdebBase; +NbTermesDesColonnesDeLaBase = Spx->NbTermesDesColonnesDeLaBase; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; +ACol = Spx->ACol; + +if ( Spx->ForcerUtilisationDeLaBaseComplete == 0 ) { + SPX_OrdonnerLesContraintesPourLaBase( Spx ); + if ( Spx->UtiliserLaBaseReduite == NON_SPX ) { + Spx->RangDeLaMatriceFactorisee = Spx->NombreDeContraintes; + Spx->ForcerUtilisationDeLaBaseComplete = 1; + SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); + } +} +else { + Spx->RangDeLaMatriceFactorisee = Spx->NombreDeContraintes; + Spx->UtiliserLaBaseReduite = NON_SPX; + Spx->NombreDeFactorisationsDeBaseReduite = 0; + # if TRACES == 1 + printf("\nRangDeLaMatriceFactorisee %d (base complete) NombreDeFactorisationsDeBaseReduite %d ModifCoutsAutorisee %d\n", + Spx->RangDeLaMatriceFactorisee,Spx->NombreDeFactorisationsDeBaseReduite,Spx->ModifCoutsAutorisee); + # endif + /* + if ( Spx->NombreDeReactivationsDeLaBaseReduite < NB_MAX_DE_REACTIVATIONS_DE_LA_BASE_REDUITE ) { + Spx->ForcerUtilisationDeLaBaseComplete--; + if ( Spx->ForcerUtilisationDeLaBaseComplete <= 0 ) { + Spx->ForcerUtilisationDeLaBaseComplete = 0; + Spx->NombreDeReactivationsDeLaBaseReduite++; + } + } + */ +} + +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + + RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; + + N2 = (double) RangDeLaMatriceFactorisee * (double) RangDeLaMatriceFactorisee; + SeuilInverseDense = SEUIL_INVERSE_ASSEZ_PLEIN * N2; + + N2 = (double) RangDeLaMatriceFactorisee * (double) RangDeLaMatriceFactorisee; + SeuilInverseDense = SEUIL_INVERSE_ASSEZ_PLEIN * N2; + + ColonneDeLaBaseFactorisee = Spx->ColonneDeLaBaseFactorisee; + + CdebProblemeReduit = Spx->CdebProblemeReduit; + CNbTermProblemeReduit = Spx->CNbTermProblemeReduit; + + ValeurDesTermesDesColonnesDeLaBase = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; + IndicesDeLigneDesTermesDeLaBase = Spx->IndicesDeLigneDesTermesDuProblemeReduit; + + NbTrm = 0.0; + for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + Var = VariableEnBaseDeLaContrainte[ColonneDeLaBaseFactorisee[r]]; + CdebBase[r] = CdebProblemeReduit[Var]; + NbTrmCol = CNbTermProblemeReduit[Var]; + NbTermesDesColonnesDeLaBase[r] = NbTrmCol; + NbTrm += (double) NbTrmCol; + } + +} +else { + + N2 = (double) Spx->NombreDeContraintes * (double) Spx->NombreDeContraintes; + SeuilInverseDense = SEUIL_INVERSE_ASSEZ_PLEIN * N2; + + /* On a deja sous la main le chainage de la transposee mais pour toutes les colonnes + de la transposee. Il s'agit donc de preparer une nouvelle table des indices debut + pour les seules colonnes de la base */ + ValeurDesTermesDesColonnesDeLaBase = Spx->ACol; + IndicesDeLigneDesTermesDeLaBase = Spx->NumeroDeContrainte; + + NbTrm = 0.0; + for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + Var = VariableEnBaseDeLaContrainte[Cnt]; + CdebBase[Cnt] = Cdeb[Var]; + NbTrmCol = CNbTerm[Var]; + NbTermesDesColonnesDeLaBase[Cnt] = NbTrmCol; + NbTrm += (double) NbTrmCol; + } +} + +if ( NbTrm > SeuilInverseDense ) Spx->InverseProbablementDense = OUI_SPX; +else Spx->InverseProbablementDense = NON_SPX; + +if ( NbTrm < TAUX_DE_REMPLISSAGE_POUR_BASE_HYPER_CREUSE * N2 ) Spx->TypeDeCreuxDeLaBase = BASE_HYPER_CREUSE; +else if ( NbTrm == N2 ) Spx->TypeDeCreuxDeLaBase = BASE_PLEINE; +else Spx->TypeDeCreuxDeLaBase = BASE_CREUSE; + +if ( Spx->TypeDeCreuxDeLaBase == BASE_HYPER_CREUSE ) SPX_InitialiserLesIndicateursHyperCreux( Spx ); + +if ( Spx->MatriceFactorisee != NULL ) { + LU_LibererMemoireLU( (MATRICE *) Spx->MatriceFactorisee ); + Spx->MatriceFactorisee = NULL; +} + +/* Attention. On ne peut pas faire de LU_Update si on fait du scaling car les coefficients + de scaling ne sont plus valables */ + +FaireScalingLU = NON_LU; +if ( Spx->FaireScalingLU > 0 && Spx->UtiliserLaLuUpdate == NON_SPX ) { + FaireScalingLU = OUI_LU; +} + +/* Si on a deja un seuil de pivot (cas de la recuperation de la derniere base inversible) on + le prend */ +if ( SeuilPivotMarkowitzParDefaut == OUI_LU ) { + if ( Spx->FlagStabiliteDeLaFactorisation == 1 ) { + if ( Spx->NombreDeChangementsDeBase == 0 ) { + /* Si le nombre changements de base etait nul, on augmente le seuil dans une limite */ + SeuilPivotMarkowitzParDefaut = NON_LU; + Spx->ValeurDuPivotMarkowitz = COEFF_MULTIPLICATEUR_DU_SEUIL * PREMIER_SEUIL_DE_PIVOTAGE; + if ( Spx->ValeurDuPivotMarkowitz > SEUIL_MARKOWITZ_MAX ) Spx->ValeurDuPivotMarkowitz = SEUIL_MARKOWITZ_MAX; + Spx->ProblemeDeStabiliteDeLaFactorisation = OUI_SPX; + Spx->FlagStabiliteDeLaFactorisation = 0; + } + else { + Spx->FlagStabiliteDeLaFactorisation = 0; + } + } + else if ( Spx->ProblemeDeStabiliteDeLaFactorisation == OUI_SPX ) { + SeuilPivotMarkowitzParDefaut = NON_LU; + Coeff = pow( (1./COEFF_MULTIPLICATEUR_DU_SEUIL) , (1./(double) NOMBRE_DE_FOIS_MODIF_SEUIL) ); + Spx->ValeurDuPivotMarkowitz = Coeff * Spx->ValeurDuPivotMarkowitz; + if ( Spx->ValeurDuPivotMarkowitz < PREMIER_SEUIL_DE_PIVOTAGE) { + SeuilPivotMarkowitzParDefaut = OUI_LU; + Spx->ValeurDuPivotMarkowitz = PREMIER_SEUIL_DE_PIVOTAGE; + Spx->ProblemeDeStabiliteDeLaFactorisation = NON_SPX; + } + } + /* Pas besoin mais juste pour la coherence */ + if ( SeuilPivotMarkowitzParDefaut == OUI_LU ) Spx->ValeurDuPivotMarkowitz = PREMIER_SEUIL_DE_PIVOTAGE; +} + +Matrice.ContexteDeLaFactorisation = LU_SIMPLEXE; +Matrice.UtiliserLesSuperLignes = NON_LU; +Matrice.ValeurDesTermesDeLaMatrice = ValeurDesTermesDesColonnesDeLaBase; +Matrice.IndicesDeLigne = IndicesDeLigneDesTermesDeLaBase; +Matrice.IndexDebutDesColonnes = CdebBase; +Matrice.NbTermesDesColonnes = NbTermesDesColonnesDeLaBase; +Matrice.NombreDeColonnes = Spx->RangDeLaMatriceFactorisee; +Matrice.FaireScalingDeLaMatrice = NON_LU /*FaireScalingLU*/; +Matrice.UtiliserLesValeursDePivotNulParDefaut = OUI_LU; +Matrice.SeuilPivotMarkowitzParDefaut = SeuilPivotMarkowitzParDefaut; +Matrice.ValeurDuPivotMarkowitz = Spx->ValeurDuPivotMarkowitz; +Matrice.FaireDuPivotageDiagonal = NON_LU; +Matrice.LaMatriceEstSymetrique = NON_LU; +Matrice.LaMatriceEstSymetriqueEnStructure = NON_LU; + + +# if COMPILE_DM == 1 +SPX_TestDM( Spx, &Matrice ); +# endif + +Spx->MatriceFactorisee = LU_Factorisation( &Matrice ); + +if ( Spx->MatriceFactorisee == NULL ) { + Spx->AnomalieDetectee = SPX_ERREUR_INTERNE; + longjmp( Spx->EnvSpx, Spx->AnomalieDetectee ); +} + +CodeRetour = Matrice.ProblemeDeFactorisation; + +Spx->FaireScalingLU--; +if ( Spx->FaireScalingLU < 0 ) Spx->FaireScalingLU = 0; + +if ( Matrice.ProblemeDeFactorisation != 0 ) { + if ( CodeRetour != MATRICE_SINGULIERE ) { + #if VERBOSE_SPX + printf(" Erreur dans la factorisation LU du simplexe, numero d'erreur %d \n",CodeRetour); + #endif + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx, Spx->AnomalieDetectee ); + } + /* Cas d'une matrice singuliere */ + if ( Spx->BaseInversibleDisponible == OUI_SPX && OnRetesteSiPivotNul == OUI_SPX ) { + #if VERBOSE_SPX + printf("Base non inversible, on repart de la derniere base inversible disponible Iteration %d\n",Spx->Iteration); + #endif + Spx->ProblemeDeStabiliteDeLaFactorisation = NON_SPX; + + SeuilPivotMarkowitzParDefaut = NON_LU; + Spx->ValeurDuPivotMarkowitz = Spx->ValeurDuPivotMarkowitzSV; + /* Recuperation de la base inversible */ + for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + Spx->VariableEnBaseDeLaContrainte[Cnt] = Spx->VariableEnBaseDeLaContrainteSV[Cnt]; + } + + RestaurerAdmissibiliteDuale = NON_SPX; + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + Spx->ContrainteDeLaVariableEnBase[Var] = Spx->ContrainteDeLaVariableEnBaseSV[Var]; + Spx->PositionDeLaVariable [Var] = Spx->PositionDeLaVariableSV[Var]; + if ( Spx->PhaseEnCours == PHASE_1 ) continue; + if ( Spx->StrongBranchingEnCours == OUI_SPX ) { + printf("Attention probleme dans SPX_Factorisation: on essaie de factoriser alors qu'on est en strong branching\n"); + continue; + } + if ( RestaurerAdmissibiliteDuale == OUI_SPX ) continue; + /* Pour les types de bornes modifiables, il faut tester la position des variables pour voir + si elle est en accord ou non. En effet, il a pu y avoir des modifications de types de bornes. Si elle n'est + pas en accord on fait une phase 1 */ + if ( Spx->TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) RestaurerAdmissibiliteDuale = OUI_SPX; + } + else if ( Spx->TypeDeVariable[Var] == NON_BORNEE ) { + if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF || + Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) RestaurerAdmissibiliteDuale = OUI_SPX; + } + } + + /* Il faut restaurer l'admissibilite duale si l'on utilise les bornes auxiliaires */ + # ifdef UTILISER_BORNES_AUXILIAIRES + RestaurerAdmissibiliteDuale = OUI_SPX; + /* On enleve toutes les bornes auxiliaires car elles seront retablies si necessaire */ + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( Spx->StatutBorneSupCourante[Var] != BORNE_NATIVE ) SPX_SupprimerUneBorneAuxiliaire( Spx, Var ); + } + if ( Spx->NombreDeBornesAuxiliairesUtilisees != 0 ) { + printf("Attention probleme dans SPX_Factorisation: le nombre de bornes auxiliaires n'est pas nul (valeur = %d)\n", + Spx->NombreDeBornesAuxiliairesUtilisees); + } + # endif + + /* Precaution: RAZ du Steepest Edge */ + SPX_InitDualPoids( Spx ); + + /* Infos concernant les variables hors base */ + SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); + + /* Initialisation des parametres de choix au hasard des variables sortantes */ + + Spx->NombreDeChoixFaitsAuHasard = 0; + Spx->FaireChangementDeBase = NON_SPX; + Spx->ChoixDeVariableSortanteAuHasard = OUI_SPX; + + Spx->NombreMaxDeChoixAuHasard = (int) (0.5 * Spx->CycleDeRefactorisation); + if ( Spx->NombreMaxDeChoixAuHasard < 10 ) Spx->NombreMaxDeChoixAuHasard = 10; + + /* On augmente le seuil dual de pivotage */ + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + + #if VERBOSE_SPX + printf("Iteration %d nombre de choix de pivot au hasard a faire parmi les choix acceptables: %d\n", + Spx->Iteration,Spx->NombreMaxDeChoixAuHasard); + #endif + + /* On refait la factorisation */ + OnRetesteSiPivotNul = NON_SPX; /* Mais si on retombe sur un pivot nul alors c'est grave */ + + goto Debut; + } + else { + /* Pas de base inversible disponible */ + Spx->AnomalieDetectee = OUI_SPX; + if ( CodeRetour == MATRICE_SINGULIERE ) { + #if VERBOSE_SPX + printf(" Erreur dans la factorisation LU du simplexe, base non inversible et aucune base inversible disponible\n"); + #endif + Spx->AnomalieDetectee = SPX_MATRICE_DE_BASE_SINGULIERE; + } + longjmp( Spx->EnvSpx, Spx->AnomalieDetectee ); + } +} + +/* Stockage de la derniere base inversible */ + +Spx->BaseInversibleDisponible = OUI_SPX; + +Spx->ValeurDuPivotMarkowitzSV = Spx->ValeurDuPivotMarkowitz; + +VariableEnBaseDeLaContrainteSV = Spx->VariableEnBaseDeLaContrainteSV; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + VariableEnBaseDeLaContrainteSV[Cnt] = VariableEnBaseDeLaContrainte[Cnt]; +} + +PositionDeLaVariableSV = Spx->PositionDeLaVariableSV; +PositionDeLaVariable = Spx->PositionDeLaVariable; +ContrainteDeLaVariableEnBaseSV = Spx->ContrainteDeLaVariableEnBaseSV; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; + +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + PositionDeLaVariableSV [Var] = PositionDeLaVariable[Var]; + ContrainteDeLaVariableEnBaseSV[Var] = ContrainteDeLaVariableEnBase[Var]; +} + +Spx->LastEta = -1; +Spx->NombreDeChangementsDeBase = 0; + +Spx->FactoriserLaBase = NON_SPX; /* Repositionnement */ + +Spx->CalculerBBarre = OUI_SPX; +Spx->CalculerCBarre = OUI_SPX; + +if ( RestaurerAdmissibiliteDuale == OUI_SPX ) { + Iteration = Spx->Iteration; + NombreMaxDIterations = Spx->NombreMaxDIterations; + + #if VERBOSE_SPX + printf("Probleme de factorisation, restauration de l'admissibilite duale necessaire a l'iteration %d\n",Spx->Iteration); + #endif + + /* Restauration des couts: normalement ca a deja ete fait sauf s'il n'y a pas eu de degenerescence duale */ + memcpy( (char *) Spx->C, (char *) Spx->Csv, Spx->NombreDeVariables * sizeof( double ) ); + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) Spx->CorrectionDuale[Var] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + + SPX_DualPhase1Simplexe( Spx ); + + Spx->PhaseEnCours = PHASE_2; + + Spx->Iteration = Iteration; + Spx->NombreMaxDIterations = NombreMaxDIterations; + Spx->CalculerBBarre = OUI_SPX; + Spx->CalculerCBarre = OUI_SPX; + Spx->FaireChangementDeBase = NON_SPX; + + if ( Spx->LaBaseEstDualeAdmissible == NON_SPX ) { + /* Echec */ + Spx->YaUneSolution = NON_SPX; + Spx->Iteration = 10 * Spx->NombreMaxDIterations; + } + else { + /* On augmente le seuil dual de pivotage car on est tombe sur un pivot nul auparavant */ + /* Et on fait quelques tirages au hasard pour eviter de retomber sur le probleme */ + Spx->NombreDeChoixFaitsAuHasard = 0; + Spx->FaireChangementDeBase = NON_SPX; + Spx->ChoixDeVariableSortanteAuHasard = OUI_SPX; + Spx->NombreMaxDeChoixAuHasard = (int) (0.5 * Spx->CycleDeRefactorisation); + if ( Spx->NombreMaxDeChoixAuHasard < 10 ) Spx->NombreMaxDeChoixAuHasard = 10; + + /* On augmente le seuil dual de pivotage */ + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + } + +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_faire_changement_base.c b/src/ext/Sirius_Solver/simplexe/spx_faire_changement_base.c new file mode 100644 index 0000000000..d1a8efb717 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_faire_changement_base.c @@ -0,0 +1,154 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Effectue le changement de base apres avoir choisi les + variables a echanger. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_FaireLeChangementDeBase( PROBLEME_SPX * Spx ) +{ +int Cnt; int SuccesUpdate; int VariableEntrante; int VariableSortante; +int i; int * BoundFlip; char * PositionDeLaVariable; int Var; +char * StatutBorneSupCourante; char * TypeDeVariable; double * Xmax; + +/* On effectue les bound flip eventuels */ +BoundFlip = Spx->BoundFlip; +PositionDeLaVariable = Spx->PositionDeLaVariable; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +TypeDeVariable = Spx->TypeDeVariable; +Xmax = Spx->Xmax; + +for ( i = 0 ; i < Spx->NbBoundFlip ; i++ ) { + if ( BoundFlip[i] > 0 ) { + /* + Var = BoundFlip[i]-1; + printf("Bound flip vers BORNE_SUP variable %d\n", Var); + */ + PositionDeLaVariable[BoundFlip[i]-1] = HORS_BASE_SUR_BORNE_SUP; + } + else { + Var = -BoundFlip[i]-1; + /* + printf("Bound flip vers BORNE_INF variable %d\n", Var); + */ + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + # ifdef UTILISER_BORNES_AUXILIAIRES + /* Si c'est une variable avec des bornes auxilaires il faut remettre la borne native */ + if ( Spx->NombreDeBornesAuxiliairesUtilisees > 0 ) { + if ( StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_BORNEE_INFERIEUREMENT ) { + SPX_SupprimerUneBorneAuxiliaire( Spx, Var ); + } + } + # endif + } +} + +VariableEntrante = Spx->VariableEntrante; +VariableSortante = Spx->VariableSortante; + +# ifdef UTILISER_BORNES_AUXILIAIRES + /* Si la variable entrante avait sur une borne sup auxiliaire on libere la borne */ + /* A verifier mais il me semble que c'est inutile car c'est fait dans SPX_MajDesVariablesEnBaseAControler + qui est appele avant */ + if ( Spx->NombreDeBornesAuxiliairesUtilisees > 0 ) SPX_SupprimerUneBorneAuxiliaire( Spx, VariableEntrante ); +# endif + +SPX_MajDuTableauDesVariablesHorsBase( Spx ); + +Debut: + +if ( Spx->FactoriserLaBase == OUI_SPX ) { + + Cnt = Spx->ContrainteDeLaVariableEnBase[VariableSortante]; + Spx->ContrainteDeLaVariableEnBase[VariableSortante] = -1; + Spx->ContrainteDeLaVariableEnBase[VariableEntrante] = Cnt; + Spx->VariableEnBaseDeLaContrainte[Cnt] = VariableEntrante; + + PositionDeLaVariable[VariableEntrante] = EN_BASE_LIBRE; + + if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + PositionDeLaVariable[VariableSortante] = HORS_BASE_SUR_BORNE_INF; + } + else { + PositionDeLaVariable[VariableSortante] = HORS_BASE_SUR_BORNE_SUP; + } + + /* Refactorisation de la nouvelle base */ + SPX_FactoriserLaBase( Spx ); + +} +else { + SPX_MettreAJourLaBase( Spx , &SuccesUpdate ); + if ( Spx->UtiliserLaLuUpdate == OUI_SPX ) { + /* En cas d'echec de la mise a jour on tente une factorisation complete */ + if ( SuccesUpdate == NON_LU ) { + Spx->FactoriserLaBase = OUI_SPX; + if ( Spx->StrongBranchingEnCours != OUI_SPX ) goto Debut; + return; /* On passe jamais par la */ + } + } + + Cnt = Spx->ContrainteDeLaVariableEnBase[VariableSortante]; + + if ( Spx->UtiliserLaLuUpdate == OUI_SPX ) { + + /* Pour pouvoir faire du raffinement iteratif */ + /* Sinon il faut transmettre la matrice qui correspond a la matrice factorisee */ + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + /* Attention il ne faut pas prendre Cnt mais l'ordre */ + i = Spx->OrdreColonneDeLaBaseFactorisee[Cnt]; + Spx->CdebBase [i] = Spx->CdebProblemeReduit[VariableEntrante]; + Spx->NbTermesDesColonnesDeLaBase[i] = Spx->CNbTermProblemeReduit[VariableEntrante]; + } + else { + Spx->CdebBase [Cnt] = Spx->Cdeb[VariableEntrante]; + Spx->NbTermesDesColonnesDeLaBase[Cnt] = Spx->CNbTerm[VariableEntrante]; + } + + } + + Spx->ContrainteDeLaVariableEnBase[VariableSortante] = -1; + Spx->ContrainteDeLaVariableEnBase[VariableEntrante] = Cnt; + Spx->VariableEnBaseDeLaContrainte[Cnt] = VariableEntrante; + + PositionDeLaVariable[VariableEntrante] = EN_BASE_LIBRE; + + if ( Spx->SortSurXmaxOuSurXmin == SORT_SUR_XMIN ) { + PositionDeLaVariable[VariableSortante] = HORS_BASE_SUR_BORNE_INF; + } + else { + PositionDeLaVariable[VariableSortante] = HORS_BASE_SUR_BORNE_SUP; + } + +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_fixer_x_fonction_de_position.c b/src/ext/Sirius_Solver/simplexe/spx_fixer_x_fonction_de_position.c new file mode 100644 index 0000000000..f684d079b7 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_fixer_x_fonction_de_position.c @@ -0,0 +1,128 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On calcule les valeurs de X en fonction de la position + hors base ou en base. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_FixerXEnFonctionDeSaPosition( PROBLEME_SPX * Spx ) +{ +int Var; char PositionDeLaVariable; double X; double * ArrayX; char * TypeDeVariable; +double SommeDesInfaisabilitesPrimales; double * ArrayXmax; double * BBarre; +char * ArrayPositionDeLaVariable; int * ContrainteDeLaVariableEnBase; +char * StatutBorneSupCourante; int Index; char UtiliserLaBaseReduite; +int * OrdreColonneDeLaBaseFactorisee; int RangDeLaMatriceFactorisee; + +ArrayX = Spx->X; +ArrayXmax = Spx->Xmax; +BBarre = Spx->BBarre; +TypeDeVariable = Spx->TypeDeVariable; +ArrayPositionDeLaVariable = Spx->PositionDeLaVariable; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +SommeDesInfaisabilitesPrimales = 0.; + +UtiliserLaBaseReduite = Spx->UtiliserLaBaseReduite; +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; +OrdreColonneDeLaBaseFactorisee = Spx->OrdreColonneDeLaBaseFactorisee; + +/* Attention l'utilisation de Index est fausse mais comme le cout des variables d'ecart est nul + on calcule un cout correcten mettant 0 pour la valeur de X */ + +if ( Spx->NombreDeBornesAuxiliairesUtilisees == 0 ) { + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + PositionDeLaVariable = ArrayPositionDeLaVariable[Var]; + if ( PositionDeLaVariable == EN_BASE_LIBRE ) { + /* La variable est donc en base */ + + if ( UtiliserLaBaseReduite == OUI_SPX ) { + Index = OrdreColonneDeLaBaseFactorisee[ContrainteDeLaVariableEnBase[Var]]; + if ( Index < RangDeLaMatriceFactorisee ) { + X = BBarre[Index]; + } + else X = 0; + } + else { + X = BBarre[ContrainteDeLaVariableEnBase[Var]]; + } + + ArrayX[Var] = X; + /* Attention ici on utilise le fait que par translation on a toujours Xmin = 0. */ + if ( X < 0. && TypeDeVariable[Var] != NON_BORNEE ) SommeDesInfaisabilitesPrimales += -X; + else { + if ( X > ArrayXmax[Var] ) SommeDesInfaisabilitesPrimales += X - ArrayXmax[Var]; + } + } + else if ( PositionDeLaVariable == HORS_BASE_SUR_BORNE_SUP ) ArrayX[Var] = ArrayXmax[Var]; + else ArrayX[Var] = 0.0; + } +} +else { + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + PositionDeLaVariable = ArrayPositionDeLaVariable[Var]; + if ( PositionDeLaVariable == EN_BASE_LIBRE ) { + /* La variable est donc en base */ + + if ( UtiliserLaBaseReduite == OUI_SPX ) { + Index = OrdreColonneDeLaBaseFactorisee[ContrainteDeLaVariableEnBase[Var]]; + if ( Index < RangDeLaMatriceFactorisee ) { + X = BBarre[Index]; + } + else X = 0; + } + else { + X = BBarre[ContrainteDeLaVariableEnBase[Var]]; + } + + ArrayX[Var] = X; + /* Attention ici on utilise le fait que par translation on a toujours Xmin = 0. */ + if ( X < 0. && TypeDeVariable[Var] != NON_BORNEE ) SommeDesInfaisabilitesPrimales += -X; + else { + if ( X > ArrayXmax[Var] ) SommeDesInfaisabilitesPrimales += X - ArrayXmax[Var]; + } + } + else if ( PositionDeLaVariable == HORS_BASE_SUR_BORNE_SUP ) ArrayX[Var] = ArrayXmax[Var]; + else { + /* La variable est HORS_BASE_A_ZERO ou HORS_BASE_SUR_BORNE_INF */ + ArrayX[Var] = 0.0; + if ( PositionDeLaVariable == HORS_BASE_SUR_BORNE_INF ) { + if ( StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) { + /* La variable est hors base sur borne inf mais qu'elle a une borne avec un StatutBorneSupCourante egal a + BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE alors elle est a -Xmax[Var] */ + ArrayX[Var] = -ArrayXmax[Var]; + } + } + } + } +} + +Spx->SommeDesInfaisabilitesPrimales = SommeDesInfaisabilitesPrimales; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_fixer_x_fonction_de_position_avec_base_complete.c b/src/ext/Sirius_Solver/simplexe/spx_fixer_x_fonction_de_position_avec_base_complete.c new file mode 100644 index 0000000000..18346ef678 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_fixer_x_fonction_de_position_avec_base_complete.c @@ -0,0 +1,95 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On calcule les valeurs de X en fonction de la position + hors base ou en base. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_FixerXEnFonctionDeSaPositionAvecBaseComplete( PROBLEME_SPX * Spx ) +{ +int Var; char PositionDeLaVariable; double X; double * ArrayX; char * TypeDeVariable; +double SommeDesInfaisabilitesPrimales; double * ArrayXmax; double * BBarre; +char * ArrayPositionDeLaVariable; int * ContrainteDeLaVariableEnBase; char * StatutBorneSupCourante; + +ArrayX = Spx->X; +ArrayXmax = Spx->Xmax; +BBarre = Spx->BBarre; +TypeDeVariable = Spx->TypeDeVariable; +ArrayPositionDeLaVariable = Spx->PositionDeLaVariable; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +SommeDesInfaisabilitesPrimales = 0.; + +if ( Spx->NombreDeBornesAuxiliairesUtilisees == 0 ) { + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + PositionDeLaVariable = ArrayPositionDeLaVariable[Var]; + if ( PositionDeLaVariable == EN_BASE_LIBRE ) { + X = BBarre[ContrainteDeLaVariableEnBase[Var]]; + ArrayX[Var] = X; + /* Attention ici on utilise le fait que par translation on a toujours Xmin = 0. */ + if ( X < 0. && TypeDeVariable[Var] != NON_BORNEE ) SommeDesInfaisabilitesPrimales += -X; + else { + if ( X > ArrayXmax[Var] ) SommeDesInfaisabilitesPrimales += X - ArrayXmax[Var]; + } + } + else if ( PositionDeLaVariable == HORS_BASE_SUR_BORNE_SUP ) ArrayX[Var] = ArrayXmax[Var]; + else ArrayX[Var] = 0.0; + } +} +else { + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + PositionDeLaVariable = ArrayPositionDeLaVariable[Var]; + if ( PositionDeLaVariable == EN_BASE_LIBRE ) { + X = BBarre[ContrainteDeLaVariableEnBase[Var]]; + ArrayX[Var] = X; + /* Attention ici on utilise le fait que par translation on a toujours Xmin = 0. */ + if ( X < 0. && TypeDeVariable[Var] != NON_BORNEE ) SommeDesInfaisabilitesPrimales += -X; + else { + if ( X > ArrayXmax[Var] ) SommeDesInfaisabilitesPrimales += X - ArrayXmax[Var]; + } + } + else if ( PositionDeLaVariable == HORS_BASE_SUR_BORNE_SUP ) ArrayX[Var] = ArrayXmax[Var]; + else { + /* La variable est HORS_BASE_A_ZERO ou HORS_BASE_SUR_BORNE_INF */ + ArrayX[Var] = 0.0; + if ( PositionDeLaVariable == HORS_BASE_SUR_BORNE_INF ) { + if ( StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) { + /* La variable est hors base sur borne inf mais qu'elle a une borne avec un StatutBorneSupCourante egal a + BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE alors elle est a -Xmax[Var] */ + ArrayX[Var] = -ArrayXmax[Var]; + } + } + } + } +} + +Spx->SommeDesInfaisabilitesPrimales = SommeDesInfaisabilitesPrimales; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_fixer_x_fonction_de_position_avec_base_reduite.c b/src/ext/Sirius_Solver/simplexe/spx_fixer_x_fonction_de_position_avec_base_reduite.c new file mode 100644 index 0000000000..119c0bb4ed --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_fixer_x_fonction_de_position_avec_base_reduite.c @@ -0,0 +1,154 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On calcule les valeurs de X en fonction de la position + hors base ou en base. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define CYCLE 10 + +/*----------------------------------------------------------------------------*/ + +void SPX_FixerXEnFonctionDeSaPositionAvecBaseReduite( PROBLEME_SPX * Spx ) +{ +int Var; double X; double * ArrayX; char * TypeDeVariable; int Var1; int Cnt; +double SommeDesInfaisabilitesPrimales; double * ArrayXmax; double * BBarre; double * B; +char * ArrayPositionDeLaVariable; int r; char * StatutBorneSupCourante; int Colonne; +int * LigneDeLaBaseFactorisee; int * OrdreColonneDeLaBaseFactorisee; int RangDeLaMatriceFactorisee; +int * ColonneDeLaBaseFactorisee; int * Mdeb; int * NbTerm; int * Indcol; double * A; +int il; int ilMax; double Coeff; int * VariableEnBaseDeLaContrainte; char CalculHorsBaseReduite; +int NbViole; + +ArrayX = Spx->X; +ArrayXmax = Spx->Xmax; +BBarre = Spx->BBarre; +TypeDeVariable = Spx->TypeDeVariable; +ArrayPositionDeLaVariable = Spx->PositionDeLaVariable; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +SommeDesInfaisabilitesPrimales = 0.; + +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; +OrdreColonneDeLaBaseFactorisee = Spx->OrdreColonneDeLaBaseFactorisee; +ColonneDeLaBaseFactorisee = Spx->ColonneDeLaBaseFactorisee; +LigneDeLaBaseFactorisee = Spx->LigneDeLaBaseFactorisee; + +B = Spx->B; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; + +if ( Spx->CalculValeurDesVariablesBasiquesHorsBaseReduite <= 0 ) { + CalculHorsBaseReduite = OUI_SPX; + Spx->CalculValeurDesVariablesBasiquesHorsBaseReduite = CYCLE; +} +else { + CalculHorsBaseReduite = NON_SPX; + Spx->CalculValeurDesVariablesBasiquesHorsBaseReduite--; +} + +if ( CalculHorsBaseReduite == NON_SPX ) { + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) ArrayX[Var] = 0; +} + +if ( Spx->NombreDeBornesAuxiliairesUtilisees == 0 ) { + /* Calcul pour les variables hors base */ + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( ArrayPositionDeLaVariable[Var] == EN_BASE_LIBRE ) continue; + if ( ArrayPositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) ArrayX[Var] = ArrayXmax[Var]; + else ArrayX[Var] = 0.0; + } +} +else { + /* Calcul pour les variables hors base */ + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( ArrayPositionDeLaVariable[Var] == EN_BASE_LIBRE ) continue; + if ( ArrayPositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) ArrayX[Var] = ArrayXmax[Var]; + else { + /* La variable est HORS_BASE_A_ZERO ou HORS_BASE_SUR_BORNE_INF */ + ArrayX[Var] = 0.0; + if ( ArrayPositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + if ( StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) { + /* La variable est hors base sur borne inf mais qu'elle a une borne avec un StatutBorneSupCourante egal a + BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE alors elle est a -Xmax[Var] */ + ArrayX[Var] = -ArrayXmax[Var]; + } + } + } + } +} + +/* La base reduite */ +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + Colonne = ColonneDeLaBaseFactorisee[r]; + Var = VariableEnBaseDeLaContrainte[ColonneDeLaBaseFactorisee[r]]; + X = BBarre[r]; + /* Attention ici on utilise le fait que par translation on a toujours Xmin = 0. */ + if ( X < 0. && TypeDeVariable[Var] != NON_BORNEE ) SommeDesInfaisabilitesPrimales += -X; + else { + if ( X > ArrayXmax[Var] ) SommeDesInfaisabilitesPrimales += X - ArrayXmax[Var]; + } + ArrayX[Var] = X; +} + +/* La partie hors base reduite */ +NbViole = 0; +if ( CalculHorsBaseReduite == OUI_SPX ) { + for ( r = RangDeLaMatriceFactorisee ; r < Spx->NombreDeContraintes ; r++ ) { + Colonne = ColonneDeLaBaseFactorisee[r]; + Var = VariableEnBaseDeLaContrainte[ColonneDeLaBaseFactorisee[r]]; + Cnt = LigneDeLaBaseFactorisee[r]; + X = B[Cnt]; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + Coeff = 1; + while ( il < ilMax ) { + Var1 = Indcol[il]; + if ( Var1 == Var ) Coeff = A[il]; + else X -= A[il] * ArrayX[Var1]; + il++; + } + X /= Coeff; + /* Attention ici on utilise le fait que par translation on a toujours Xmin = 0. */ + if ( X < 0. && TypeDeVariable[Var] != NON_BORNEE ) { + SommeDesInfaisabilitesPrimales += -X; + NbViole++; + } + else if ( X > ArrayXmax[Var] ) { + SommeDesInfaisabilitesPrimales += X - ArrayXmax[Var]; + NbViole++; + } + ArrayX[Var] = X; /* C'est la variable non native */ + } + Spx->NombreDeVariablesBasiquesHorsBaseReduiteViolees = NbViole; +} + +Spx->SommeDesInfaisabilitesPrimales = SommeDesInfaisabilitesPrimales; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_fonctions.h b/src/ext/Sirius_Solver/simplexe/spx_fonctions.h new file mode 100644 index 0000000000..280876f327 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_fonctions.h @@ -0,0 +1,390 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifdef __cplusplus + extern "C" + { +# endif +# ifndef FONCTIONS_SPX_DEJA_DEFINIES +/*-----------------------------------------------------------------------------------------*/ + +# include "spx_definition_arguments.h" +# include "spx_define.h" + +/* En cours pour tests heuristique +spx_dual_sortir_les_variables_binaires.c + + +*/ + +/*----------------------------- Fonctions du simplexe ------------------------------*/ + +PROBLEME_SPX * SPX_Simplexe( PROBLEME_SIMPLEXE * , PROBLEME_SPX * ); + +void SPX_SimplexeCalculs( PROBLEME_SIMPLEXE * , PROBLEME_SPX * ); + +void SPX_AllouerProbleme( PROBLEME_SPX * , int , int , int * , int * ); + +void SPX_AugmenterLeNombreDeVariables( PROBLEME_SPX * ); + +void SPX_AugmenterLeNombreDeContraintes( PROBLEME_SPX * ); + +void SPX_AugmenterLaTailleDeLaMatriceDesContraintes( PROBLEME_SPX * ); + +void SPX_LibererProbleme( PROBLEME_SPX * ); + +void SPX_InitDateDebutDuCalcul( PROBLEME_SPX * ); + +void SPX_ControleDuTempsEcoule( PROBLEME_SPX * ); + +/*---------------------------------------------------------------------------------*/ + +void SPX_ConstruireLeProbleme( PROBLEME_SPX * , + double * , double * , double * , double * , int , int * , + int , int * , int * , int * , double * , char * , + double * , int * , int , int * , double , int ); + +void SPX_ModifierLeProbleme( PROBLEME_SPX * , double * , double * , double * , double * , + int , int * , double , int ); + +void SPX_OrdonnerMatriceDesContraintes( int , int * , int * , int * , double * ); + +void SPX_ConstruireLaBaseDuProblemeModifie( PROBLEME_SPX * , int , int * , int , + int * ); + +void SPX_CompleterLaBaseDuProblemeModifie( PROBLEME_SPX * , int , int , int * ); + +void SPX_ModifierLeVecteurCouts( PROBLEME_SPX * , double * , int ); + +void SPX_ModifierLeVecteurSecondMembre( PROBLEME_SPX * , double * , char * , int ); + +void SPX_InitialiserLeNombreDesVariablesHorsBaseDesContraintes( PROBLEME_SPX * ); + +void SPX_MettreAJourLeNombreDesVariablesHorsBaseDesContraintes( PROBLEME_SPX * ); + +void SPX_InitialiserLeTableauDesVariablesHorsBase( PROBLEME_SPX * ); + +void SPX_MajDuTableauDesVariablesHorsBase( PROBLEME_SPX * ); + +void SPX_InitialiserLesVariablesEnBaseAControler( PROBLEME_SPX * ); + +void SPX_MajDesVariablesEnBaseAControler( PROBLEME_SPX * , int , int * , int * ); + +void SPX_AjouterLesCoupes( PROBLEME_SPX * , int , char * , int * , int * , int * , double * , double * ); + +void SPX_MettreLaContrainteSousFormeStandard( PROBLEME_SPX * , int ); + +void SPX_RecupererLaSolution( PROBLEME_SPX * , int , double * , int * , int , int * , int * , int * ); + +void SPX_RecuperationSimplifieeDeLaSolutionPourStrongBranching( PROBLEME_SPX * , int , int * , int * , int * ); + +void SPX_RecupererLaSolutionSurLesCoupes( PROBLEME_SPX * , int , int * , char * ); + +void SPX_ChainageDeLaTransposee( PROBLEME_SPX * , int ); + +void SPX_ModifierLeChainageDeLaTransposee( PROBLEME_SPX * ); + +void SPX_TranslaterLesBornes( PROBLEME_SPX * ); + +void SPX_CalculerLeScaling( PROBLEME_SPX * ); + +void SPX_ArrondiEnPuissanceDe2( double * ); + +void SPX_Scaling( PROBLEME_SPX * ); + +void SPX_AjusterTolerancesVariablesEntieres( PROBLEME_SPX * ); + +void SPX_UnScaling( PROBLEME_SPX * ); + +void SPX_VerifierAdmissibiliteDuale( PROBLEME_SPX * , int * ); + +void SPX_ReinitialiserLesCoutsNatifSiCestPossible( PROBLEME_SPX * ); + +void SPX_BruitageInitialDesCouts( PROBLEME_SPX * ); + +void SPX_FixerXEnFonctionDeSaPosition( PROBLEME_SPX * ); + +void SPX_CalculDuCout( PROBLEME_SPX * ); + +void SPX_CalculDuCoutSimplifie( PROBLEME_SPX * ); + +void SPX_ResoudreUBEgalC( PROBLEME_SPX * , char , double * , int * , int * , char * , char ); + +void SPX_ResolutionDeSystemeTransposee( PROBLEME_SPX * , char , double * , int * , int * , char * , char , char ); + +void SPX_AppliquerLesEtaVecteursTransposee( PROBLEME_SPX * , double * , int * , int * , char , char ); + +void SPX_CalculerErBMoins1( PROBLEME_SPX * , char ); + +void SPX_CalculerErBMoins1AvecBaseComplete( PROBLEME_SPX * , char ); + +void SPX_CalculerErBMoins1AvecBaseReduite( PROBLEME_SPX * , char ); + +void SPX_TenterRestaurationCalculErBMoinsEnHyperCreux( PROBLEME_SPX * ); + +void SPX_TenterRestaurationCalculABarreSEnHyperCreux( PROBLEME_SPX * ); + +void SPX_ResoudreBYegalA( PROBLEME_SPX * , char , double * , int * , int * , char * , char , char , char ); + +void SPX_ResolutionDeSysteme( PROBLEME_SPX * , char , double * , int * , int * , char * , char , char , char ); + +void SPX_AppliquerLesEtaVecteurs( PROBLEME_SPX * , double * , int * , int * , char , char ); + +void SPX_CalculerPi( PROBLEME_SPX * ); + +void SPX_CalculerPiAvecBaseReduite( PROBLEME_SPX * ); + +void SPX_CalculerPiAvecBaseComplete( PROBLEME_SPX * ); + +void SPX_MettreAJourPi( void /* PROBLEME_SPX * */ ); + +void SPX_CalculerLesCoutsReduits( PROBLEME_SPX * ); + +void SPX_MettreAJourLesCoutsReduits( PROBLEME_SPX * ); + +void SPX_CalculerBBarre( PROBLEME_SPX * ); + +void SPX_CalculerBBarreAvecBaseReduite( PROBLEME_SPX * ); + +void SPX_CalculerBBarreAvecBaseComplete( PROBLEME_SPX * ); + +void SPX_CalculerBBarreAHorsReduite( PROBLEME_SPX * ); + +void SPX_MettreAJourBBarre( PROBLEME_SPX * ); + +void SPX_MettreAJourBBarreAvecBaseReduite( PROBLEME_SPX * , double * , int * , int * , char * ); + +void SPX_MettreAJourBBarreAvecBaseComplete( PROBLEME_SPX * , double * , int * , int * , char * ); + +void SPX_FactoriserLaBase( PROBLEME_SPX * ); + +void SPX_CalculerABarreS( PROBLEME_SPX * ); + +void SPX_CalculerABarreSAvecBaseReduite( PROBLEME_SPX * , char * , char * , char * , char * ); + +void SPX_CalculerABarreSAvecBaseComplete( PROBLEME_SPX * , char * , char * , char * , char * ); + +void SPX_VerifierABarreS( PROBLEME_SPX * ); +void SPX_VerifierABarreSAvecBaseReduite( PROBLEME_SPX * ); +void SPX_VerifierABarreSAvecBaseComplete( PROBLEME_SPX * ); + +void SPX_FaireLeChangementDeBase( PROBLEME_SPX * ); + +void SPX_MettreAJourLaBase( PROBLEME_SPX * , int * ); + +void SPX_InitialiserLesIndicateursHyperCreux( PROBLEME_SPX * ); + +/*------------------------ Specifique algorithme dual -----------------------------*/ + +void SPX_DualSimplexe( PROBLEME_SPX * ); + +void SPX_DualControlerOptimalite( PROBLEME_SPX * , int * , char * ); + +void SPX_DualControleDualNonBorne( PROBLEME_SPX * , char * ); + +void SPX_DualConstruireUneCrashBase( PROBLEME_SPX * ); + +void SPX_DualCreerVariableDeBase( PROBLEME_SPX * , int ); + +void SPX_DualConstruireLaBaseInitiale( PROBLEME_SPX * , int , int * , int , int * , char * ); + +void SPX_DualReconstruireUneBase( PROBLEME_SPX * , char * ); + +/* */ + void SPX_DualPhase1Simplexe( PROBLEME_SPX * ); + void SPX_DualPhase1PositionnerLesVariablesHorsBase( PROBLEME_SPX * ); + void SPX_DualPhase1UtiliserLesBornesAuxiliaires( PROBLEME_SPX * ); + void SPX_DualPhase1CalculerV( PROBLEME_SPX * ); + void SPX_DualPhase1ChoixDeLaVariableSortante( PROBLEME_SPX * ); + void SPX_DualPhase1ChoixDeLaVariableSortanteAuHasard( PROBLEME_SPX * ); + void SPX_DualPhase1TestDuRatio( PROBLEME_SPX * ); + void SPX_DualPhase1ChoixDeLaVariableEntrante( PROBLEME_SPX * ); + double SPX_CalculerUneBorneAuxiliaire( PROBLEME_SPX * , int ); +/* */ + +void SPX_DualChoixDeLaVariableSortante( PROBLEME_SPX * ); + +void SPX_DualChoixDeLaVariableSortanteAuHasard( PROBLEME_SPX * ); + +void SPX_DualCalculerNBarreR( PROBLEME_SPX * , char , char * ); + +void SPX_DualCalculerNBarreRStandard( PROBLEME_SPX * ); + +void SPX_DualCalculerNBarreRHyperCreux( PROBLEME_SPX * ); + +void SPX_DualConfirmerDualNonBorne( PROBLEME_SPX * ); + +void SPX_DualVerifierErBMoinsUn( PROBLEME_SPX * ); + +void SPX_DualComparerABarreSEtNBarreR( PROBLEME_SPX * ); + +void SPX_DualChoixDeLaVariableEntrante( PROBLEME_SPX * ); + +void SPX_DualTestDuRatio( PROBLEME_SPX * , int * ); + +void SPX_InitDualPoids( PROBLEME_SPX * ); + +void SPX_ResetReferenceSpace( PROBLEME_SPX * ); + +void SPX_MajPoidsDualSteepestEdge( PROBLEME_SPX * ); + +void SPX_DualSteepestEdgeResolutionBaseReduite( PROBLEME_SPX * , double * , char , char * , int * , char * , char * ); + +void SPX_DualSteepestEdgeResolutionAvecBaseComplete( PROBLEME_SPX * , double * , char , char * , int * , char * , char * ); + +void SPX_DualSteepestGestionIndicateursHyperCreux( PROBLEME_SPX * , char , char , char , char * , char * ); + +void SPX_DualSteepestControleDuPoidsDeCntBase( PROBLEME_SPX * , double , char * ); + +void SPX_DualSteepestVariablesDeBornesIdentiques( PROBLEME_SPX * , double * ); + +void SPX_TenterRestaurationCalculTauEnHyperCreux( PROBLEME_SPX * ); + +void SPX_DualSupprimerLesBornesAuxiliaires( PROBLEME_SPX * ); + +void SPX_DualControlerLesBornesAuxiliaires( PROBLEME_SPX * , char * ); + +void SPX_DualRepositionnerLesBornes( PROBLEME_SPX * , char * ); + +void SPX_SupprimerUneBorneAuxiliaire( PROBLEME_SPX * , int ); + +/*----------------- Specifique utilitaires branch and bound --------------------*/ + +void SPX_DualEpurerLaBaseSimplexe( PROBLEME_SPX * , int * , char * , char * ); + +void SPX_SauvegardesBranchAndBoundAndCut( PROBLEME_SPX * ); + +void SPX_DualStrongBranching( PROBLEME_SPX * , int , double , double , double , double * , + int * , char * , double * , int * , int * , int * , int , + int * , int , int , int * , char * ); + +void SPX_DualStrongBranchingGUB( PROBLEME_SPX * , + int , int * , double * , + int * , char * , double * , int * , int * , int * , + int , int * , int , + int , int * , char * ); + +/*----------------- Specifique pour les coupes de Gomory --------------------*/ + +int SPX_PreparerLeCalculDesGomory( PROBLEME_SPX * , int , int * ); + +void SPX_TerminerLeCalculDesGomory( PROBLEME_SPX * ); + +void SPX_CalculerUneCoupeDeGomory( PROBLEME_SPX * , int ,double , double , double , double , double , + int * , double * , int * , double * , char * ); + +void SPX_CalculMIRPourCoupeDeGomoryOuIntersection( PROBLEME_SPX * , double , double , double , double , + double , double , double * , char * , double * , char * , + int * , double * , int * , double * , char * ); + +/*----------------- Specifique pour 2 MIR cuts (a revoir car eput etre ameliore --------------------*/ + +void SPX_GetTableauRow( PROBLEME_SPX * , int , double , int * , double * , int * , double * , char * ); + +/*----------------- Specifique pour les coupes d'intersection --------------------*/ + +void SPX_InitCoupesDIntersection( PROBLEME_SPX * , char * , double * ); + +void SPX_TerminerLeCalculDesCoupesDIntersection( PROBLEME_SPX * ); + +void SPX_AllocLignePourCoupesDIntersection( PROBLEME_SPX * ); + +void SPX_MatriceCoupesDIntersection( PROBLEME_SPX * ); + +double SPX_CalculDeLaNouvelleNorme( LIGNE_DE_PRODUITS_SCALAIRES * , LIGNE_DE_PRODUITS_SCALAIRES * , int , int , double ); + +void SPX_MajMatricePourCoupesDIntersection( PROBLEME_SPX * , int , int , double , double ); + +void SPX_ReductionDesNormesPourCoupesDIntersection( PROBLEME_SPX * ); + +int SPX_NombrePotentielDeCoupesDIntersection( PROBLEME_SPX * ); + +void SPX_CalculerUneCoupeDIntersection( PROBLEME_SPX * , int , double , double , double , double , double , + int * , double * , int * , double * , char * ); + +/*----------------- Specifique pour l'exploration rapide en profondeur --------------------*/ +void Spx_ModifierLesDonneesSurInstanciation( PROBLEME_SPX * , int , int ); +void Spx_RemettreLesDonneesAvantInstanciation( PROBLEME_SPX * , int , int ); +void SPX_SauvegarderLaBaseDeDepart( PROBLEME_SPX * , void * ); +void SPX_InitialiserLaBaseDeDepart( PROBLEME_SPX * , void * ); +void Spx_CreationNoeudsFils( PROBLEME_SPX * , void * , void * , int ); +void SPX_ChoisirLaVariableAInstancier( PROBLEME_SPX * , void * ,int * , int * ); +void SPX_RecupererLaSolutionSiExplorationRapide( PROBLEME_SPX * , void * , void * , void * , int * ); + +/*-----------------------------------------------------------------------------------------*/ + +/* Pour le simplexe generalise de Metrix */ + +PROBLEME_SPX * SPX_SimplexeGeneralise( PROBLEME_SIMPLEXE * , PROBLEME_SPX * , char , double , int * , + char * , int * , int * , double * , char , char ); + +void SPX_ClasserDesVariables( double * , int , int , int * , int , int * , int * , char ); + + +/*-----------------------------------------------------------------------------------------*/ +/* En test: pivotages supplementaires pour obtenir une solution entiere par pivotages degeneres */ + +void SPX_DualPivotagesComplementaires( PROBLEME_SPX * ); + +/*-----------------------------------------------------------------------------------------*/ +/* Heuristique */ +void SPX_HeuristiqueArrondis( PROBLEME_SPX * , int * , int , double * , int * , int , int * , + int * , int * , int , int , int * , double * , double * ); +void SPX_RAZHeuristiqueArrondis( PROBLEME_SPX * ); + +/*-----------------------------------------------------------------------------------------*/ + +void SPX_EcrireProblemeSpxAuFormatMPS( PROBLEME_SPX * ); + +void SPX_EcrireProblemeAuFormatMPS( PROBLEME_SIMPLEXE ); + +void SPX_EcrireJeuDeDonneesLineaireAuFormatMPS(int , int * , double * , double * , double * , int , double * , char * , int * , int * , double * , int * ); + +/*-----------------------------------------------------------------------------------------*/ + +void SPX_OrdonnerLesContraintesPourLaBase( PROBLEME_SPX * ); + +void SPX_ConstructionDeLaMatriceReduite( PROBLEME_SPX * ); + +void SPX_TestPassageBaseReduiteBaseComplete( PROBLEME_SPX * ); + +void SPX_ControleDesVariablesBasiquesHorsBaseReduite( PROBLEME_SPX * , int * ); + +void SPX_VerifierLesVecteursDeTravail( PROBLEME_SPX * ); + +/*-----------------------------------------------------------------------------------------*/ + +void SPX_InitMatriceHorsBase( PROBLEME_SPX * ); + +void SPX_MettreAJourLaMatriceHorsBase( PROBLEME_SPX * ); + +/*-----------------------------------------------------------------------------------------*/ + +# define FONCTIONS_SPX_DEJA_DEFINIES +# endif +# ifdef __cplusplus + } +# endif + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_gestion_bases_en_exploration_rapide.c b/src/ext/Sirius_Solver/simplexe/spx_gestion_bases_en_exploration_rapide.c new file mode 100644 index 0000000000..50257e95c5 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_gestion_bases_en_exploration_rapide.c @@ -0,0 +1,112 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Sauvegarde et restitution des bases en exploration rapide + en profondeur. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +#include "bb_define.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void SPX_SauvegarderLaBaseDeDepart( PROBLEME_SPX * Spx , void * Noeud ) +{ +BASE_SIMPLEXE * BaseDuNoeud; NOEUD * NoeudEnCours; + +NoeudEnCours = (NOEUD *) Noeud; + +/* Initialisation a partir de la base simplexe */ +NoeudEnCours->BaseSimplexeDuNoeud = (BASE_SIMPLEXE *) malloc( sizeof( BASE_SIMPLEXE ) ); +if ( NoeudEnCours->BaseSimplexeDuNoeud == NULL ) { + /* Completer la gestion de la saturation memoire */ + printf("Simplexe -> memoire insuffisante pour l allocation de l espace de travail \n"); + return; +} +BaseDuNoeud = NoeudEnCours->BaseSimplexeDuNoeud; + +BaseDuNoeud->PositionDeLaVariable = (char *) malloc( Spx->NombreDeVariables * sizeof( char ) ); +BaseDuNoeud->InDualFramework = (char *) malloc( Spx->NombreDeVariables * sizeof( char ) ); +BaseDuNoeud->ContrainteDeLaVariableEnBase = (int *) malloc( Spx->NombreDeVariables * sizeof( int ) ); +BaseDuNoeud->DualPoids = (double *) malloc( Spx->NombreDeContraintes * sizeof( double ) ); +BaseDuNoeud->VariableEnBaseDeLaContrainte = (int *) malloc( Spx->NombreDeContraintes * sizeof( int ) ); + +if ( BaseDuNoeud->PositionDeLaVariable == NULL || BaseDuNoeud->InDualFramework == NULL || + BaseDuNoeud->ContrainteDeLaVariableEnBase == NULL || BaseDuNoeud->DualPoids == NULL || + BaseDuNoeud->VariableEnBaseDeLaContrainte == NULL ) { + /* Completer la gestion de la saturation memoire */ + printf("Simplexe -> memoire insuffisante pour l allocation de l espace de travail \n"); + return; +} + +memcpy( (char *) BaseDuNoeud->DualPoids, + (char *) Spx->DualPoids, Spx->NombreDeContraintes * sizeof( double ) ); + +memcpy( (char *) BaseDuNoeud->VariableEnBaseDeLaContrainte, + (char *) Spx->VariableEnBaseDeLaContrainte, Spx->NombreDeContraintes * sizeof( int ) ); + +memcpy( (char *) BaseDuNoeud->PositionDeLaVariable, + (char *) Spx->PositionDeLaVariable, Spx->NombreDeVariables * sizeof( char ) ); + +memcpy( (char *) BaseDuNoeud->InDualFramework, + (char *) Spx->InDualFramework, Spx->NombreDeVariables * sizeof( char ) ); + +memcpy( (char *) BaseDuNoeud->ContrainteDeLaVariableEnBase, + (char *) Spx->ContrainteDeLaVariableEnBase, Spx->NombreDeVariables * sizeof( int ) ); + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_InitialiserLaBaseDeDepart( PROBLEME_SPX * Spx , void * Noeud ) +{ +NOEUD * NoeudEnCours; BASE_SIMPLEXE * BaseDuNoeud; + +/* Initialisation a partir de la base simplexe */ +NoeudEnCours = (NOEUD *) Noeud; +BaseDuNoeud = NoeudEnCours->BaseSimplexeDuNoeud; + +memcpy( (char *) Spx->DualPoids, + (char *) BaseDuNoeud->DualPoids, Spx->NombreDeContraintes * sizeof( double ) ); + +memcpy( (char *) Spx->VariableEnBaseDeLaContrainte, + (char *) BaseDuNoeud->VariableEnBaseDeLaContrainte, Spx->NombreDeContraintes * sizeof( int ) ); + +memcpy( (char *) Spx->PositionDeLaVariable, + (char *) BaseDuNoeud->PositionDeLaVariable, Spx->NombreDeVariables * sizeof( char ) ); + +memcpy( (char *) Spx->InDualFramework, + (char *) BaseDuNoeud->InDualFramework, Spx->NombreDeVariables * sizeof( char ) ); + +memcpy( (char *) Spx->ContrainteDeLaVariableEnBase, + (char *) BaseDuNoeud->ContrainteDeLaVariableEnBase, Spx->NombreDeVariables * sizeof( int ) ); + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_gestion_listes_des_variables_EN_HORS_base.c b/src/ext/Sirius_Solver/simplexe/spx_gestion_listes_des_variables_EN_HORS_base.c new file mode 100644 index 0000000000..1265a928ad --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_gestion_listes_des_variables_EN_HORS_base.c @@ -0,0 +1,515 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + FONCTION: Gestion des listes de variables hors base et des bornes + sur les variables en base. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_fonctions.h" + +# define MARGE_ABSOLUE_MIN 1.e-12 /*1.e-12*/ +# define MARGE_ABSOLUE_MAX 1.e-9 /*1.e-9*/ + +/*----------------------------------------------------------------------------*/ + +void SPX_InitialiserLeNombreDesVariablesHorsBaseDesContraintes( PROBLEME_SPX * Spx ) +{ +int il; int ilMax; int Cnt; char * PositionDeLaVariable; int Nb; int * Mdeb; int * NbTerm; +int * Indcol; int * NombreDeVariablesHorsBaseDeLaContrainte; + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +NombreDeVariablesHorsBaseDeLaContrainte = Spx->NombreDeVariablesHorsBaseDeLaContrainte; +PositionDeLaVariable = Spx->PositionDeLaVariable; + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + Nb = 0; + while ( il < ilMax ) { + if ( PositionDeLaVariable[Indcol[il]] != EN_BASE_LIBRE ) Nb++; + il++; + } + NombreDeVariablesHorsBaseDeLaContrainte[Cnt] = Nb; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_MettreAJourLeNombreDesVariablesHorsBaseDesContraintes( PROBLEME_SPX * Spx ) +{ +int ic; int icMx; int * Cdeb; int * CNbTerm; int * NumeroDeContrainte; int * NombreDeVariablesHorsBaseDeLaContrainte; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; +NombreDeVariablesHorsBaseDeLaContrainte = Spx->NombreDeVariablesHorsBaseDeLaContrainte; + +/* Mise a jour du nombre de variables hors base de chaque contrainte */ +ic = Cdeb[Spx->VariableSortante]; +icMx = ic + CNbTerm[Spx->VariableSortante]; +while ( ic < icMx ) { + NombreDeVariablesHorsBaseDeLaContrainte[NumeroDeContrainte[ic]]++; + ic++; +} +ic = Cdeb[Spx->VariableEntrante]; +icMx = ic + CNbTerm[Spx->VariableEntrante]; +while ( ic < icMx ) { + NombreDeVariablesHorsBaseDeLaContrainte[NumeroDeContrainte[ic]]--; + ic++; +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_InitialiserLeTableauDesVariablesHorsBase( PROBLEME_SPX * Spx ) +{ +int Var; char * PositionDeLaVariable; int * CNbTerm; int * NumerosDesVariablesHorsBase; +int NombreDeVariablesHorsBase; int * IndexDeLaVariableDansLesVariablesHorsBase; int NombreDeVariables; +char * InDualFramework; double * Xmin; double * Xmax; char LeSteepestEdgeEstInitilise; + +SPX_InitialiserLeNombreDesVariablesHorsBaseDesContraintes( Spx ); +/*SPX_InitMatriceHorsBase( Spx );*/ + +NombreDeVariables = Spx->NombreDeVariables; +PositionDeLaVariable = Spx->PositionDeLaVariable; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) CNbTerm = Spx->CNbTermProblemeReduit; +else CNbTerm = Spx->CNbTerm; + +CNbTerm = Spx->CNbTerm; /* Pour l'instant on les met toutes car dans la phase 1 on les positionne pour etre + dual admissible et on cree les bornes auxiliaires necessaires. Donc s'il manque + des variables hors base, la partie des variables qui intervient uniquement dans + la partie hors probleme reduit n'est pas prise en compte et en realite la + base de depart n'est pas duale realisable */ + +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +IndexDeLaVariableDansLesVariablesHorsBase = Spx->IndexDeLaVariableDansLesVariablesHorsBase; + +NombreDeVariablesHorsBase = 0; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) IndexDeLaVariableDansLesVariablesHorsBase[Var] = -1; + +Spx->PresenceDeVariablesDeBornesIdentiques = NON_SPX; + +Xmin = Spx->Xmin; +Xmax = Spx->Xmax; +InDualFramework = Spx->InDualFramework; +LeSteepestEdgeEstInitilise = Spx->LeSteepestEdgeEstInitilise; +if ( LeSteepestEdgeEstInitilise == OUI_SPX ) { + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + + if ( CNbTerm[Var] == 0 ) continue; + + if ( Spx->PresenceDeVariablesDeBornesIdentiques == NON_SPX ) { + if ( Xmin[Var] == Xmax[Var] ) Spx->PresenceDeVariablesDeBornesIdentiques = OUI_SPX; + } + if ( PositionDeLaVariable[Var] != EN_BASE_LIBRE ) { + /* Si la variable a Xmin = Xmax (c'est a dire 0) on ne la met pas dans la liste. + Et alors, soit il y a une solution avec le probleme reduit et alors elle + est optimale, soit il n'y en a pas et il n'y en aurait de toutes facons pas + meme si la variable n'avait pas ete enlevee de la liste */ + /* Noter que si la variable etait dans le framework du steepest edge, on ne sait pas + la faire sortir proprement. Cela entrainera donc une reinitialisation du + steepest edge a un moment donne. Mais les essais numeriques montrent que c'est + malgre tout une facon de faire qui accelere les temps de calcul */ + if ( InDualFramework[Var] == OUI_SPX ) { + NumerosDesVariablesHorsBase[NombreDeVariablesHorsBase] = Var; + IndexDeLaVariableDansLesVariablesHorsBase[Var] = NombreDeVariablesHorsBase; + NombreDeVariablesHorsBase++; + } + else if ( Xmin[Var] != Xmax[Var] ) { + NumerosDesVariablesHorsBase[NombreDeVariablesHorsBase] = Var; + IndexDeLaVariableDansLesVariablesHorsBase[Var] = NombreDeVariablesHorsBase; + NombreDeVariablesHorsBase++; + } + } + } +} +else { + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + + if ( CNbTerm[Var] == 0 ) continue; + + if ( Spx->PresenceDeVariablesDeBornesIdentiques == NON_SPX ) { + if ( Xmin[Var] == Xmax[Var] ) Spx->PresenceDeVariablesDeBornesIdentiques = OUI_SPX; + } + if ( PositionDeLaVariable[Var] != EN_BASE_LIBRE ) { + /* Si la variable a Xmin = Xmax (c'est a dire 0) on ne la met pas dans la liste. + Et alors, soit il y a une solution avec le probleme reduit et alors elle + est optimale, soit il n'y en a pas et il n'y en aurait de toutes facons pas + meme si la variable n'avait pas ete enlevee de la liste */ + /* Noter que si la variable etait dans le framework du steepest edge, on ne sait pas + la faire sortir proprement. Cela entrainera donc une reinitialisation du + steepest edge a un moment donne. Mais les essais numeriques montrent que c'est + malgre tout une facon de faire qui accelere les temps de calcul */ + if ( Xmin[Var] != Xmax[Var] ) { + NumerosDesVariablesHorsBase[NombreDeVariablesHorsBase] = Var; + IndexDeLaVariableDansLesVariablesHorsBase[Var] = NombreDeVariablesHorsBase; + NombreDeVariablesHorsBase++; + } + } + } +} + +Spx->NombreDeVariablesHorsBase = NombreDeVariablesHorsBase; +/* +printf("SPX_InitialiserLeTableauDesVariablesHorsBase NombreDeVariablesHorsBase %d au lieu de %d\n", + NombreDeVariablesHorsBase, Spx->NombreDeVariables-Spx->NombreDeContraintes); +*/ +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_MajDuTableauDesVariablesHorsBase( PROBLEME_SPX * Spx ) +{ +int i; int j; int Var; int VariableEntrante; int VariableSortante; +int * IndexDeLaVariableDansLesVariablesHorsBase; int * NumerosDesVariablesHorsBase; +double * Xmin; double * Xmax; + +SPX_MettreAJourLeNombreDesVariablesHorsBaseDesContraintes( Spx ); +/*SPX_MettreAJourLaMatriceHorsBase( Spx );*/ + +VariableEntrante = Spx->VariableEntrante; +VariableSortante = Spx->VariableSortante; +IndexDeLaVariableDansLesVariablesHorsBase = Spx->IndexDeLaVariableDansLesVariablesHorsBase; +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +Xmin = Spx->Xmin; +Xmax = Spx->Xmax; + +i = IndexDeLaVariableDansLesVariablesHorsBase[VariableEntrante]; +NumerosDesVariablesHorsBase[i] = VariableSortante; + +/* Si la variable sortante a Xmin = Xmax (c'est a dire 0) on la sort de la liste. + Et alors, soit il y a une solution avec le probleme reduit et alors elle + est optimale, soit il n'y en a pas et il n'y en aurait de toutes facons pas + meme si la variable n'avait pas ete enlevee de la liste */ +if ( Xmin[VariableSortante] != Xmax[VariableSortante] ) { + IndexDeLaVariableDansLesVariablesHorsBase[VariableSortante] = i; + IndexDeLaVariableDansLesVariablesHorsBase[VariableEntrante] = -1; +} +else { + IndexDeLaVariableDansLesVariablesHorsBase[VariableSortante] = -1; + IndexDeLaVariableDansLesVariablesHorsBase[VariableEntrante] = -1; + j = Spx->NombreDeVariablesHorsBase - 1; + if ( j != i ) { + Var = NumerosDesVariablesHorsBase[j]; + IndexDeLaVariableDansLesVariablesHorsBase[Var] = i; + NumerosDesVariablesHorsBase [i] = Var; + } + Spx->NombreDeVariablesHorsBase--; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_InitialiserLesVariablesEnBaseAControler( PROBLEME_SPX * Spx ) +{ +int Var; int NbSurv; double X; int IndexMax; int Index; double BorSup; double BorInf; +int * VariableEnBaseDeLaContrainte; char * TypeDeVariable; double * Xmax ; +double * SeuilDeViolationDeBorne; double * ValeurDeViolationDeBorne; +double * DualPoids; int * IndexDansContrainteASurveiller; double MargeAbsolue; +int * NumerosDesContraintesASurveiller; double * BBarre; double ValBBarre; +int * ColonneDeLaBaseFactorisee; + +Spx->A1 = PNE_Rand( Spx->A1 ); /* Nombre aleatoire entre 0 et 1 */ +MargeAbsolue = MARGE_ABSOLUE_MIN; +MargeAbsolue += Spx->A1 * ( MARGE_ABSOLUE_MAX - MARGE_ABSOLUE_MIN ); + +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +TypeDeVariable = Spx->TypeDeVariable; +SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; +Xmax = Spx->Xmax; + +BBarre = Spx->BBarre; +DualPoids = Spx->DualPoids; +ValeurDeViolationDeBorne = Spx->ValeurDeViolationDeBorne; +IndexDansContrainteASurveiller = Spx->IndexDansContrainteASurveiller; +NumerosDesContraintesASurveiller = Spx->NumerosDesContraintesASurveiller; +NbSurv = 0; + +ColonneDeLaBaseFactorisee = Spx->ColonneDeLaBaseFactorisee; /* Ici a cause des warning de compilation */ +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) IndexMax = Spx->RangDeLaMatriceFactorisee; +else IndexMax = Spx->NombreDeContraintes; + +for ( Index = 0 ; Index < IndexMax ; Index++ ) IndexDansContrainteASurveiller[Index] = -1; + +for ( Index = 0 ; Index < IndexMax ; Index++ ) { + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + Var = VariableEnBaseDeLaContrainte[ColonneDeLaBaseFactorisee[Index]]; + } + else { + Var = VariableEnBaseDeLaContrainte[Index]; + } + + /* Initialisation des bornes et constitution de la liste */ + if ( TypeDeVariable[Var] == NON_BORNEE ) continue; + else { + ValBBarre = BBarre[Index]; + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + + # if PRICING_AVEC_VIOLATIONS_STRICTES == OUI_SPX + if ( SeuilDeViolationDeBorne[Var] > MargeAbsolue ) BorInf = -MargeAbsolue; + else BorInf = -SeuilDeViolationDeBorne[Var]; + # else + BorInf = -SeuilDeViolationDeBorne[Var]; + # endif + + if ( ValBBarre < BorInf ) { + /* On ajoute la contrainte dans la liste */ + NumerosDesContraintesASurveiller[NbSurv] = Index; + + # if POIDS_DANS_VALEUR_DE_VIOLATION == OUI_SPX + ValeurDeViolationDeBorne[NbSurv] = ( ValBBarre * ValBBarre ) / DualPoids[Index]; + # else + ValeurDeViolationDeBorne[NbSurv] = ValBBarre * ValBBarre; + # endif + + IndexDansContrainteASurveiller[Index] = NbSurv; + NbSurv++; + } + + } + else { + /* La variable est bornee */ + + # if PRICING_AVEC_VIOLATIONS_STRICTES == OUI_SPX + if ( SeuilDeViolationDeBorne[Var] > MargeAbsolue ) { + BorInf = -MargeAbsolue; + BorSup = Xmax[Var] + MargeAbsolue; + } + else { + BorInf = -SeuilDeViolationDeBorne[Var]; + BorSup = Xmax[Var] + SeuilDeViolationDeBorne[Var]; + } + # else + BorInf = -SeuilDeViolationDeBorne[Var]; + BorSup = Xmax[Var] + SeuilDeViolationDeBorne[Var]; + # endif + + if ( ValBBarre < BorInf ) { + /* On ajoute la contrainte dans la liste */ + NumerosDesContraintesASurveiller[NbSurv] = Index; + + # if POIDS_DANS_VALEUR_DE_VIOLATION == OUI_SPX + ValeurDeViolationDeBorne[NbSurv] = ( ValBBarre * ValBBarre ) / DualPoids[Index]; + # else + ValeurDeViolationDeBorne[NbSurv] = ValBBarre * ValBBarre; + # endif + + IndexDansContrainteASurveiller[Index] = NbSurv; + NbSurv++; + } + else if ( ValBBarre > BorSup ) { + /* On ajoute la contrainte dans la liste */ + NumerosDesContraintesASurveiller[NbSurv] = Index; + X = ValBBarre - Xmax[Var]; + + # if POIDS_DANS_VALEUR_DE_VIOLATION == OUI_SPX + ValeurDeViolationDeBorne[NbSurv] = ( X * X ) / DualPoids[Index]; + # else + ValeurDeViolationDeBorne[NbSurv] = X * X; + # endif + + IndexDansContrainteASurveiller[Index] = NbSurv; + NbSurv++; + } + } + } +} + +Spx->NombreDeContraintesASurveiller = NbSurv; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_MajDesVariablesEnBaseAControler( PROBLEME_SPX * Spx , int NbBBarreModifies, + int * IndexDeBBarreModifies, int * T ) +{ +int Var; int Index; int IndexMax; char Viole; int NbSurv; int * IndexDansContrainteASurveiller; +int * NumerosDesContraintesASurveiller; int Index1; int IndexCntBase; int k; int i; double BorSup; +double BorInf; int * VariableEnBaseDeLaContrainte; char * TypeDeVariable; double * SeuilDeViolationDeBorne; +double X; double * DualPoids; double * ValeurDeViolationDeBorne; int VariableSortante; +int VariableEntrante; double ValeurDeBBarre; double * BBarre; double * Xmax; +int * ColonneDeLaBaseFactorisee; double MargeAbsolue; + +Spx->A1 = PNE_Rand( Spx->A1 ); /* Nombre aleatoire entre 0 et 1 */ +MargeAbsolue = MARGE_ABSOLUE_MIN; +MargeAbsolue += Spx->A1 * ( MARGE_ABSOLUE_MAX - MARGE_ABSOLUE_MIN ); + +VariableSortante = Spx->VariableSortante; +VariableEntrante = Spx->VariableEntrante; + +ColonneDeLaBaseFactorisee = Spx->ColonneDeLaBaseFactorisee; /* Ici a cause des warning de compilation */ +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + IndexMax = Spx->RangDeLaMatriceFactorisee; + IndexCntBase = Spx->OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]]; +} +else { + IndexMax = Spx->NombreDeContraintes; + IndexCntBase = Spx->ContrainteDeLaVariableEnBase[VariableSortante]; +} + +# ifdef UTILISER_BORNES_AUXILIAIRES + if ( Spx->ChangementDeBase == OUI_SPX ) { + /* Si la variable entrante avait sur une borne sup auxiliaire on libere la borne */ + if ( Spx->NombreDeBornesAuxiliairesUtilisees > 0 ) SPX_SupprimerUneBorneAuxiliaire( Spx, VariableEntrante ); + } +# endif + +SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; +Xmax = Spx->Xmax; +TypeDeVariable = Spx->TypeDeVariable; + +BBarre = Spx->BBarre; +DualPoids = Spx->DualPoids; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + +NbSurv = Spx->NombreDeContraintesASurveiller; +IndexDansContrainteASurveiller = Spx->IndexDansContrainteASurveiller; +NumerosDesContraintesASurveiller = Spx->NumerosDesContraintesASurveiller; +ValeurDeViolationDeBorne = Spx->ValeurDeViolationDeBorne; + +for ( k = 0 ; k < NbBBarreModifies ; k++ ) { + Index = IndexDeBBarreModifies[k]; + T[Index] = -1; + Viole = NON_SPX; + ValeurDeBBarre = BBarre[Index]; + + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + Var = VariableEnBaseDeLaContrainte[ColonneDeLaBaseFactorisee[Index]]; + } + else { + Var = VariableEnBaseDeLaContrainte[Index]; + } + + if ( Var == VariableSortante ) Var = VariableEntrante; + + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + + # if PRICING_AVEC_VIOLATIONS_STRICTES == OUI_SPX + if ( SeuilDeViolationDeBorne[Var] > MargeAbsolue ) BorInf = -MargeAbsolue; + else BorInf = -SeuilDeViolationDeBorne[Var]; + # else + BorInf = -SeuilDeViolationDeBorne[Var]; + # endif + + if ( ValeurDeBBarre < BorInf ) { + Viole = OUI_SPX; + + # if POIDS_DANS_VALEUR_DE_VIOLATION == OUI_SPX + X = ( ValeurDeBBarre * ValeurDeBBarre ) / DualPoids[Index]; + # else + X = ValeurDeBBarre * ValeurDeBBarre; + # endif + + } + + } + else if ( TypeDeVariable[Var] == BORNEE ) { + + # if PRICING_AVEC_VIOLATIONS_STRICTES == OUI_SPX + if ( SeuilDeViolationDeBorne[Var] > MargeAbsolue ) { + BorInf = -MargeAbsolue; + BorSup = Xmax[Var] + MargeAbsolue; + } + else { + BorInf = -SeuilDeViolationDeBorne[Var]; + BorSup = Xmax[Var] + SeuilDeViolationDeBorne[Var]; + } + # else + BorInf = -SeuilDeViolationDeBorne[Var]; + BorSup = Xmax[Var] + SeuilDeViolationDeBorne[Var]; + # endif + + if ( ValeurDeBBarre < BorInf ) { + Viole = OUI_SPX; + + # if POIDS_DANS_VALEUR_DE_VIOLATION == OUI_SPX + X = ( ValeurDeBBarre * ValeurDeBBarre ) / DualPoids[Index]; + # else + X = ValeurDeBBarre * ValeurDeBBarre; + # endif + + } + + else if ( ValeurDeBBarre > BorSup ) { + Viole = OUI_SPX; + X = ValeurDeBBarre - Xmax[Var]; + # if POIDS_DANS_VALEUR_DE_VIOLATION == OUI_SPX + X = ( X * X ) / DualPoids[Index]; + # else + X = X * X; + # endif + + } + } + + i = IndexDansContrainteASurveiller[Index]; + if ( Viole == NON_SPX ) { + /* On enleve la contrainte de la liste */ + if ( i >= 0 ) { + /* On enleve la contrainte de la liste */ + IndexDansContrainteASurveiller[Index] = -1; + Index1 = NumerosDesContraintesASurveiller[NbSurv-1]; + if ( Index !=Index1 ) { + NumerosDesContraintesASurveiller[i] = Index1; + ValeurDeViolationDeBorne [i] = ValeurDeViolationDeBorne[NbSurv-1]; + IndexDansContrainteASurveiller[Index1] = i; + } + NbSurv--; + } + } + else { + if ( i < 0 ) { + /* La Contrainte est nouvellement violee */ + /* On ajoute la contrainte dans la liste */ + NumerosDesContraintesASurveiller[NbSurv] = Index; + ValeurDeViolationDeBorne [NbSurv] = X; + IndexDansContrainteASurveiller[Index] = NbSurv; + NbSurv++; + } + else { + /* La variable est deja dans la liste: on actualise la valeur */ + ValeurDeViolationDeBorne[i] = X; + } + } +} + +Spx->NombreDeContraintesASurveiller = NbSurv; + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_gestion_temps_de_calcul.c b/src/ext/Sirius_Solver/simplexe/spx_gestion_temps_de_calcul.c new file mode 100644 index 0000000000..260da0015a --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_gestion_temps_de_calcul.c @@ -0,0 +1,62 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Gestion des temps de calcul + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + + +/*----------------------------------------------------------------------------*/ + +void SPX_InitDateDebutDuCalcul( PROBLEME_SPX * Spx ) +{ +time_t HeureDeCalendrierDebut; + +time( &HeureDeCalendrierDebut ); +Spx->HeureDeCalendrierDebut = HeureDeCalendrierDebut; + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_ControleDuTempsEcoule( PROBLEME_SPX * Spx ) +{ +time_t HeureDeCalendrierCourant; +double TempsEcoule; + +if ( Spx->DureeMaxDuCalcul < 0 ) return; + +time( &HeureDeCalendrierCourant ); + +TempsEcoule = difftime( HeureDeCalendrierCourant , Spx->HeureDeCalendrierDebut ); + +if ( TempsEcoule <= 0.0 ) TempsEcoule = 0.0; + +/* On provoque l'arret du calcul si temps depasse */ +if ( TempsEcoule > Spx->DureeMaxDuCalcul ) Spx->Iteration = 10 * Spx->NombreMaxDIterations; + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_get_tableau_row.c b/src/ext/Sirius_Solver/simplexe/spx_get_tableau_row.c new file mode 100644 index 0000000000..db6b91478c --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_get_tableau_row.c @@ -0,0 +1,212 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recuperation d'une ligne du tableau pour les 2 step MIR cuts + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_define.h" +# include "pne_fonctions.h" + +# include "lu_define.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void SPX_GetTableauRow( + PROBLEME_SPX * Spx, + int VariableFractionnaire, /* Numero de la variable pour laquelle on veut la ligne */ + double ValeurDuZero , /* Utilise pour detecter les coefficients nuls de la coupe */ + /* En retour, la ligne */ + int * NombreDeTermes , + double * Coefficient , + int * IndiceDeLaVariable , + double * SecondMembre, + char * CodeRet ) +{ +int VarSpx ; double NBarreR; double AlphaI0 ; int Cnt ; int il ; int ilMax; double NormeL1; +int VariableFractionnaireSpx; double Scale ; double S; double ScaleXFoisSupDesXmax; int NbTermes; +char * T; char * LaVariableSpxEstEntiere; int * VariableEnBaseDeLaContrainte; double * ErBMoinsUn; +int * Cdeb; double * ACol; int * CNbTerm; int * NumeroDeContrainte; char * OrigineDeLaVariable; +char * PositionDeLaVariable; double * ScaleX; double * NBarreRVecteur; double * XminEntree; +double * XmaxEntree; double * Xmax; double * Bs; +int * IndexTermesNonNulsDeErBMoinsUn; int *NumVarNBarreRNonNul; char ControlerAdmissibiliteDuale; +DONNEES_POUR_COUPES_DE_GOMORY * DonneesPourCoupesDeGomory; + +*CodeRet = OUI_SPX; + +ValeurDuZero = ZERO_TERMES_DU_TABLEAU_POUR_GOMORY; + +DonneesPourCoupesDeGomory = Spx->DonneesPourCoupesDeGomory; +LaVariableSpxEstEntiere = DonneesPourCoupesDeGomory->LaVariableSpxEstEntiere; + +/* Le numero fourni ne peut pas etre dans la numerotation interne au simplexe car l'appelant n'y a + pas acces */ +VariableFractionnaireSpx = Spx->CorrespondanceVarEntreeVarSimplexe[VariableFractionnaire]; + +Scale = Spx->ScaleX[VariableFractionnaireSpx]; +AlphaI0 = Spx->BBarre[Spx->ContrainteDeLaVariableEnBase[VariableFractionnaireSpx]] * Scale; + +/* Calcul de la ligne de B^{-1} qui correspond a la variable de base fractionnaire. On utilise pour cela + le module de l'algorithme dual */ +/* Il est preferable de ne pas faire le calcul des gomory en hyper creux. De toutes façons une gomory est + rarement hyper creuse. */ +Spx->CalculErBMoinsUnEnHyperCreux = NON_SPX; +Spx->CalculErBMoinsEnHyperCreuxPossible = NON_SPX; +Spx->CalculABarreSEnHyperCreux = NON_SPX; +Spx->CalculABarreSEnHyperCreuxPossible = NON_SPX; + +Spx->VariableSortante = VariableFractionnaireSpx; /* Info utilisee dans le calcul de la ligne de B^{-1} */ + +/* Attention, DualCalculerNBarreR calcule ErBmoins1 */ +SPX_DualCalculerNBarreR( Spx, NON_SPX, &ControlerAdmissibiliteDuale ); /* En sortie on recupere la ligne dans le vecteur Spx->NBarreR, les + emplacements utiles etant ceux qui correspondent aux variables hors base */ + +/* Verification */ + +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +ErBMoinsUn = Spx->ErBMoinsUn; + +ACol = Spx->ACol; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +/* Si le stockage de ErBMoinsUn est COMPACT_SPX on en fait un VECTEUR_SPX */ +if ( Spx->TypeDeStockageDeErBMoinsUn == COMPACT_SPX ) { + Bs = Spx->Bs; + memset( (char *) Bs, 0, Spx->NombreDeContraintes * sizeof( double ) ); + IndexTermesNonNulsDeErBMoinsUn = Spx->IndexTermesNonNulsDeErBMoinsUn; + for ( il = 0 ; il < Spx->NbTermesNonNulsDeErBMoinsUn ; il++ ) Bs[IndexTermesNonNulsDeErBMoinsUn[il]] = ErBMoinsUn[il]; + memcpy( (char *) ErBMoinsUn, (char *) Bs, Spx->NombreDeContraintes * sizeof( double ) ); + Spx->TypeDeStockageDeErBMoinsUn = VECTEUR_SPX; +} +else if ( Spx->TypeDeStockageDeErBMoinsUn != VECTEUR_SPX ) { + printf("Calcul des gomory, attention le mode de stockage de ErBMoinsUn est incorrect\n"); +} + +NormeL1 = 0.0; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + VarSpx = VariableEnBaseDeLaContrainte[Cnt]; + /* Verification */ + S = 0.; + if ( VarSpx == Spx->VariableSortante ) S = -1.; + il = Cdeb[VarSpx]; + ilMax = il + CNbTerm[VarSpx]; + while ( il < ilMax ) { + S+= ACol[il] * ErBMoinsUn[NumeroDeContrainte[il]]; + il++; + } + NormeL1+= fabs( S ); +} + +if ( NormeL1 > SEUIL_DE_VERIFICATION_DE_NBarreR_GOMORY ) { + *CodeRet = NON_SPX; + return; +} + +/* Constitution de la contrainte avant application des regles d'arrondi */ +/* On ne veut pas de variables artificielles dans les coupes. Comme elles valent 0 on peut s'en passer */ +OrigineDeLaVariable = Spx->OrigineDeLaVariable; +PositionDeLaVariable = Spx->PositionDeLaVariable; +ScaleX = Spx->ScaleX; +NBarreRVecteur = Spx->NBarreR; +XminEntree = Spx->XminEntree; +XmaxEntree = Spx->XmaxEntree; +Xmax = Spx->Xmax; + +/* Si le stockage de NBarreR est ADRESSAGE_INDIRECT_SPX on en fait un VECTEUR_SPX */ +T = (char *) IndiceDeLaVariable; +if ( Spx->TypeDeStockageDeNBarreR == ADRESSAGE_INDIRECT_SPX ) { + memset( (char *) T, 0, Spx->NombreDeVariables * sizeof( char ) ); + NumVarNBarreRNonNul = Spx->NumVarNBarreRNonNul; + for ( il = 0 ; il < Spx->NombreDeValeursNonNullesDeNBarreR ; il++ ) T[NumVarNBarreRNonNul[il]] = 1; + for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + if ( T[VarSpx] == 0 ) NBarreRVecteur[VarSpx] = 0.0; + } +} + +NbTermes = 0; + +for ( VarSpx = 0 ; VarSpx < Spx->NombreDeVariables ; VarSpx++ ) { + + if ( OrigineDeLaVariable[VarSpx] == BASIQUE_ARTIFICIELLE ) continue; + + /* Nettoyage des valeurs qui relevent plus du bruit numerique que des calculs */ + /* On nettoie les petites valeurs */ + if ( fabs( NBarreRVecteur[VarSpx] ) < ZERO_TERMES_DU_TABLEAU_POUR_GOMORY ) continue; + + if ( PositionDeLaVariable[VarSpx] != HORS_BASE_SUR_BORNE_INF && + PositionDeLaVariable[VarSpx] != HORS_BASE_SUR_BORNE_SUP ) { + /* On a une variable non bornee hors base => on ne fait rien */ + *CodeRet = NON_SPX; + return; + } + + /* Nettoyage des tres petites valeurs car le vecteur va passer dans les coupes d'intersection. + Si on conserve trop de termes, le calcul des coupes d'intersection sera long. */ + if ( fabs( NBarreRVecteur[VarSpx] ) < ValeurDuZero ) { + NBarreRVecteur[VarSpx] = 0.0; + continue; + } + + ScaleXFoisSupDesXmax = ScaleX[VarSpx]; + NBarreR = NBarreRVecteur[VarSpx] * Scale / ScaleXFoisSupDesXmax; + + if ( LaVariableSpxEstEntiere[VarSpx] == OUI_SPX ) { + /* La variable est entiere. Si elle a ete instanciee a 0, l'information HORS_BASE_SUR_BORNE_INF ou + HORS_BASE_SUR_BORNE_SUP ne joue pas. Si elle a ete instanciee a 1 alors c'est comme si elle + etait HORS_BASE_SUR_BORNE_SUP */ + if ( XminEntree[VarSpx] == XmaxEntree[VarSpx] && 0 ) { /* Car uniquement au noeud racine */ + /* C'est une variable instanciee */ + if ( XminEntree[VarSpx] != 0. ) { + AlphaI0-= NBarreR * Xmax[VarSpx] * ScaleXFoisSupDesXmax; + NBarreR = -NBarreR; + } + } + } + + /* On ne tient pas compte de HORS_BASE_SUR_BORNE_SUP car il va y avoir la substitution ensuite */ + if ( PositionDeLaVariable[VarSpx] == HORS_BASE_SUR_BORNE_SUP && 0 ) { + /* On fait le changement de variable X = Xmax - Xtilde => Xtilde est hors base et vaut 0 */ + AlphaI0-= NBarreR * Xmax[VarSpx] * ScaleXFoisSupDesXmax; + NBarreR = -NBarreR; + } + + IndiceDeLaVariable[NbTermes] = VarSpx; + Coefficient[NbTermes] = NBarreR; + NbTermes++; +} + +*SecondMembre = AlphaI0; +*NombreDeTermes = NbTermes; + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_heuristique_arrondis.c b/src/ext/Sirius_Solver/simplexe/spx_heuristique_arrondis.c new file mode 100644 index 0000000000..6038f653d2 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_heuristique_arrondis.c @@ -0,0 +1,208 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Pilote par la partie PNE. On fait un simplexe apres avoir + fait des arrondis en esperant trouver une solution entiere. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_define.h" + +# include "lu_fonctions.h" + +# define MARGE 1.e-9 + +/*----------------------------------------------------------------------------*/ + +void SPX_HeuristiqueArrondis( + PROBLEME_SPX * Spx , + int * YaUneSolution, + int NbVar_E , + double * X_E , + int * TypeVar_E , + int NbContr_E , + int * PositionDeLaVariable_E , + int * NbVarDeBaseComplementaires_E , + int * ComplementDeLaBase_E, + int NombreMaxDIterations, + int NombreDeVariablesFixees, + int * NumerosDesVariablesArrondies, + double * NouvelleBorneMin, + double * NouvelleBorneMax + ) +{ +int i; int VariablePneArrondie; int VariableSpx; /* int Cnt; */ int il; +int ilMax ; double XmaxSV; double XminVariableSpx; double XmaxVariableSpx; +double ScaleLigneDesCouts; +int * CorrespondanceVarEntreeVarSimplexe; int * ContrainteDeLaVariableEnBase; int * Cdeb; int * CNbTerm; +int * NumeroDeContrainte; double * XminEntree; double * Xmin; double * Xmax; double * ScaleX; double * X; +double * C; double * BBarre; double * B; double * ACol; + +XminEntree = Spx->XminEntree; +CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; + +Xmin = Spx->Xmin; +Xmax = Spx->Xmax; +ScaleX = Spx->ScaleX; +X = Spx->X; +C = Spx->C; +ScaleLigneDesCouts = Spx->ScaleLigneDesCouts; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +BBarre = Spx->BBarre; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +ACol = Spx->ACol; +NumeroDeContrainte = Spx->NumeroDeContrainte; +B = Spx->B; + +/* Le numero fourni ne peut pas etre dans la numerotation interne au simplexe car l'appelant n'y a + pas acces */ +for ( i = 0 ; i < NombreDeVariablesFixees ; i++ ) { + VariablePneArrondie = NumerosDesVariablesArrondies[i]; + VariableSpx = CorrespondanceVarEntreeVarSimplexe[VariablePneArrondie]; + if ( VariableSpx < 0 ) continue; + XminEntree[VariableSpx] = NouvelleBorneMin[i]; + + XmaxSV = Xmax[VariableSpx]; + XminVariableSpx = NouvelleBorneMin[i] / ScaleX[VariableSpx]; + XmaxVariableSpx = NouvelleBorneMax[i] / ScaleX[VariableSpx]; + + if ( XminVariableSpx > Xmin[VariableSpx] + MARGE ) { + /* On a demande a placer la variable sur la borne sup */ + Spx->PartieFixeDuCout += ( C[VariableSpx] * XmaxSV ) / ScaleLigneDesCouts; + /* Il faut tenir compte de la modification du second membre B qui decoulerait du fait que la variable + dont on fixe borne min = borne max se retrouve avec Xmin = Xmax */ + il = Cdeb[VariableSpx]; + ilMax = il + CNbTerm[VariableSpx]; + while ( il < ilMax ) { + B[NumeroDeContrainte[il]]-= ACol[il] * XmaxSV; + il++; + } + } + + /* On simule la translation des bornes */ + Xmin[VariableSpx] = 0.; + Xmax[VariableSpx] = 0.; + +} + +/* La base factorisee est la base courante et on s'arrete des qu'il faut factoriser + la base */ +Spx->SeuilDePivotDual = VALEUR_DE_PIVOT_ACCEPTABLE; +Spx->StrongBranchingEnCours = NON_SPX; +Spx->UtiliserLaLuUpdate = OUI_SPX; +Spx->FaireDuRaffinementIteratif = 0; +Spx->FlagStabiliteDeLaFactorisation = 0; +Spx->ProblemeDeStabiliteDeLaFactorisation = NON_SPX; + + +Spx->YaUneSolution = OUI_SPX; +/*SPX_InitialiserLeTableauDesVariablesHorsBase( Spx );*/ + +Spx->UtiliserLaLuUpdate = OUI_SPX; + +Spx->Iteration = 0; +Spx->NombreDeChangementsDeBase = 0; +Spx->NombreMaxDIterations = NOMBRE_MAX_DITERATIONS; +if ( Spx->NombreMaxDIterations <= ( 5 * Spx->NombreDeContraintes ) ) { + Spx->NombreMaxDIterations = 5 * Spx->NombreDeContraintes; +} +/* Prise en compte de la valeur fournie si elle est valide */ +if ( NombreMaxDIterations > 0 ) Spx->NombreMaxDIterations = NombreMaxDIterations; + +Spx->CycleDeRefactorisation = CYCLE_DE_REFACTORISATION_DUAL; + +SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); /* On n'est pas oblige de le faire a chaque fois */ + +/* Factoriser la premiere base */ +Spx->BaseInversibleDisponible = NON_SPX; +SPX_FactoriserLaBase( Spx ); + +if ( Spx->YaUneSolution != NON_SPX ) SPX_DualSimplexe( Spx ); + +if ( Spx->YaUneSolution == OUI_SPX ) { + + /* Recalcul systematique des variables duales car elle ne sont pas mise a jour a chaque iteration */ + /* Calcul de Pi = c_B * B^{-1} */ + SPX_CalculerPi( Spx ); + + /* On initialise les valeurs des variables en fonction de leur position */ + SPX_FixerXEnFonctionDeSaPosition( Spx ); + + /* Dans le cas d'un contexte de Branch And Bound ou de Branch And Cut on sauvegarde les donnees + qui seront necessaires pour faire du strong branching voire des coupes de Gomory. Si la base + ne vient pas d'ętre factorisée, on la factorise. */ + /*if ( Spx->Contexte != SIMPLEXE_SEUL ) SPX_SauvegardesBranchAndBoundAndCut( Spx );*/ + SPX_RecupererLaSolution( Spx , NbVar_E , X_E , TypeVar_E , NbContr_E , PositionDeLaVariable_E , + NbVarDeBaseComplementaires_E , ComplementDeLaBase_E ); + } + +*YaUneSolution = Spx->YaUneSolution; + +/* Attention dans RecupererLaSolution on a fait un unscaling. Il faut donc remettre les valeur de X car + elles sont reutilisees */ + +if ( Spx->FaireDuScalingSPX == OUI_SPX ) { + ScaleX = Spx->ScaleX; + for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) X[i] /= ScaleX[i]; +} + +return; + +} + +/*----------------------------------------------------------------------------*/ + +void SPX_RAZHeuristiqueArrondis( PROBLEME_SPX * Spx ) +{ +int il; +/* On remet les donnees internes du simplexe dans l'etat initial */ +il = Spx->NombreDeVariables * sizeof( double ); +memcpy( (char *) Spx->X, (char *) Spx->XSV, il ); +memcpy( (char *) Spx->CBarre, (char *) Spx->CBarreSV, il ); +memcpy( (char *) Spx->C, (char *) Spx->Csv, il ); +il = Spx->NombreDeVariables * sizeof( int ); +memcpy( (char *) Spx->ContrainteDeLaVariableEnBase, (char *) Spx->ContrainteDeLaVariableEnBaseSV, il ); +il = Spx->NombreDeVariables * sizeof( char ); +memcpy( (char *) Spx->PositionDeLaVariable, (char *) Spx->PositionDeLaVariableSV, il ); +memcpy( (char *) Spx->InDualFramework, (char *) Spx->InDualFrameworkSV, il ); + +il = Spx->NombreDeContraintes * sizeof( double ); +memcpy( (char *) Spx->BBarre, (char *) Spx->BBarreSV, il ); +memcpy( (char *) Spx->DualPoids, (char *) Spx->DualPoidsSV, il ); +il = Spx->NombreDeContraintes * sizeof( int ); +memcpy( (char *) Spx->VariableEnBaseDeLaContrainte, (char *) Spx->VariableEnBaseDeLaContrainteSV, il ); +memcpy( (char *) Spx->CdebBase, (char *) Spx->CdebBaseSV, il ); +memcpy( (char *) Spx->NbTermesDesColonnesDeLaBase, (char *) Spx->NbTermesDesColonnesDeLaBaseSV, il ); + +Spx->LastEta = -1; +Spx->NombreDeChangementsDeBase = 0; +Spx->Iteration = 0; + + + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_init_indicateurs_hypercreux.c b/src/ext/Sirius_Solver/simplexe/spx_init_indicateurs_hypercreux.c new file mode 100644 index 0000000000..a22dbe9347 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_init_indicateurs_hypercreux.c @@ -0,0 +1,48 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Initialisation des inticateurs hyper creux + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_InitialiserLesIndicateursHyperCreux( PROBLEME_SPX * Spx ) +{ + +Spx->CalculErBMoinsUnEnHyperCreux = OUI_SPX; +Spx->CalculErBMoinsEnHyperCreuxPossible = OUI_SPX; +Spx->CountEchecsErBMoins = 0; +Spx->AvertissementsEchecsErBMoins = 0; +Spx->NbEchecsErBMoins = 0; + +Spx->CalculABarreSEnHyperCreux = OUI_SPX; +Spx->CalculABarreSEnHyperCreuxPossible = OUI_SPX; +Spx->CountEchecsABarreS = 0; +Spx->AvertissementsEchecsABarreS = 0; +Spx->NbEchecsABarreS = 0; + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_instancier_variable_dans_simplexe.c b/src/ext/Sirius_Solver/simplexe/spx_instancier_variable_dans_simplexe.c new file mode 100644 index 0000000000..f7f126c12d --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_instancier_variable_dans_simplexe.c @@ -0,0 +1,96 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Selon le cas: + Modification des donnees du simplexe pour simuler une + instanciation. + Remise des donnees dans l'etat initial. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ +/* On modifie les donnees pour simuler une instanciation */ + +void Spx_ModifierLesDonneesSurInstanciation( PROBLEME_SPX * Spx, + int VariablePneAInstancier, + int SortSurXmaxOuSurXmin ) +{ +double XmaxSV; int il; int ilMax; int VariableSpxAInstancier; + +VariableSpxAInstancier = Spx->CorrespondanceVarEntreeVarSimplexe[VariablePneAInstancier]; + +if ( Spx->Xmax[VariableSpxAInstancier] == Spx->Xmin[VariableSpxAInstancier] || Spx->Xmin[VariableSpxAInstancier] != 0.0 ) { + printf("erreur instanciation de la variable spx %d alors que Xmin %e et Xmax %e\n", + VariableSpxAInstancier,Spx->Xmin[VariableSpxAInstancier],Spx->Xmax[VariableSpxAInstancier]); + exit(0); +} + +XmaxSV = Spx->Xmax[VariableSpxAInstancier]; +Spx->Xmax[VariableSpxAInstancier] = 0.0; + +if ( SortSurXmaxOuSurXmin == SORT_SUR_XMAX ) { + + Spx->PartieFixeDuCout+= (Spx->C[VariableSpxAInstancier] * XmaxSV ) / Spx->ScaleLigneDesCouts; + + il = Spx->Cdeb[VariableSpxAInstancier]; + ilMax = il + Spx->CNbTerm[VariableSpxAInstancier]; + while ( il < ilMax ) { + Spx->B[Spx->NumeroDeContrainte[il]]-= Spx->ACol[il] * XmaxSV; + il++; + } +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* On remet les donnees dans l'etat avant instanciation */ + +void Spx_RemettreLesDonneesAvantInstanciation( PROBLEME_SPX * Spx , int VariablePneARemettre , int SortaitSurXmaxOuSurXmin ) +{ +double Xmax; int il; int ilMax; int VariablesSpxARemettre; + +if ( SortaitSurXmaxOuSurXmin != SORT_SUR_XMIN && SortaitSurXmaxOuSurXmin != SORT_SUR_XMAX ) return; + +VariablesSpxARemettre = Spx->CorrespondanceVarEntreeVarSimplexe[VariablePneARemettre]; + +Spx->Xmax[VariablesSpxARemettre] = 1.0 / Spx->ScaleX[VariablesSpxARemettre]; +Xmax = Spx->Xmax[VariablesSpxARemettre]; + +if ( SortaitSurXmaxOuSurXmin == SORT_SUR_XMAX ) { + + Spx->PartieFixeDuCout-= (Spx->C[VariablesSpxARemettre] * Xmax) / Spx->ScaleLigneDesCouts; + + il = Spx->Cdeb[VariablesSpxARemettre]; + ilMax = il + Spx->CNbTerm[VariablesSpxARemettre]; + while ( il < ilMax ) { + Spx->B[Spx->NumeroDeContrainte[il]]+= Spx->ACol[il] * Xmax; + il++; + } +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_memoire.h b/src/ext/Sirius_Solver/simplexe/spx_memoire.h new file mode 100644 index 0000000000..fec34829cd --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_memoire.h @@ -0,0 +1,34 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# ifndef SPX_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# include "mem_fonctions.h" +/***************************************************************** + + + Macros pour redefinir les primitives de gestion memoire lorsqu'on + ne veut pas utiliser celles de lib de l'OS + + +*****************************************************************/ + +# define malloc(Taille) MEM_Malloc(Spx->Tas,Taille) +# define free(Pointeur) MEM_Free(Pointeur) +# define realloc(Pointeur,Taille) MEM_Realloc(Spx->Tas,Pointeur,Taille) + +/*****************************************************************/ +# define SPX_MACROS_POUR_FONCTION_EXTERNES_DE_GESTION_MEMOIRE +# endif diff --git a/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_b_barre.c b/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_b_barre.c new file mode 100644 index 0000000000..234df69884 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_b_barre.c @@ -0,0 +1,172 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Mise de BBarre = B^{-1} * b + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +/*----------------------------------------------------------------------------*/ +/* Cas de la mise a jour de BBarre */ + +void SPX_MettreAJourBBarre( PROBLEME_SPX * Spx ) +{ +int Index; int i; double * Bs; double * BBarre; double * ABarreS; int * CntDeABarreSNonNuls; +double DeltaXSurLaVariableHorsBase; int * T; int * IndexTermesNonNuls; int NbTermesNonNuls; +int IndexCntBase; int NbBBarreModifies; int * IndexDeBBarreModifies; char StockageDeBs; +int * ColonneDeLaBaseFactorisee; int IndexMax; + +/* Bs est toujours a 0 des qu'on a fini de s'en servir */ +/*memset( (char *) Bs , 0 , Spx->NombreDeContraintes * sizeof( double ) );*/ +/*for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) Bs[i] = 0.0;*/ +Bs = Spx->Bs; + +IndexTermesNonNuls = (int *) Spx->ErBMoinsUn; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + SPX_MettreAJourBBarreAvecBaseReduite( Spx, Bs, IndexTermesNonNuls, &NbTermesNonNuls, &StockageDeBs ); +} +else { + SPX_MettreAJourBBarreAvecBaseComplete( Spx, Bs, IndexTermesNonNuls, &NbTermesNonNuls, &StockageDeBs); +} + +T = Spx->T; +ABarreS = Spx->ABarreS; +BBarre = Spx->BBarre; +DeltaXSurLaVariableHorsBase = Spx->DeltaXSurLaVariableHorsBase; +NbBBarreModifies = 0; +IndexDeBBarreModifies = (int *) Spx->V; + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + ColonneDeLaBaseFactorisee = Spx->ColonneDeLaBaseFactorisee; + IndexMax = Spx->RangDeLaMatriceFactorisee; + IndexCntBase = Spx->OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]]; +} +else { + IndexMax = Spx->NombreDeContraintes; + IndexCntBase = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; +} + +if ( Spx->TypeDeStockageDeABarreS == COMPACT_SPX ) { + CntDeABarreSNonNuls = Spx->CntDeABarreSNonNuls; + for ( i = 0 ; i < Spx->NbABarreSNonNuls ; i++ ) { + Index = CntDeABarreSNonNuls[i]; + BBarre[Index]-= DeltaXSurLaVariableHorsBase * ABarreS[i]; + T[Index] = 1; + IndexDeBBarreModifies[NbBBarreModifies] = Index; + NbBBarreModifies++; + } + if ( StockageDeBs == COMPACT_SPX ) { + for ( i = 0 ; i < NbTermesNonNuls ; i++ ) { + Index = IndexTermesNonNuls[i]; + BBarre[Index] -= Bs[i]; + Bs[i] = 0; + if ( T[Index] == -1 ) { + T[Index] = 1; + IndexDeBBarreModifies[NbBBarreModifies] = Index; + NbBBarreModifies++; + } + } + } + else { + for ( Index = 0 ; Index < IndexMax ; Index++ ) { + if ( Bs[Index] != 0.0 ) { + BBarre[Index] -= Bs[Index]; + Bs[Index] = 0; + if ( T[Index] == -1 ) { + T[Index] = 1; + IndexDeBBarreModifies[NbBBarreModifies] = Index; + NbBBarreModifies++; + } + } + } + } +} +else { + /* ABarreS est sous forme vecteur */ + if ( StockageDeBs == COMPACT_SPX ) { + for ( Index = 0 ; Index < IndexMax ; Index++ ) { + if ( ABarreS[Index] != 0.0 ) { + BBarre[Index] -= DeltaXSurLaVariableHorsBase * ABarreS[Index]; + T[Index] = 1; + IndexDeBBarreModifies[NbBBarreModifies] = Index; + NbBBarreModifies++; + } + } + for ( i = 0 ; i < NbTermesNonNuls ; i++ ) { + Index = IndexTermesNonNuls[i]; + BBarre[Index]-= Bs[i]; + Bs[i] = 0; + if ( T[Index] == -1 ) { + T[Index] = 1; + IndexDeBBarreModifies[NbBBarreModifies] = Index; + NbBBarreModifies++; + } + } + } + else { + for ( Index = 0 ; Index < IndexMax ; Index++ ) { + if ( Bs[Index] != 0.0 || ABarreS[Index] != 0.0 ) { + BBarre[Index]-= Bs[Index] + ( DeltaXSurLaVariableHorsBase * ABarreS[Index] ); + Bs[Index] = 0; + T[Index] = 1; + IndexDeBBarreModifies[NbBBarreModifies] = Index; + NbBBarreModifies++; + } + } + } +} + +/* Cas particulier des variables echangees */ +if ( Spx->ChangementDeBase == OUI_SPX ) { + if ( Spx->PositionDeLaVariable[Spx->VariableEntrante] == HORS_BASE_SUR_BORNE_INF || + Spx->PositionDeLaVariable[Spx->VariableEntrante] == HORS_BASE_A_ZERO ) { + BBarre[IndexCntBase] = DeltaXSurLaVariableHorsBase; + if ( T[IndexCntBase] == -1 ) { + T[IndexCntBase] = 1; + IndexDeBBarreModifies[NbBBarreModifies] = IndexCntBase; + NbBBarreModifies++; + } + } + else { + BBarre[IndexCntBase] = DeltaXSurLaVariableHorsBase + Spx->Xmax[Spx->VariableEntrante]; + if ( T[IndexCntBase] == -1 ) { + T[IndexCntBase] = 1; + IndexDeBBarreModifies[NbBBarreModifies] = IndexCntBase; + NbBBarreModifies++; + } + } +} + +Spx->BBarreAEteCalculeParMiseAJour = OUI_SPX; + +SPX_MajDesVariablesEnBaseAControler( Spx, NbBBarreModifies, IndexDeBBarreModifies, T ); + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_b_barre_avec_base_complete.c b/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_b_barre_avec_base_complete.c new file mode 100644 index 0000000000..9565fb35cf --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_b_barre_avec_base_complete.c @@ -0,0 +1,190 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Mise a jour de BBarre = B^{-1} * b + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +void SPX_CalculerBsHyperCreuxAvecBaseComplete( PROBLEME_SPX * , char * , int * , int * ); +void SPX_CalculerBsStandardAvecBaseComplete( PROBLEME_SPX * , char * ); + +/*----------------------------------------------------------------------------*/ +/* On tente un calcul en hyper creux s'il y a des chances de succes */ +void SPX_CalculerBsHyperCreuxAvecBaseComplete( PROBLEME_SPX * Spx, char * ResoudreLeSysteme, + int * IndexTermesNonNuls, int * NbTNonNuls ) +{ +int il; int ilMax; int i; int Var; double Xmx; char Flag; double * Bs; int * T; +int * BoundFlip; double * Xmax; int * NumeroDeContrainte; double * ACol; int * Cdeb; +int * CNbTerm; int NbTermesNonNuls; int k; + +T = Spx->T; +NbTermesNonNuls = 0; +Bs = Spx->Bs; +BoundFlip = Spx->BoundFlip; +Xmax = Spx->Xmax; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; +ACol = Spx->ACol; + +Flag = NON_SPX; +for ( i = 0 ; i < Spx->NbBoundFlip; i++ ) { + Var = BoundFlip[i]; + if ( BoundFlip[i] > 0 ) { + Var = BoundFlip[i] - 1; + Xmx = Xmax[Var]; + } + else { + Var = -BoundFlip[i] - 1; + Xmx = -Xmax[Var]; + } + if ( Xmx == 0.0 ) continue; + Flag = OUI_SPX; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + k = NumeroDeContrainte[il]; + if ( T[k] == -1 ) { + T[k] = 1; + IndexTermesNonNuls[NbTermesNonNuls] = k; + NbTermesNonNuls++; + } + Bs[k]+= Xmx * ACol[il]; + il++; + } +} + +/* RAZ de T */ +for ( i = 0 ; i < NbTermesNonNuls ; i++ ) T[IndexTermesNonNuls[i]] = -1; + +*ResoudreLeSysteme = Flag; +*NbTNonNuls = NbTermesNonNuls; +return; +} + +/*----------------------------------------------------------------------------*/ +void SPX_CalculerBsStandardAvecBaseComplete( PROBLEME_SPX * Spx, char * ResoudreLeSysteme ) +{ + +int il; int ilMax; int i; int Var; double Xmx; char Flag; double * Bs; +int * BoundFlip; double * Xmax; int * NumeroDeContrainte; +double * ACol; int * Cdeb; int * CNbTerm; + +Bs = Spx->Bs; +BoundFlip = Spx->BoundFlip; +Xmax = Spx->Xmax; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; +ACol = Spx->ACol; + +Flag = NON_SPX; +for ( i = 0 ; i < Spx->NbBoundFlip; i++ ) { + Var = BoundFlip[i]; + if ( BoundFlip[i] > 0 ) { + Var = BoundFlip[i] - 1; + Xmx = Xmax[Var]; + } + else { + Var = -BoundFlip[i] - 1; + Xmx = -Xmax[Var]; + } + if ( Xmx == 0.0 ) continue; + Flag = OUI_SPX; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + Bs[NumeroDeContrainte[il]]+= Xmx * ACol[il]; + il++; + } +} + +*ResoudreLeSysteme = Flag; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Cas de la mise a jour de BBarre */ + +void SPX_MettreAJourBBarreAvecBaseComplete( PROBLEME_SPX * Spx, double * Bs, int * IndexTermesNonNuls, + int * NbTermesNonNuls, char * StockageDeBs ) +{ +char Save; char SecondMembreCreux; char ResoudreLeSysteme; char TypeDEntree; char TypeDeSortie; +char ResolutionEnHyperCreux; + +if ( Spx->CalculABarreSEnHyperCreux == OUI_SPX ) ResolutionEnHyperCreux = OUI_SPX; +else ResolutionEnHyperCreux = NON_SPX; + +if ( Spx->TypeDeCreuxDeLaBase == BASE_HYPER_CREUSE && ResolutionEnHyperCreux == OUI_SPX ) { + SPX_CalculerBsHyperCreuxAvecBaseComplete( Spx, &ResoudreLeSysteme, IndexTermesNonNuls, NbTermesNonNuls ); + TypeDEntree = ADRESSAGE_INDIRECT_LU; + TypeDeSortie = COMPACT_LU; + *StockageDeBs = COMPACT_SPX; +} +else { + ResolutionEnHyperCreux = NON_SPX; + SPX_CalculerBsStandardAvecBaseComplete( Spx, &ResoudreLeSysteme ); + *StockageDeBs = VECTEUR_SPX; + TypeDEntree = VECTEUR_LU; + TypeDeSortie = VECTEUR_LU; +} + +/* Je pense qu'il y a un bug dans le type de stockage de StockageDeBs qu'on recupere + car TypeDeSortie demande est soit VECTEUR soit COMPACT */ + +if ( ResoudreLeSysteme == OUI_SPX ) { + Save = NON_LU; + SecondMembreCreux = OUI_LU; + + if ( ResolutionEnHyperCreux == OUI_SPX ) { + if ( *NbTermesNonNuls >= ceil( TAUX_DE_REMPLISSAGE_POUR_VECTEUR_HYPER_CREUX * Spx->NombreDeContraintes ) ) { + ResolutionEnHyperCreux = NON_SPX; + *StockageDeBs = VECTEUR_SPX; + TypeDEntree = VECTEUR_LU; + TypeDeSortie = VECTEUR_LU; + } + } + + SPX_ResoudreBYegalA( Spx, TypeDEntree, Bs, IndexTermesNonNuls, NbTermesNonNuls, &TypeDeSortie, + ResolutionEnHyperCreux, Save, SecondMembreCreux ); + + if ( ResolutionEnHyperCreux == OUI_SPX ) { + if ( TypeDeSortie != COMPACT_LU ) { + *StockageDeBs = VECTEUR_SPX; + } + } + +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_b_barre_avec_base_reduite.c b/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_b_barre_avec_base_reduite.c new file mode 100644 index 0000000000..f003dab281 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_b_barre_avec_base_reduite.c @@ -0,0 +1,272 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Mise de BBarre = B^{-1} * b + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +# define DEBUG NON_SPX + +void SPX_CalculSecondMembrePourABarreSAvecBaseReduite( PROBLEME_SPX * , char * , int * , int * ); + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculSecondMembrePourABarreSAvecBaseReduite( PROBLEME_SPX * Spx, char * ResoudreLeSysteme, + int * IndexTermesNonNuls, int * NbTNonNuls ) +{ +int il; int ilMax; int i; int Var; double Xmx; char Flag; int * BoundFlip; double * Xmax; +int * IndicesDeLigneDesTermesDuProblemeReduit; double * ValeurDesTermesDesColonnesDuProblemeReduit; +int * CdebProblemeReduit; int * CNbTermProblemeReduit; int RangDeLaMatriceFactorisee; +int r; int * T; double * Bs; int NbTermesNonNuls; + +BoundFlip = Spx->BoundFlip; +Xmax = Spx->Xmax; +Bs = Spx->Bs; + +CdebProblemeReduit = Spx->CdebProblemeReduit; +CNbTermProblemeReduit = Spx->CNbTermProblemeReduit; +IndicesDeLigneDesTermesDuProblemeReduit = Spx->IndicesDeLigneDesTermesDuProblemeReduit; +ValeurDesTermesDesColonnesDuProblemeReduit = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; + +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; + +T = Spx->T; /* Toujours a -1 quand on a fini de s'en servir */ + +NbTermesNonNuls = 0; + +Flag = NON_SPX; + +for ( i = 0 ; i < Spx->NbBoundFlip; i++ ) { + Var = BoundFlip[i]; + if ( BoundFlip[i] > 0 ) { + Var = BoundFlip[i] - 1; + Xmx = Xmax[Var]; + } + else { + Var = -BoundFlip[i] - 1; + Xmx = -Xmax[Var]; + } + if ( Xmx == 0.0 ) continue; + il = CdebProblemeReduit[Var]; + ilMax = il + CNbTermProblemeReduit[Var]; + while ( il < ilMax ) { + r = IndicesDeLigneDesTermesDuProblemeReduit[il]; + if ( T[r] == -1 ) { + Flag = OUI_SPX; + T[r] = 1; + IndexTermesNonNuls[NbTermesNonNuls] = r; + NbTermesNonNuls++; + } + Bs[r] += Xmx * ValeurDesTermesDesColonnesDuProblemeReduit[il]; + il++; + } +} + +/* Raz de T */ +for ( i = 0 ; i < NbTermesNonNuls ; i++ ) T[IndexTermesNonNuls[i]] = -1; + +/* On a interet a compacter AReduit et peut etre meme aussi pour la partie hors base reduite */ + +for ( i = 0 ; i < NbTermesNonNuls ; i++ ) { + if ( Bs[IndexTermesNonNuls[i]] == 0 ) { + IndexTermesNonNuls[i] = IndexTermesNonNuls[NbTermesNonNuls-1]; + i--; + NbTermesNonNuls--; + } +} + +*ResoudreLeSysteme = Flag; +*NbTNonNuls = NbTermesNonNuls; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Cas de la mise a jour de BBarre */ + +void SPX_MettreAJourBBarreAvecBaseReduite( PROBLEME_SPX * Spx, double * Bs, int * IndexTermesNonNuls, + int * NbTermesNonNuls, char * StockageDeBs ) +{ +char Save; char SecondMembreCreux; char ResoudreLeSysteme; char TypeDEntree; char TypeDeSortie; +char ResolutionEnHyperCreux; + +if ( Spx->CalculABarreSEnHyperCreux == OUI_SPX ) ResolutionEnHyperCreux = OUI_SPX; +else ResolutionEnHyperCreux = NON_SPX; + +SPX_CalculSecondMembrePourABarreSAvecBaseReduite( Spx, &ResoudreLeSysteme, IndexTermesNonNuls, NbTermesNonNuls ); + +if ( Spx->TypeDeCreuxDeLaBase == BASE_HYPER_CREUSE && ResolutionEnHyperCreux == OUI_SPX ) { + TypeDEntree = ADRESSAGE_INDIRECT_LU; + TypeDeSortie = COMPACT_LU; + *StockageDeBs = COMPACT_SPX; +} +else { + *StockageDeBs = VECTEUR_SPX; + ResolutionEnHyperCreux = NON_SPX; + TypeDEntree = VECTEUR_LU; + TypeDeSortie = VECTEUR_LU; +} + +if ( ResoudreLeSysteme == OUI_SPX ) { + Save = NON_LU; + SecondMembreCreux = OUI_LU; + + if ( ResolutionEnHyperCreux == OUI_SPX ) { + if ( *NbTermesNonNuls >= ceil( TAUX_DE_REMPLISSAGE_POUR_VECTEUR_HYPER_CREUX * Spx->RangDeLaMatriceFactorisee ) ) { + ResolutionEnHyperCreux = NON_SPX; + *StockageDeBs = VECTEUR_SPX; + TypeDEntree = VECTEUR_LU; + TypeDeSortie = VECTEUR_LU; + } + } + + /* TypeDEntree est egal soit a ADRESSAGE_INDIRECT_SPX soit a COMPACT_LU */ + /* TypeDeSortie (demande) est egal a COMPACT_LU */ + + SPX_ResolutionDeSysteme( Spx, TypeDEntree, Bs, IndexTermesNonNuls, NbTermesNonNuls, + &TypeDeSortie, ResolutionEnHyperCreux, Save, SecondMembreCreux ); + + if ( ResolutionEnHyperCreux == OUI_SPX ) { + if ( TypeDeSortie != COMPACT_LU ) { + *StockageDeBs = VECTEUR_SPX; + } + } + +} +else { + *NbTermesNonNuls = 0; /* Pour le cas ou on ne resout pas le systeme */ +} + +return; + +/* A completer par la forme produit de l'inverse si necessaire */ + + +# if VERIFICATION_MAJ_BBARRE == OUI_SPX +printf("------------- MettreAJourBBarreAvecBaseReduite Spx->NombreDeChangementsDeBase %d Iteration %d ---\n",Spx->NombreDeChangementsDeBase,Spx->Iteration); +if ( TypeDEntree == VECTEUR_LU ) printf("TypeDEntree = VECTEUR_LU\n"); +if ( TypeDEntree == COMPACT_LU ) printf("TypeDEntree = COMPACT_LU\n"); +if ( TypeDEntree == ADRESSAGE_INDIRECT_LU ) printf("TypeDEntree = ADRESSAGE_INDIRECT_LU\n"); +if ( TypeDeSortie == VECTEUR_LU ) printf("TypeDeSortie = VECTEUR_LU\n"); +if ( TypeDeSortie == COMPACT_LU ) printf("TypeDeSortie = COMPACT_LU\n"); +if ( TypeDeSortie == ADRESSAGE_INDIRECT_LU ) printf("TypeDeSortie = ADRESSAGE_INDIRECT_LU\n"); +if ( *StockageDeBs == VECTEUR_LU ) printf("StockageDeBs = VECTEUR_LU\n"); +if ( *StockageDeBs == COMPACT_LU ) printf("StockageDeBs = COMPACT_LU\n"); +if ( *StockageDeBs == ADRESSAGE_INDIRECT_LU ) printf("StockageDeBs = ADRESSAGE_INDIRECT_LU\n"); + +{ +double * Buff; int i; int Var; int ic; int icMx; double * Sortie; char Arret; double Xmx; +Buff = (double *) malloc( Spx->NombreDeContraintes * sizeof( double ) ); +Sortie = (double *) malloc( Spx->NombreDeContraintes * sizeof( double ) ); +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) Sortie[i] = 0; +if ( *StockageDeBs == COMPACT_LU ) { + for ( i = 0 ; i < *NbTermesNonNuls ; i++ ) Sortie[IndexTermesNonNuls[i]] = Bs[i]; +} +else if ( *StockageDeBs == ADRESSAGE_INDIRECT_LU ) { /* EN realite c'est a prendre comme une forme compacte */ + for ( i = 0 ; i < *NbTermesNonNuls ; i++ ) { + Sortie[IndexTermesNonNuls[i]] = Bs[i]; + } +} +else if ( *StockageDeBs == VECTEUR_LU ) { + for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) Sortie[i] = Bs[i]; +} +else { + printf("BUG StockageDeBs incorrect \n"); + exit(0); +} + +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) Buff[i] = 0; +for ( i = 0 ; i < Spx->NbBoundFlip; i++ ) { + Var = Spx->BoundFlip[i]; + if ( Spx->BoundFlip[i] > 0 ) { + Var = Spx->BoundFlip[i] - 1; + Xmx = Xmax[Var]; + } + else { + Var = -Spx->BoundFlip[i] - 1; + Xmx = -Xmax[Var]; + } + if ( Xmx == 0.0 ) continue; + il = Spx->Cdeb[Var]; + ilMax = il + Spx->CNbTerm[Var]; + while ( il < ilMax ) { + Buff[Spx->NumeroDeContrainte[il]] += Xmx * Spx->ACol[il]; + il++; + } +} + +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + Var = Spx->VariableEnBaseDeLaContrainte[i]; + ic = Spx->Cdeb[Var]; + icMx = ic + Spx->CNbTerm[Var]; + while ( ic < icMx ) { + Buff[NumeroDeContrainte[ic]] -= ACol[ic] * Sortie[i]; + ic++; + } +} + +Arret = NON_SPX; +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + if ( fabs( Buff[Cnt] ) > 1.e-7 ) { + printf("Cnt = %d ecart %e\n",Cnt,Buff[Cnt]); + + il = Spx->Mdeb[Cnt]; + ilMax = il + Spx->NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Spx->Indcol[il]; + if ( Spx->PositionDeLaVariable[Var] == EN_BASE_LIBRE ) { + printf("A %e Colonne %d valeur %e\n",Spx->A[il],Spx->ContrainteDeLaVariableEnBase[Var],Bs[Spx->ContrainteDeLaVariableEnBase[Var]]); + } + il++; + } + printf("\n"); + + Arret = OUI_SPX; + } +} + +free( Buff ); +free( Sortie ); + +SPX_VerifierLesVecteursDeTravail( Spx ); +printf("Verif des vecteurs auxiliaires OK\n"); + +if ( Arret == OUI_SPX ) { + printf("RangDeLaMatriceFactorisee %d NombreDeContraintes %d\n",Spx->RangDeLaMatriceFactorisee,Spx->NombreDeContraintes); + exit(0); +} +printf("Fin verif MettreAJourBBarreAvecBaseReduite OK\n"); + +} + +# endif + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_la_base.c b/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_la_base.c new file mode 100644 index 0000000000..9b209f59c6 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_mettre_a_jour_la_base.c @@ -0,0 +1,122 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Mise a jour de la forme produit de l'inverse + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_MettreAJourLaBase( PROBLEME_SPX * Spx , int * SuccesUpdate ) +{ +int Cnt; int CntBase; double S; int * EtaDeb; int * EtaColonne; int * EtaNbTerm; +double * ABarreS; double * EtaMoins1Valeur; int * EtaIndiceLigne; int LastEta; +int * CntDeABarreSNonNuls; int i; int NombreDeChangementsDeBase; int Colonne; + +if ( Spx->UtiliserLaLuUpdate == OUI_SPX ) { + /* On donne: + - le numero de la colonne qui correspond a la variable sortante + - un pointeur sur la colonne A de la variable entrante + - la colonne A + */ + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + Colonne = Spx->OrdreColonneDeLaBaseFactorisee[Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]]; + } + else { + Colonne = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; + } + LU_UpdateLuSpikePret( + Spx->MatriceFactorisee, + Colonne, + SuccesUpdate + ); + Spx->NombreDeChangementsDeBase++; + return; +} + +/* Division par 0: c'est pas possible car sinon c'est pas un pivot */ +CntBase = Spx->ContrainteDeLaVariableEnBase[Spx->VariableSortante]; +ABarreS = Spx->ABarreS; +EtaDeb = Spx->EtaDeb; +EtaColonne = Spx->EtaColonne; +EtaNbTerm = Spx->EtaNbTerm; +EtaMoins1Valeur = Spx->EtaMoins1Valeur; +EtaIndiceLigne = Spx->EtaIndiceLigne; +LastEta = Spx->LastEta; +NombreDeChangementsDeBase = Spx->NombreDeChangementsDeBase; + +S = -1. / Spx->ABarreSCntBase; + +EtaDeb [ NombreDeChangementsDeBase ] = LastEta + 1; +EtaColonne[ NombreDeChangementsDeBase ] = CntBase; +EtaNbTerm [ NombreDeChangementsDeBase ] = 0; + +if ( Spx->TypeDeStockageDeABarreS == VECTEUR_SPX ) { + for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + if ( ABarreS[Cnt] == 0.0 ) { + /* Ne peut pas arriver si Cnt = CntBase */ + continue; + } + EtaNbTerm[ NombreDeChangementsDeBase ]++; + LastEta++; + EtaIndiceLigne[ LastEta ] = Cnt; + if ( Cnt == CntBase ) EtaMoins1Valeur[LastEta] = -S; + else EtaMoins1Valeur[LastEta] = ABarreS[Cnt] * S; + } +} +else { + CntDeABarreSNonNuls = Spx->CntDeABarreSNonNuls; + for ( i = 0 ; i < Spx->NbABarreSNonNuls ; i++ ) { + if ( ABarreS[i] != 0 ) { + /* Rq: si Cnt == CntBase ABarreS[i] est different de 0 */ + + Cnt = CntDeABarreSNonNuls[i]; + EtaNbTerm[ NombreDeChangementsDeBase ]++; + LastEta++; + EtaIndiceLigne[ LastEta ] = Cnt; + if ( Cnt == CntBase ) EtaMoins1Valeur[LastEta] = -S; + else EtaMoins1Valeur[LastEta] = ABarreS[i] * S; + + } + } +} + +Spx->LastEta = LastEta; +Spx->NombreDeChangementsDeBase++; + +/* Si trop de termes en moyenne on refactorise */ +if ( Spx->LastEta > Spx->RemplissageMaxDeLaFPI ) { + /* + printf("Detection d exigence de factorisation dans SPX_MettreAJourLaBase a l iteration %d\n",Spx->Iteration); + */ + Spx->FactoriserLaBase = OUI_SPX; +} + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_modifier_chainage_transposee.c b/src/ext/Sirius_Solver/simplexe/spx_modifier_chainage_transposee.c new file mode 100644 index 0000000000..4ca1866059 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_modifier_chainage_transposee.c @@ -0,0 +1,137 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul du chainage de la transposee de la matrice des + contraintes + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +/*----------------------------------------------------------------------------*/ + +void SPX_ModifierLeChainageDeLaTransposee( PROBLEME_SPX * Spx ) +{ +int il; int ilMax; int Var; int j; + +int * Cdeb; int * CNbTermSansCoupes; +double * ACol; int * NumeroDeContrainte; int * CNbTermesDeCoupes; + +int * Mdeb; double * A; int * NbTerm; int * Indcol; int ic1; int ic2; +int ic1Max; int NbT; int Cnt; + +int NombreDeVariablesDuProblemeSansCoupes; +int * CdebNew; int * CNbTermNew; double * AColNew; int * NumeroDeContrainteNew; + +CdebNew = (int *) malloc( Spx->NombreDeVariablesAllouees * sizeof( int ) ); +CNbTermNew = (int *) malloc( Spx->NombreDeVariablesAllouees * sizeof( int ) ); +AColNew = (double *) malloc( Spx->NbTermesAlloues * sizeof( double ) ); +NumeroDeContrainteNew = (int *) malloc( Spx->NbTermesAlloues * sizeof( int ) ); +if ( CdebNew == NULL || CNbTermNew == NULL || AColNew == NULL || NumeroDeContrainteNew == NULL ) { + printf(" Simplexe: memoire insuffisante dans SPX_ModifierLeChainageDeLaTransposee\n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); +} + +NombreDeVariablesDuProblemeSansCoupes = Spx->NombreDeVariablesDuProblemeSansCoupes; + +CNbTermSansCoupes = Spx->CNbTermSansCoupes; +CNbTermesDeCoupes = Spx->CNbTermesDeCoupes; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; +Cdeb = Spx->Cdeb; +ACol = Spx->ACol; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +ic2 = 0; +for ( Var = 0 ; Var < NombreDeVariablesDuProblemeSansCoupes; Var++ ) { + /* On Copie la colonne */ + ic1 = Cdeb[Var]; + NbT = CNbTermSansCoupes[Var]; + ic1Max = ic1 + NbT; + CdebNew [Var] = ic2; + CNbTermNew[Var] = NbT; + /* + while ( ic1 < ic1Max ) { + AColNew [ic2] = ACol[ic1]; + NumeroDeContrainteNew[ic2] = NumeroDeContrainte[ic1]; + ic1++; + ic2++; + } + */ + j = ic1Max-ic1; + memcpy( (char *) &AColNew[ic2], (char *) &ACol[ic1], j * sizeof( double ) ); + memcpy( (char *) &NumeroDeContrainteNew[ic2], (char *) &NumeroDeContrainte[ic1], j * sizeof( int ) ); + ic2 += j; + /* On laisse de la place pour les termes des coupes */ + ic2 += CNbTermesDeCoupes[Var]; +} + +/* Les autres variables n'ont que des 1 car ce sont des variables d'ecart de coupes */ +for ( ; Var < Spx->NombreDeVariables; Var++ ) { + CdebNew [Var] = ic2; + CNbTermNew[Var] = 1; + ic2++; +} + +/* On balaie les coupes */ +for ( Cnt = Spx->NombreDeContraintesDuProblemeSansCoupes ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( Var < NombreDeVariablesDuProblemeSansCoupes ) { + ic2 = CdebNew[Var] + CNbTermNew[Var]; + AColNew[ic2] = A[il]; + CNbTermNew[Var]++; + } + else { + /* Variable d'ecart de coupe */ + ic2 = CdebNew[Var]; + AColNew[ic2] = 1.; + } + /*AColNew[ic2] = A[il];*/ + NumeroDeContrainteNew[ic2] = Cnt; + il++; + } +} + +free( Spx->Cdeb ); +free( Spx->CNbTerm ); +free( Spx->ACol ); +free( Spx->NumeroDeContrainte ); + +Spx->Cdeb = CdebNew; +Spx->CNbTerm = CNbTermNew; +Spx->ACol = AColNew; +Spx->NumeroDeContrainte = NumeroDeContrainteNew; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_modifier_couts_ou_second_membre.c b/src/ext/Sirius_Solver/simplexe/spx_modifier_couts_ou_second_membre.c new file mode 100644 index 0000000000..a32731f1bb --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_modifier_couts_ou_second_membre.c @@ -0,0 +1,86 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + FONCTION: Modification du probleme. On permet de changer le vecteur + des couts ou bien celui du second membre. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_ModifierLeVecteurCouts( PROBLEME_SPX * Spx , double * C_E , int NbVar_E ) +{ +int Var_E ; int Var; double Cout; int * NumeroDesVariablesACoutNonNul; int il; +double * C; double * Csv; double * ScaleX; double ScaleLigneDesCouts; +int NombreDeVariablesDuProblemeSansCoupes; int * CorrespondanceVarEntreeVarSimplexe; + +CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; +NombreDeVariablesDuProblemeSansCoupes = Spx->NombreDeVariablesDuProblemeSansCoupes; +C = Spx->C ; +Csv = Spx->Csv; +ScaleX = Spx->ScaleX; +ScaleLigneDesCouts = Spx->ScaleLigneDesCouts; +for ( Var_E = 0 ; Var_E < NbVar_E ; Var_E++ ) { + Var = CorrespondanceVarEntreeVarSimplexe[Var_E]; + if ( Var < 0 || Var >= NombreDeVariablesDuProblemeSansCoupes ) continue; + Cout = C_E[Var_E] * ScaleX[Var] * ScaleLigneDesCouts; + Csv[Var] = Cout; + C [Var] = Cout; +} + +il = 0; +NumeroDesVariablesACoutNonNul = Spx->NumeroDesVariablesACoutNonNul; +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( C[Var] != 0 ) { + NumeroDesVariablesACoutNonNul[il] = Var; + il++; + } +} +Spx->NombreDeVariablesACoutNonNul = il; + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Modification du second membre apres scaling mais avant translation */ +/* Attention, cela suppose qu'il n'y ait pas de variables de type VARIABLE_FIXE + dans le probleme d'entree car seul est conserve BAvantTranslationEtApresScaling */ +void SPX_ModifierLeVecteurSecondMembre( PROBLEME_SPX * Spx , double * B_E , char * Sens_E, int NbCnt_E ) +{ +int Cnt_E; int Cnt; double Coeff; + +/* Attention, ne marche pas s'il y a des variables fixes: il faut que les variables fixes soient du + exprimees de la facon suivante : xmin = xmax */ + +for ( Cnt_E = 0 ; Cnt_E < NbCnt_E ; Cnt_E++ ) { + Cnt = Spx->CorrespondanceCntEntreeCntSimplexe[Cnt_E]; + if ( Cnt < 0 || Cnt >= Spx->NombreDeContraintesDuProblemeSansCoupes ) continue; + /* Spx->B[Cnt] est mis a jour plus tard en fonction du vecteur ci-dessous */ + Coeff = 1.; + if ( Sens_E[Cnt_E] == '>' ) Coeff = -1.0; + Spx->BAvantTranslationEtApresScaling[Cnt] = Coeff * B_E[Cnt_E] * Spx->ScaleB[Cnt]; +} + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_modifier_probleme.c b/src/ext/Sirius_Solver/simplexe/spx_modifier_probleme.c new file mode 100644 index 0000000000..c4fbb0d860 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_modifier_probleme.c @@ -0,0 +1,317 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + FONCTION: Modification du probleme dans un contexte de branch and + bound. En effet, d'un probleme a un autre, la seule + difference consiste en un changement de borne pour la + variable instanciee. En consequence il n'est pas necessaire + de reconstruire l'ensemble du probleme (scaling et autres + chainages de la matrice des contraintes). + Les donnees qui changent sont: + * Les bornes des variables entieres. + * La base (ici la base de depart est toujours fournie). + Attention, les types de variables (fixe ou pas) ne doivent + pas changer, les couts non plus. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_ModifierLeProbleme( + PROBLEME_SPX * Spx, + double * C_E, /* Couts lineaires */ + double * X_E, /* Inconnues */ + double * Xmin_E, /* Borne inf des variables */ + double * Xmax_E, /* Borne sup des variables */ + int NbVar_E, /* Nombre de variables */ + int * TypeVar_E, /* Indicateur du type de variable, il ne doit prendre que les + suivantes (voir le fichier spx_define.h mais ne jamais utiliser + les valeurs explicites des constantes): + VARIABLE_FIXE , + VARIABLE_BORNEE_DES_DEUX_COTES , + VARIABLE_BORNEE_INFERIEUREMENT , + VARIABLE_BORNEE_SUPERIEUREMENT , + VARIABLE_NON_BORNEE + */ + /* Pilotage de l'algorithme dual */ + double CoutMax, + int UtiliserCoutMax + ) +{ +int il ; int ilMax; int Var_E ; int Var; int Cnt ; double Marge; double S; +double UnSurScaleXFoisUnSurSupXmax; int * CorrespondanceVarEntreeVarSimplexe; + +char * TypeDeVariable; double * X; double * Xmin; double * Xmax ; double * C ; +double * XminEntree ; double * XmaxEntree ; double * XEntree; double * B ; +double * BAvantTranslationEtApresScaling ; double * A ; int * Mdeb ; +int * NbTerm ; int * Indcol ; double * ScaleX ; double * Csv; +double PartieFixeDuCout; + +/* +printf("SPX_ModifierLeProbleme \n"); fflush(stdout); +*/ + +Spx->NombreDeVariables = Spx->NombreDeVariablesDuProblemeSansCoupes; +Spx->NombreDeContraintes = Spx->NombreDeContraintesDuProblemeSansCoupes; + +Spx->FaireScalingLU = 0; +Spx->UtiliserCoutMax = NON_SPX; +if ( Spx->AlgorithmeChoisi == SPX_DUAL && UtiliserCoutMax == OUI_SPX ) { + Marge = 1.e-6 * fabs ( CoutMax ); + if ( Marge < 1.e-6 ) Marge = 1.e-6; + if ( Marge > 1.e+1 ) Marge = 1.e+1; + Spx->CoutMax = CoutMax + Marge; + Spx->UtiliserCoutMax = OUI_SPX; +} + +PartieFixeDuCout = 0.; +if ( Spx->UtiliserCoutMax == OUI_SPX ) { + for ( Var_E = 0 ; Var_E < NbVar_E ; Var_E++ ) { + if ( TypeVar_E[Var_E] == VARIABLE_FIXE ) { + PartieFixeDuCout+= C_E[Var_E] * X_E[Var_E]; + continue; + } + if ( TypeVar_E[Var_E] == VARIABLE_BORNEE_DES_DEUX_COTES || TypeVar_E[Var_E] == VARIABLE_BORNEE_INFERIEUREMENT ) { + PartieFixeDuCout+= C_E[Var_E] * Xmin_E[Var_E]; + } + } +} +Spx->PartieFixeDuCout = PartieFixeDuCout; + +/*------------------------------------------------------------*/ + +CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; +TypeDeVariable = Spx->TypeDeVariable; +X = Spx->X; +Xmin = Spx->Xmin; +Xmax = Spx->Xmax; +C = Spx->C; +Csv = Spx->Csv; + +XminEntree = Spx->XminEntree; +XmaxEntree = Spx->XmaxEntree; +XEntree = Spx->XEntree; + +BAvantTranslationEtApresScaling = Spx->BAvantTranslationEtApresScaling; +B = Spx->B; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +A = Spx->A; +Indcol = Spx->Indcol; +ScaleX = Spx->ScaleX; + +/* Initialisation sur les variables */ +for ( Var_E = 0 ; Var_E < NbVar_E ; Var_E++ ) { + Var = CorrespondanceVarEntreeVarSimplexe[Var_E]; + if ( Var < 0 || Var >= Spx->NombreDeVariables ) continue; + X[Var] = X_E[Var_E]; + /* Nouvelles bornes */ + Xmin[Var] = Xmin_E[Var_E]; + Xmax[Var] = Xmax_E[Var_E]; + C [Var] = Csv[Var]; + /* Comme on peut changer le type a cause du reduced cost fixing on le met a jour */ + if ( TypeVar_E[Var_E] == VARIABLE_BORNEE_DES_DEUX_COTES ) TypeDeVariable[Var] = BORNEE; + else if ( TypeVar_E[Var_E] == VARIABLE_BORNEE_INFERIEUREMENT ) TypeDeVariable[Var] = BORNEE_INFERIEUREMENT; + else if ( TypeVar_E[Var_E] == VARIABLE_NON_BORNEE ) TypeDeVariable[Var] = NON_BORNEE; + else { + printf("Bug dans l'appel du Simplexe, variable simplexe %d variable externe %d \n",Var,Var_E); + printf(" type de borne %d non autorise en mode branch and bound\n",(int) TypeVar_E[Var_E]); + exit(0); + } +} + +/* Les bornes min. des variables entieres ont pu etre relevees pour une instanciation a 1. + Il faut donc refaire une translation des bornes. */ +/* Translation des bornes */ +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + XminEntree[Var] = Xmin[Var]; + XmaxEntree[Var] = Xmax[Var]; + if ( TypeDeVariable[Var] == NON_BORNEE ) continue; + if ( TypeDeVariable[Var] == BORNEE ) Xmax[Var] = XmaxEntree[Var] - XminEntree[Var]; + Xmin[Var] = 0.; + XEntree[Var] = X[Var]; + X[Var] = XEntree[Var] - XminEntree[Var]; +} + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + B[Cnt] = BAvantTranslationEtApresScaling[Cnt]; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + S = 0.; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( TypeDeVariable[Var] != NON_BORNEE ) S+= A[il] * XminEntree[Var] / ScaleX[Var]; + il++; + } + B[Cnt]-=S; +} + +/* Scaling des bornes */ +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + /* Attention, on suppose toujours que la variable est bornee */ + UnSurScaleXFoisUnSurSupXmax = 1. / ScaleX[Var]; + X[Var]*= UnSurScaleXFoisUnSurSupXmax; + if ( TypeDeVariable[Var] != NON_BORNEE ) Xmin[Var]*= UnSurScaleXFoisUnSurSupXmax; + if ( TypeDeVariable[Var] == BORNEE ) Xmax[Var]*= UnSurScaleXFoisUnSurSupXmax; +} + +return; +} + +/*----------------------------------------------------------------------------*/ +/* Construction de la base de depart (hors coupes) */ + +void SPX_ConstruireLaBaseDuProblemeModifie( PROBLEME_SPX * Spx, int NbVar_E, + int * PositionDeLaVariable_E, + int NbVarDeBaseComplementaires_E, + int * ComplementDeLaBase_E ) +{ +int Cnt; int Var; int Var_E; int il; /*int ilMax;*/ int * VariableEnBaseDeLaContrainte; +char * PositionDeLaVariable; int * CorrespondanceCntEntreeCntSimplexe; +int * ContrainteDeLaVariableEnBase; int * Mdeb; int * NbTerm; int * Indcol; +char * OrigineDeLaVariable; + +NbVar_E = 0; /* Pour ne pas avoir de warning a la compilation */ +PositionDeLaVariable = (char *) PositionDeLaVariable_E; /* Pour ne pas avoir de warning a la compilation */ + +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +PositionDeLaVariable = Spx->PositionDeLaVariable; +CorrespondanceCntEntreeCntSimplexe = Spx->CorrespondanceCntEntreeCntSimplexe; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +OrigineDeLaVariable = Spx->OrigineDeLaVariable; + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) VariableEnBaseDeLaContrainte[Cnt] = -1; +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; + +for ( Var_E = 0 ; Var_E < NbVarDeBaseComplementaires_E ; Var_E++ ) { + Cnt = CorrespondanceCntEntreeCntSimplexe[ComplementDeLaBase_E[Var_E]]; + if ( Cnt < 0 ) { + printf("Attention, anomalie detectee dans SPX_ConstruireLaBaseDuProblemeModifie:\n"); + printf(" La variable d'ecart contrainte %d est fournie comme etant basique or cette contrainte est inconnue du simplexe\n",Var_E); + continue; + } + /* Comme le chainage est reorganise en cours d'algorithme, il faut rechercher la variable dont + l'origine est ECART ou BASIQUE_ARTIFICIELLE */ + /* Non: on est revenu a l'ancienne methode. La variable d'ecart ou la variable BASIQUE_ARTIFICIELLE est + toujours la derniere de la contrainte */ + /* + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( OrigineDeLaVariable[Var] == ECART || OrigineDeLaVariable[Var] == BASIQUE_ARTIFICIELLE ) { + PositionDeLaVariable [Var] = EN_BASE_LIBRE; + ContrainteDeLaVariableEnBase[Var] = Cnt; + VariableEnBaseDeLaContrainte[Cnt] = Var; + break; + } + il++; + } + */ + il = Mdeb[Cnt] + NbTerm[Cnt] - 1; + Var = Indcol[il]; + PositionDeLaVariable [Var] = EN_BASE_LIBRE; + ContrainteDeLaVariableEnBase[Var] = Cnt; + VariableEnBaseDeLaContrainte[Cnt] = Var; +} + +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_CompleterLaBaseDuProblemeModifie( + PROBLEME_SPX * Spx, + int NbVar_E, /* Nombre de variables */ + int NbContr_E, /* Nombre de contraintes */ + int * PositionDeLaVariable_E /* La base sur les variables natives */ + ) +{ +int j; int Var_E; int Var ; char * CorrectionDuale; char * TypeDeVariable; +int * CorrespondanceVarEntreeVarSimplexe; char * PositionDeLaVariable; +int * ContrainteDeLaVariableEnBase; int * VariableEnBaseDeLaContrainte; + +NbContr_E = 0; /* Pour ne pas avoir de warning a la compilation */ + +/* Reinitialisation des corrections duales une fois qu'on a toutes les variables + sous la main */ + +CorrectionDuale = Spx->CorrectionDuale; + +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) CorrectionDuale[Var] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + +/* Pour les contraintes et les variables restantes */ + +CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; +PositionDeLaVariable = Spx->PositionDeLaVariable; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +TypeDeVariable = Spx->TypeDeVariable; + +for ( j = 0 , Var_E = 0 ; Var_E < NbVar_E ; Var_E++ ) { + + Var = CorrespondanceVarEntreeVarSimplexe[Var_E]; + + if ( Var < 0 || Var >= Spx->NombreDeVariables ) continue; + if ( PositionDeLaVariable_E[Var_E] == EN_BASE ) { + PositionDeLaVariable[Var] = EN_BASE_LIBRE; + while ( VariableEnBaseDeLaContrainte[j] != - 1 ) j++; + ContrainteDeLaVariableEnBase[Var] = j; + VariableEnBaseDeLaContrainte[j] = Var; + j++; + } + else if ( PositionDeLaVariable_E[Var_E] == HORS_BASE_SUR_BORNE_INF ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + /* Mise en coherence en cas de changement de type de borne dans la partie PNE */ + if ( TypeDeVariable[Var] == NON_BORNEE ) PositionDeLaVariable[Var] = HORS_BASE_A_ZERO; + } + else if ( PositionDeLaVariable_E[Var_E] == HORS_BASE_SUR_BORNE_SUP ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_SUP; + /* Mise en coherence en cas de changement de type de borne dans la partie PNE */ + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + else if ( TypeDeVariable[Var] == NON_BORNEE ) PositionDeLaVariable[Var] = HORS_BASE_A_ZERO; + } + else if ( PositionDeLaVariable_E[Var_E] == HORS_BASE_A_ZERO ) { + PositionDeLaVariable[Var] = HORS_BASE_A_ZERO; + /* Mise en coherence en cas de changement de type de borne dans la partie PNE */ + if ( TypeDeVariable[Var] == BORNEE || TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + } + } + else { + printf(" Bug dans la fourniture de la base de depart, la variable %d est mal positionnee\n",Var_E); + printf(" son positionnement donne est %d \n",(int) PositionDeLaVariable_E[Var_E]); + exit(0); + } +} + +/* Pour ne pas utiliser les poids precedents */ +Spx->LeSteepestEdgeEstInitilise = NON_SPX; + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_ordonner_contraintes_pour_la_base.c b/src/ext/Sirius_Solver/simplexe/spx_ordonner_contraintes_pour_la_base.c new file mode 100644 index 0000000000..e63d6ecc29 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_ordonner_contraintes_pour_la_base.c @@ -0,0 +1,478 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Determination de l'ordre des contraintes pour la factorisation + de la partie de la base qui concerne des colonnes a plus + d'un terme. + + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +# define TRACES 0 + +# define MAX_RANG_BASE_REDUITE 0.66 /* i.e. 2/3 */ + +# define COEFF_POUR_RANG_BASE_REDUITE 0.5 + +# define COEFF_MULT_TOLERANCE_PRIMALE 1. + +# define TRAVAILLER_AVEC_LA_BASE_REDUITE OUI_SPX /*OUI_SPX*/ + +int SPX_PartitionTriRapideViolation( double * , int * , int , int ); +void SPX_TriRapideViolations( double * , int * , int , int ); + +/*----------------------------------------------------------------------------*/ + +void SPX_TestPassageBaseReduiteBaseComplete( PROBLEME_SPX * Spx ) +{ +int NombreDInfaisabilites; char TenterBaseReduite; int Seuil1; int Seuil2; + +SPX_ControleDesVariablesBasiquesHorsBaseReduite( Spx, &NombreDInfaisabilites ); + +TenterBaseReduite = OUI_SPX; + +Seuil1 = 100; +Seuil2 = 100; + +if ( NombreDInfaisabilites >= 0 ) { + if ( Spx->NombreDeContraintes < 100000 ) Seuil2 = 0.01 * Spx->NombreDeContraintes; + else if ( Spx->NombreDeContraintes < 200000 ) Seuil2 = 0.02 * Spx->NombreDeContraintes; + else if ( Spx->NombreDeContraintes < 300000 ) Seuil2 = 0.03 * Spx->NombreDeContraintes; + else if ( Spx->NombreDeContraintes < 400000 ) Seuil2 = 0.04 * Spx->NombreDeContraintes; + else Seuil2 = 0.05 * Spx->NombreDeContraintes; +} +else NombreDInfaisabilites = -NombreDInfaisabilites; + +# if TRACES == 1 + printf("NombreDInfaisabilites = %d iteration %d ModifCoutsAutorisee %d\n",NombreDInfaisabilites,Spx->Iteration,Spx->ModifCoutsAutorisee); +# endif + +if ( NombreDInfaisabilites < 100 || NombreDInfaisabilites < Seuil2 ) { + if ( NombreDInfaisabilites == 0 ) TenterBaseReduite = NON_SPX; + else if ( Spx->Iteration > 1000 ) { + /* On reprend la matrice complete */ + TenterBaseReduite = NON_SPX; + } +} + +# if TRACES == 1 + if ( TenterBaseReduite == NON_SPX ) printf("On passe en base complete\n"); +# endif + +if ( Spx->IterationDeConstructionDeLaBaseReduite > 0 ) { + /* + if ( Spx->Iteration - Spx->IterationDeConstructionDeLaBaseReduite > 0.66 * Spx->RangDeLaMatriceFactorisee ) { + TenterBaseReduite = NON_SPX; + } + */ + + if ( Spx->Iteration - Spx->IterationDeConstructionDeLaBaseReduite > 0.5 * (Spx->NombreDeContraintes-Spx->RangDeLaMatriceFactorisee) ) { + TenterBaseReduite = NON_SPX; + } + +} + +if ( TenterBaseReduite == OUI_SPX ) { + # if TRACES == 1 + printf(" On refactorise avec possibilite de base reduite \n"); + #endif + Spx->InitBaseReduite = OUI_SPX; + Spx->YaUneSolution = OUI_SPX; /* Car c'est positionne a NON_SPX en cas de probleme */ + SPX_FactoriserLaBase( Spx ); + if ( Spx->YaUneSolution == NON_SPX ) { + #if VERBOSE_SPX + printf("Base non inversible ou probleme pour trouver une base duale admissible\n"); + #endif + return; + } +} +else { + /* La base reduite est optimale et admissible */ + # if TRACES == 1 + printf(" On refactorise la base complete\n"); + #endif + + Spx->UtiliserLaBaseReduite = NON_SPX; + SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); + + Spx->ForcerUtilisationDeLaBaseComplete = Spx->NombreDeBasesCompletesSuccessives; + Spx->NombreDeBasesCompletesSuccessives++; + Spx->YaUneSolution = OUI_SPX; /* Car c'est positionne a NON_SPX en cas de probleme */ + SPX_FactoriserLaBase( Spx ); + if ( Spx->YaUneSolution == NON_SPX ) { + #if VERBOSE_SPX + printf("Base non inversible ou probleme pour trouver une base duale admissible\n"); + #endif + return; + } + SPX_InitDualPoids( Spx ); /* Car les poids de la base reduite ne sont plus bons */ + + Spx->CoefficientPourLaValeurDePerturbationDeCoutAPosteriori = 1.0; + +} +Spx->CalculerBBarre = OUI_SPX; +Spx->CalculerCBarre = OUI_SPX; +return; +} + +/*----------------------------------------------------------------------------*/ + +int SPX_PartitionTriRapideViolation( double * Violation, int * NumeroDeVariable, int Deb, int Fin ) +{ +int Compt; double Pivot; int i; int Var; double Viol; + +Compt = Deb; +Var = NumeroDeVariable[Deb]; +Pivot = Violation[Deb]; + +/* Ordre decroissant */ +for ( i = Deb + 1 ; i <= Fin ; i++) { + if ( Violation[i] > Pivot) { + Compt++; + Viol = Violation[Compt]; + Violation[Compt] = Violation[i]; + Violation[i] = Viol; + Var = NumeroDeVariable[Compt]; + NumeroDeVariable[Compt] = NumeroDeVariable[i]; + NumeroDeVariable[i] = Var; + } +} +Viol = Violation[Compt]; +Violation[Compt] = Violation[Deb]; +Violation[Deb] = Viol; +Var = NumeroDeVariable[Compt]; +NumeroDeVariable[Compt] = NumeroDeVariable[Deb]; +NumeroDeVariable[Deb] = Var; +return(Compt); +} + +/*----------------------------------------------------------------------------*/ + +void SPX_TriRapideViolations( double * Violation, int * NumeroDeVariable, int Debut, int Fin ) +{ +int Pivot; +if ( Debut < Fin ) { + Pivot = SPX_PartitionTriRapideViolation( Violation, NumeroDeVariable, Debut, Fin ); + SPX_TriRapideViolations( Violation, NumeroDeVariable, Debut , Pivot-1 ); + SPX_TriRapideViolations( Violation, NumeroDeVariable, Pivot+1, Fin ); +} +return; +} + +/*----------------------------------------------------------------------------*/ +/* Initialisation */ +void SPX_ControleDesVariablesBasiquesHorsBaseReduite( PROBLEME_SPX * Spx, int * NombreDInfaisabilites ) +{ +int * ColonneDeLaBaseFactorisee; int Colonne; int Var; int * VariableEnBaseDeLaContrainte; +double * BBarre; int r; double * SeuilDeViolationDeBorne; char * PositionHorsBaseReduiteAutorisee; +int NbInfaisabilites; char * OrigineDeLaVariable; char * TypeDeVariable; int NbInfMax; +int * NumeroDeVariable; double * Violation; int NombreDeRevalidations; double * C; +int NouvelleDimensionDeLaBaseReduite; + +/* Calcul des valeurs pour la partie hors base reduite */ +SPX_CalculerBBarreAHorsReduite( Spx ); +ColonneDeLaBaseFactorisee = Spx->ColonneDeLaBaseFactorisee; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +PositionHorsBaseReduiteAutorisee = Spx->PositionHorsBaseReduiteAutorisee; +BBarre = Spx->BBarre; +SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; +OrigineDeLaVariable = Spx->OrigineDeLaVariable; +TypeDeVariable = Spx->TypeDeVariable; +C = Spx->C; + +Violation = (double *) malloc( Spx->NombreDeVariables * sizeof( double ) ); +NumeroDeVariable = (int *) malloc( Spx->NombreDeVariables * sizeof( int ) ); +if ( Violation == NULL || NumeroDeVariable == NULL ) { + free( Violation ); free( NumeroDeVariable ); + *NombreDInfaisabilites = 0; /* Afin de passer en base complete */ + return; +} + +NombreDeRevalidations = 0; +for ( r = 0 ; r < Spx->RangDeLaMatriceFactorisee ; r++ ) { + Colonne = ColonneDeLaBaseFactorisee[r]; + Var = VariableEnBaseDeLaContrainte[Colonne]; + if ( OrigineDeLaVariable[Var] == ECART && C[Var] == 0 ) { + if ( PositionHorsBaseReduiteAutorisee[Var] != NON_2_FOIS ) NombreDeRevalidations++; + } +} + +/* Classement des N premieres violations */ +NbInfaisabilites = 0; +for ( r = Spx->RangDeLaMatriceFactorisee ; r < Spx->NombreDeContraintes ; r++ ) { + Colonne = ColonneDeLaBaseFactorisee[r]; + Var = VariableEnBaseDeLaContrainte[Colonne]; + if ( PositionHorsBaseReduiteAutorisee[Var] == OUI_1_FOIS || PositionHorsBaseReduiteAutorisee[Var] == OUI_2_FOIS ) { + if ( BBarre[Colonne] < -(COEFF_MULT_TOLERANCE_PRIMALE * SeuilDeViolationDeBorne[Var]) ) { + Violation[NbInfaisabilites] = fabs( BBarre[Colonne] ); + NumeroDeVariable[NbInfaisabilites] = Var; + NbInfaisabilites++; + } + else if ( BBarre[Colonne] > Spx->Xmax[Var] + (COEFF_MULT_TOLERANCE_PRIMALE * SeuilDeViolationDeBorne[Var]) ) { + Violation[NbInfaisabilites] = fabs( BBarre[Colonne] - Spx->Xmax[Var] ); + NumeroDeVariable[NbInfaisabilites] = Var; + NbInfaisabilites++; + } + } +} +*NombreDInfaisabilites = NbInfaisabilites; + +SPX_TriRapideViolations( Violation, NumeroDeVariable, 0, NbInfaisabilites - 1 ); + +NbInfaisabilites = 0; + +if ( Spx->NombreDeContraintes < 100000 ) NbInfMax = 0.01 * Spx->NombreDeContraintes; +else if ( Spx->NombreDeContraintes < 200000 ) NbInfMax = 0.02 * Spx->NombreDeContraintes; +else if ( Spx->NombreDeContraintes < 300000 ) NbInfMax = 0.03 * Spx->NombreDeContraintes; +else if ( Spx->NombreDeContraintes < 400000 ) NbInfMax = 0.04 * Spx->NombreDeContraintes; +else NbInfMax = 0.05 * Spx->NombreDeContraintes; + +for ( NbInfaisabilites = 0 ; NbInfaisabilites < *NombreDInfaisabilites && NbInfaisabilites < NbInfMax ; NbInfaisabilites++ ) { + Var = NumeroDeVariable[NbInfaisabilites]; + if ( PositionHorsBaseReduiteAutorisee[Var] == OUI_1_FOIS ) { + if ( OrigineDeLaVariable[Var] == ECART || TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + PositionHorsBaseReduiteAutorisee[Var] = /*NON_2_FOIS*/ NON_1_FOIS; + } + else PositionHorsBaseReduiteAutorisee[Var] = NON_2_FOIS; + } + else PositionHorsBaseReduiteAutorisee[Var] = NON_2_FOIS; +} + +if ( *NombreDInfaisabilites <= Spx->NombreDinfaisabilitesSiBaseReduite || Spx->NbEchecsReductionNombreDinfaisabilitesSiBaseReduite < 2 ) { + /* Seulement si on arrive a faire baisser le nombre d'infaisabilites */ + /* Tant que la nouvelle dimension de la base reduite reste petite, on arrete pas le princing dual partiel */ + if ( *NombreDInfaisabilites > 100 ) { + NouvelleDimensionDeLaBaseReduite = Spx->RangDeLaMatriceFactorisee + NbInfaisabilites - NombreDeRevalidations; + if ( NouvelleDimensionDeLaBaseReduite < COEFF_POUR_RANG_BASE_REDUITE * Spx->NombreDeContraintes ) { + *NombreDInfaisabilites = -(*NombreDInfaisabilites); + } + } +} +if ( fabs( *NombreDInfaisabilites ) > Spx->NombreDinfaisabilitesSiBaseReduite ) Spx->NbEchecsReductionNombreDinfaisabilitesSiBaseReduite++; + +Spx->NombreDinfaisabilitesSiBaseReduite = fabs( *NombreDInfaisabilites ); + +free( NumeroDeVariable ); +free( Violation ); +return; +} + +/*----------------------------------------------------------------------------*/ +/* Initialisation */ +void SPX_OrdonnerLesContraintesPourLaBase( PROBLEME_SPX * Spx ) +{ +int NombreDeContraintes; int * OrdreColonneDeLaBaseFactorisee; int * ColonneDeLaBaseFactorisee; +int Colonne; int * OrdreLigneDeLaBaseFactorisee; int * LigneDeLaBaseFactorisee; int MaxRang; +int Var; char * OrigineDeLaVariable; int Ligne; int i; int RangDeLaMatriceFactorisee; +int OrdreNonNative; int * Cdeb; int * NumeroDeContrainte; int AncienOrdreDeLigne; int DerniereLigne; +int * VariableEnBaseDeLaContrainte; int * IndexDansContrainteASurveiller; int NombreDeContraintesASurveiller; +int Iteration; double * BBarre; int r; char VariableDansBaseReduite; char * PositionDeLaVariable; +int NombreDeVariablesDecartBasiques; char * PositionHorsBaseReduiteAutorisee; double * C; +char ControlerAdmissibiliteDuale; char * CorrectionDuale; int * CNbTerm; char * TypeDeVariable; + +BBarre = Spx->BBarre; +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; +PositionDeLaVariable = Spx->PositionDeLaVariable; +C = Spx->C; + +# if TRAVAILLER_AVEC_LA_BASE_REDUITE == NON_SPX + Spx->RangDeLaMatriceFactorisee = Spx->NombreDeContraintes; + Spx->UtiliserLaBaseReduite = NON_SPX; + Spx->UtiliserLaLuUpdate = OUI_SPX; + return; +# endif + +if ( Spx->Iteration > Spx->NombreDeContraintes && 0 ) { + Spx->RangDeLaMatriceFactorisee = NombreDeContraintes; + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) SPX_InitDualPoids( Spx ); + Spx->UtiliserLaBaseReduite = NON_SPX; + Spx->UtiliserLaLuUpdate = OUI_SPX; + return; +} + +if ( Spx->InitBaseReduite == NON_SPX ) { + return; +} + +NombreDeContraintes = Spx->NombreDeContraintes; +OrigineDeLaVariable = Spx->OrigineDeLaVariable; + +MaxRang = (int) ( (ceil) (MAX_RANG_BASE_REDUITE * NombreDeContraintes) ); + +NombreDeVariablesDecartBasiques = 0; +for ( Var = Spx->NombreDeVariablesNatives ; Var < Spx->NombreDeVariables ; Var++ ) { + if ( PositionDeLaVariable[Var] == EN_BASE_LIBRE ) { + if ( OrigineDeLaVariable[Var] == ECART ) NombreDeVariablesDecartBasiques++; + } +} + +if ( NombreDeContraintes - NombreDeVariablesDecartBasiques > MaxRang ) { + Spx->RangDeLaMatriceFactorisee = NombreDeContraintes; + if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) SPX_InitDualPoids( Spx ); + Spx->UtiliserLaBaseReduite = NON_SPX; + Spx->UtiliserLaLuUpdate = OUI_SPX; + return; +} + +/* Prevoir une exclusion d'emblee basee sur MaxRang s'il n'y a pas assez de variables d'ecart */ +TypeDeVariable = Spx->TypeDeVariable; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +IndexDansContrainteASurveiller = Spx->IndexDansContrainteASurveiller; +NombreDeContraintesASurveiller = Spx->NombreDeContraintesASurveiller; +Iteration = Spx->Iteration; + +OrdreColonneDeLaBaseFactorisee = Spx->OrdreColonneDeLaBaseFactorisee; +ColonneDeLaBaseFactorisee = Spx->ColonneDeLaBaseFactorisee; + +OrdreLigneDeLaBaseFactorisee = Spx->OrdreLigneDeLaBaseFactorisee; +LigneDeLaBaseFactorisee = Spx->LigneDeLaBaseFactorisee; + +PositionHorsBaseReduiteAutorisee = Spx->PositionHorsBaseReduiteAutorisee; + +/* Permutation des colonnes */ +/* Permutation des lignes. On utilise le fait que les variables d'ecart et artificielles sont classees + a la fin de la contrainte dans le stockage par ligne */ + +RangDeLaMatriceFactorisee = 0; +OrdreNonNative = NombreDeContraintes - 1; + +for ( i = 0 ; i < NombreDeContraintes ; i++ ) { + OrdreLigneDeLaBaseFactorisee[i] = i; + LigneDeLaBaseFactorisee[i] = i; +} + +CorrectionDuale = Spx->CorrectionDuale; +ControlerAdmissibiliteDuale = NON_SPX; + +for ( Colonne = 0 ; Colonne < NombreDeContraintes ; Colonne++ ) { + + Var = VariableEnBaseDeLaContrainte[Colonne]; + + VariableDansBaseReduite = NON_SPX; + if ( OrigineDeLaVariable[Var] != ECART ) { + /* On regarde si la variable peut faire office de variable d'ecart */ + if ( CNbTerm[Var] == 1 && C[Var] == 0 /*&& OrigineDeLaVariable[Var] != BASIQUE_ARTIFICIELLE*/ ) { + if ( PositionHorsBaseReduiteAutorisee[Var] == NON_1_FOIS || PositionHorsBaseReduiteAutorisee[Var] == NON_2_FOIS ) VariableDansBaseReduite = OUI_SPX; + else { + if ( PositionHorsBaseReduiteAutorisee[Var] == OUI_1_FOIS ) VariableDansBaseReduite = NON_SPX; + else if ( PositionHorsBaseReduiteAutorisee[Var] == OUI_2_FOIS ) { + if ( Spx->BBarre[Colonne] > -Spx->SeuilDeViolationDeBorne[Var] && + Spx->BBarre[Colonne] < Spx->Xmax[Var] + Spx->SeuilDeViolationDeBorne[Var] ) VariableDansBaseReduite = NON_SPX; + else VariableDansBaseReduite = OUI_SPX; + } + } + if ( PositionHorsBaseReduiteAutorisee[Var] == NON_1_FOIS ) PositionHorsBaseReduiteAutorisee[Var] = OUI_2_FOIS; + } + else VariableDansBaseReduite = OUI_SPX; + } + else { + /* C'est une variable d'ecart */ + if ( PositionHorsBaseReduiteAutorisee[Var] == NON_1_FOIS || PositionHorsBaseReduiteAutorisee[Var] == NON_2_FOIS || C[Var] != 0.0 ) VariableDansBaseReduite = OUI_SPX; + if ( PositionHorsBaseReduiteAutorisee[Var] == NON_1_FOIS && C[Var] == 0 ) PositionHorsBaseReduiteAutorisee[Var] = OUI_2_FOIS; + } + + /* Si la variable est native ou violee on la met dans la partie reduite pour qu'elle puisse sortir + de la base si necessaire */ + if ( VariableDansBaseReduite == OUI_SPX ) { + OrdreColonneDeLaBaseFactorisee[Colonne] = RangDeLaMatriceFactorisee; + ColonneDeLaBaseFactorisee[RangDeLaMatriceFactorisee] = Colonne; + RangDeLaMatriceFactorisee++; + } + else { + /* Variable non native (ecart ou basique artificielle) */ + OrdreColonneDeLaBaseFactorisee[Colonne] = OrdreNonNative; + ColonneDeLaBaseFactorisee[OrdreNonNative] = Colonne; + + DerniereLigne = LigneDeLaBaseFactorisee[OrdreNonNative]; + + Ligne = NumeroDeContrainte[Cdeb[Var]]; + AncienOrdreDeLigne = OrdreLigneDeLaBaseFactorisee[Ligne]; + + LigneDeLaBaseFactorisee[OrdreNonNative] = Ligne; + OrdreLigneDeLaBaseFactorisee[Ligne] = OrdreNonNative; + + OrdreLigneDeLaBaseFactorisee[DerniereLigne] = AncienOrdreDeLigne; + LigneDeLaBaseFactorisee[AncienOrdreDeLigne] = DerniereLigne; + + /* Test: la contrainte est negligee. Si a la fin elle est violee on elle passera a NON_2_FOIS et ne sera plus + jamais relaxee */ + /*PositionHorsBaseReduiteAutorisee[Var] = OUI_1_FOIS;*/ + /* Fin test */ + + OrdreNonNative--; + + } +} + +/* Il faut reinitialiser les poids car les contraintes ont pu changer */ +SPX_InitDualPoids( Spx ); + +SPX_InitialiserLesIndicateursHyperCreux( Spx ); + +Spx->RangDeLaMatriceFactorisee = RangDeLaMatriceFactorisee; +Spx->UtiliserLaBaseReduite = OUI_SPX; +Spx->UtiliserLaLuUpdate = OUI_SPX; +Spx->NombreDeBasesReduitesSuccessives--; + +Spx->InitBaseReduite = NON_SPX; + +if ( Spx->RangDeLaMatriceFactorisee > MaxRang ) { + Spx->RangDeLaMatriceFactorisee = NombreDeContraintes; + Spx->UtiliserLaBaseReduite = NON_SPX; + Spx->UtiliserLaLuUpdate = OUI_SPX; + return; +} + +/* Construction du stockge de la transposee de la matrice reduite */ +SPX_ConstructionDeLaMatriceReduite( Spx ); + +SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); + +Spx->IterationDeConstructionDeLaBaseReduite = Spx->Iteration; + +/* Il est indispensable que les couts des variables d'ecart basiques hors base reduite soient nuls car on ne recalcule pas + la variable duale des contraintes associees puisqu'on suppose qu'elles sont nulles */ + +/* Pas certain que ce soit utile */ +for ( r = RangDeLaMatriceFactorisee ; r < NombreDeContraintes ; r++ ) { + BBarre[r] = 0; +} + +/*printf("\nRangDeLaMatriceFactorisee %d NombreDeContraintes %d Iteration %d\n\n",Spx->RangDeLaMatriceFactorisee,NombreDeContraintes,Spx->Iteration);*/ + +# if TRACES == 1 + printf("SPX_OrdonnerLesContraintesPourLaBase: RangDeLaMatriceFactorisee = %d\n",Spx->RangDeLaMatriceFactorisee); +# endif + +return; +} + +/*----------------------------------------------------------------------------*/ + diff --git a/src/ext/Sirius_Solver/simplexe/spx_ordonner_stockage_matrice.c b/src/ext/Sirius_Solver/simplexe/spx_ordonner_stockage_matrice.c new file mode 100644 index 0000000000..2517390eaf --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_ordonner_stockage_matrice.c @@ -0,0 +1,90 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On ordonne les stockage des matrices dans l'ordre croissant + des indices. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" + +int SPX_PartitionOrdreCroissant( double * , int * , int , int ); +void SPX_ClasserVecteurDansOrdreCroissant( double * , int * , int , int ); + +/*----------------------------------------------------------------------------*/ + +int SPX_PartitionOrdreCroissant( double * A, int * NumColonneOuNumLigne, int Debut, int Fin ) +{ +int Compt; int Pivot; int i; double a; int v; +Compt = Debut; +Pivot = NumColonneOuNumLigne[Debut]; +/* Ordre croissant */ +for ( i = Debut + 1 ; i <= Fin ; i++) { + if ( NumColonneOuNumLigne[i] < Pivot) { + Compt++; + a = A[Compt]; + A[Compt] = A[i]; + A[i] = a; + v = NumColonneOuNumLigne[Compt]; + NumColonneOuNumLigne[Compt] = NumColonneOuNumLigne[i]; + NumColonneOuNumLigne[i] = v; + } +} +a = A[Compt]; +A[Compt] = A[Debut]; +A[Debut] = a; +v = NumColonneOuNumLigne[Compt]; +NumColonneOuNumLigne[Compt] = NumColonneOuNumLigne[Debut]; +NumColonneOuNumLigne[Debut] = v; +return(Compt); +} + +/*----------------------------------------------------------------------------*/ + +void SPX_ClasserVecteurDansOrdreCroissant( double * A, int * NumColonneOuNumLigne, int Debut, int Fin ) +{ +int Pivot; +if ( Debut < Fin ) { + Pivot = SPX_PartitionOrdreCroissant( A, NumColonneOuNumLigne, Debut, Fin ); + SPX_ClasserVecteurDansOrdreCroissant( A, NumColonneOuNumLigne, Debut, Pivot-1 ); + SPX_ClasserVecteurDansOrdreCroissant( A, NumColonneOuNumLigne, Pivot+1, Fin ); +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_OrdonnerMatriceDesContraintes( int NombreDeVecteurs, int * IndexDebut, int * NbTermes, + int * NumColonneOuNumLigne, double * A ) +{ +int Vecteur; int Debut; int Fin; +for ( Vecteur = 0 ; Vecteur < NombreDeVecteurs ; Vecteur++ ) { + if ( NbTermes[Vecteur] <= 0 ) continue; + Debut = IndexDebut[Vecteur]; + if ( Debut < 0 ) continue; + Fin = Debut + NbTermes[Vecteur] - 1; + SPX_ClasserVecteurDansOrdreCroissant( A, NumColonneOuNumLigne, Debut, Fin ); +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_recuperer_solution.c b/src/ext/Sirius_Solver/simplexe/spx_recuperer_solution.c new file mode 100644 index 0000000000..5607379f82 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_recuperer_solution.c @@ -0,0 +1,342 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Translater les bornes en sortie pour tout remettre + en ordre et restituer les resultats sur les variables + initiales du probleme. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define OLD_VERSION 1 +# define NEW_VERSION 2 +# define CHOIX_VERSION NEW_VERSION + +/*----------------------------------------------------------------------------*/ + +void SPX_RecupererLaSolution( PROBLEME_SPX * Spx, + int NbVar_E, + double * X_E, + int * TypeVar_E, + int NbContr_E, + int * PositionDeLaVariable, + int * NbVarDeBaseComplementaires, + int * ComplementDeLaBase + ) +{ +int Cnt; int Cnt_E; int Var_E; int VarSimplexe; char Position; +char * PositionDeLaVariableSPX; +# if CHOIX_VERSION == OLD_VERSION + int * CorrespondanceVarEntreeVarSimplexe; +# endif +# if CHOIX_VERSION == NEW_VERSION + int * CorrespondanceVarSimplexeVarEntree; +# endif +# if VERBOSE_PNE + char * OrigineDeLaVariable; +# endif +int * Cdeb; int * NumeroDeContrainte; +int * CorrespondanceCntSimplexeCntEntree; double * XminEntree; +char * TypeDeVariable; double * X; + +/*NbContr_E = 0;*/ + +SPX_UnScaling( Spx ); + +PositionDeLaVariableSPX = Spx->PositionDeLaVariable; + +# if VERBOSE_PNE + OrigineDeLaVariable = Spx->OrigineDeLaVariable; +# endif +CorrespondanceCntSimplexeCntEntree = Spx->CorrespondanceCntSimplexeCntEntree; +# if CHOIX_VERSION == OLD_VERSION + CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; +# endif +# if CHOIX_VERSION == NEW_VERSION + CorrespondanceVarSimplexeVarEntree = Spx->CorrespondanceVarSimplexeVarEntree; +# endif + +Cdeb = Spx->Cdeb; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +TypeDeVariable = Spx->TypeDeVariable; +X = Spx->X; +XminEntree = Spx->XminEntree; + +/* Remettre la solution dans les variables d origine et renvoyer la base optimale */ + +# if CHOIX_VERSION == OLD_VERSION + +for ( Var_E = 0 ; Var_E < NbVar_E ; Var_E++ ) { + PositionDeLaVariable[Var_E] = -1; + /* Attention correspondance des contraintes */ + VarSimplexe = CorrespondanceVarEntreeVarSimplexe[Var_E]; + if ( VarSimplexe >= 0 ) { + Position = PositionDeLaVariableSPX[VarSimplexe]; + if ( Position == EN_BASE_LIBRE ) { + /* Une variable native est basique. Si la contrainte de cette variable en base + est une coupe, on va considerer que cette coupe est saturee. En principe, elle + sera conservee. Cependant il peut s'agir d'un appel dans un contexte de + strong branching et dans ce cas elle risque d'etre supprimee si dans une des + instanciations a entier inf ou a entier sup la variable d'ecart associee a + la contrainte est basique */ + PositionDeLaVariable[Var_E] = EN_BASE; + } + else if ( Position == HORS_BASE_SUR_BORNE_INF ) { + PositionDeLaVariable[Var_E] = HORS_BASE_SUR_BORNE_INF; + } + else if ( Position == HORS_BASE_SUR_BORNE_SUP ) { + PositionDeLaVariable[Var_E] = HORS_BASE_SUR_BORNE_SUP; + } + else { + PositionDeLaVariable[Var_E] = HORS_BASE_A_ZERO; + } + } + else continue; + + if ( TypeVar_E[Var_E] != VARIABLE_FIXE ) { + if ( TypeDeVariable[VarSimplexe] == BORNEE || TypeDeVariable[VarSimplexe] == BORNEE_INFERIEUREMENT ) { + X_E[Var_E] = X[VarSimplexe] + XminEntree[VarSimplexe]; + } + else X_E[Var_E] = X[VarSimplexe]; + if ( TypeVar_E[Var_E] == VARIABLE_BORNEE_SUPERIEUREMENT ) X_E[Var_E] = -X_E[Var_E]; + } + +} + +# elif CHOIX_VERSION == NEW_VERSION + +for ( VarSimplexe = 0 ; VarSimplexe < Spx->NombreDeVariablesNatives ; VarSimplexe++ ) { + /* Attention correspondance des contraintes */ + Var_E = CorrespondanceVarSimplexeVarEntree[VarSimplexe]; + if ( Var_E < 0 || Var_E >= NbVar_E) continue; + Position = PositionDeLaVariableSPX[VarSimplexe]; + if ( Position == EN_BASE_LIBRE ) { + /* Une variable native est basique. Si la contrainte de cette variable en base + est une coupe, on va considerer que cette coupe est saturee. En principe, elle + sera conservee. Cependant il peut s'agir d'un appel dans un contexte de + strong branching et dans ce cas elle risque d'etre supprimee si dans une des + instanciations a entier inf ou a entier sup la variable d'ecart associee a + la contrainte est basique */ + PositionDeLaVariable[Var_E] = EN_BASE; + } + else if ( Position == HORS_BASE_SUR_BORNE_INF ) { + PositionDeLaVariable[Var_E] = HORS_BASE_SUR_BORNE_INF; + } + else if ( Position == HORS_BASE_SUR_BORNE_SUP ) { + PositionDeLaVariable[Var_E] = HORS_BASE_SUR_BORNE_SUP; + } + else { + PositionDeLaVariable[Var_E] = HORS_BASE_A_ZERO; + } + + if ( TypeVar_E[Var_E] != VARIABLE_FIXE ) { + if ( TypeDeVariable[VarSimplexe] == BORNEE || TypeDeVariable[VarSimplexe] == BORNEE_INFERIEUREMENT ) { + X_E[Var_E] = X[VarSimplexe] + XminEntree[VarSimplexe]; + } + else X_E[Var_E] = X[VarSimplexe]; + if ( TypeVar_E[Var_E] == VARIABLE_BORNEE_SUPERIEUREMENT ) X_E[Var_E] = -X_E[Var_E]; + } + +} + +# endif + +/* Des contraintes natives peuvent ne pas avoir de variable de base si c'est une variables additionnelle. + Il se peut alors que la variable additionnelle soit celle d'une autre contrainte. + On donne alors la matrice sous la forme d'un vecteur (puisqu'il s'agit de variables additionnelles) */ +*NbVarDeBaseComplementaires = 0; +for ( VarSimplexe = Spx->NombreDeVariablesNatives ; VarSimplexe < Spx->NombreDeVariablesDuProblemeSansCoupes ; VarSimplexe++ ) { + + if ( PositionDeLaVariableSPX[VarSimplexe] != EN_BASE_LIBRE ) continue; + + #if VERBOSE_PNE + if ( OrigineDeLaVariable[VarSimplexe] == BASIQUE_ARTIFICIELLE && Spx->StrongBranchingEnCours == NON_SPX ) { + printf(" IL RESTE DES VARIABLES BASIQUES ARTIFICIELLES DANS LA BASE variable simplexe %d valeur %lf \n", + VarSimplexe,Spx->X[VarSimplexe]); + } + #endif + Cnt = NumeroDeContrainte[Cdeb[VarSimplexe]]; + /* La variable est en base, la colonne de la variable doit avoir un seul terme */ + Cnt_E = CorrespondanceCntSimplexeCntEntree[Cnt]; + /* Attention ce n'est pas Spx->NombreDeContraintesDuProblemeSansCoupes mais le nombre de contraintes donnees au simplexe + lequel peut etre different de Spx->NombreDeContraintesDuProblemeSansCoupes si par exemple il y a des contraintes + vides */ + /*if ( Cnt_E >= 0 && Cnt_E < Spx->NombreDeContraintesDuProblemeSansCoupes ) {*/ + if ( Cnt_E >= 0 && Cnt_E < NbContr_E ) { + ComplementDeLaBase[*NbVarDeBaseComplementaires] = Cnt_E; + *NbVarDeBaseComplementaires = *NbVarDeBaseComplementaires + 1; + } +} + +return; +} + +/*---------------------------------------------------------------------------------*/ + +void SPX_RecuperationSimplifieeDeLaSolutionPourStrongBranching( + PROBLEME_SPX * Spx, + int NbVar_E, + int * PositionDeLaVariable, + int * NbVarDeBaseComplementaires, + int * ComplementDeLaBase + ) +{ +int Cnt; int Cnt_E; int Var_E; int VarSimplexe; char Position; +char * PositionDeLaVariableSPX; int * CorrespondanceVarEntreeVarSimplexe; +int * Cdeb; int * NumeroDeContrainte; int * CorrespondanceCntSimplexeCntEntree; + +CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; +PositionDeLaVariableSPX = Spx->PositionDeLaVariable; +CorrespondanceCntSimplexeCntEntree = Spx->CorrespondanceCntSimplexeCntEntree; +CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; + +Cdeb = Spx->Cdeb; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +for ( Var_E = 0 ; Var_E < NbVar_E ; Var_E++ ) { + PositionDeLaVariable[Var_E] = -1; + /* Attention correspondance des contraintes */ + VarSimplexe = CorrespondanceVarEntreeVarSimplexe[Var_E]; + if ( VarSimplexe >= 0 ) { + Position = PositionDeLaVariableSPX[VarSimplexe]; + if ( Position == EN_BASE_LIBRE ) { + /* Une variable native est basique. Si la contrainte de cette variable en base + est une coupe, on va considerer que cette coupe est saturee. En principe, elle + sera conservee. Cependant il peut s'agir d'un appel dans un contexte de + strong branching et dans ce cas elle risque d'etre supprimee si dans une des + instanciations a entier inf ou a entier sup la variable d'ecart associee a + la contrainte est basique */ + PositionDeLaVariable[Var_E] = EN_BASE; + } + else if ( Position == HORS_BASE_SUR_BORNE_INF ) { + PositionDeLaVariable[Var_E] = HORS_BASE_SUR_BORNE_INF; + } + else if ( Position == HORS_BASE_SUR_BORNE_SUP ) { + PositionDeLaVariable[Var_E] = HORS_BASE_SUR_BORNE_SUP; + } + else { + PositionDeLaVariable[Var_E] = HORS_BASE_A_ZERO; + } + } +} + +/* Des contraintes natives peuvent ne pas avoir de variable de base si c'est une variables additionnelle. + Il se peut alors que la variable additionnelle soit celle d'une autre contrainte. + On donne alors la matrice sous la forme d'un vecteur (puisqu'il s'agit de variables additionnelles) */ +*NbVarDeBaseComplementaires = 0; +for ( VarSimplexe = Spx->NombreDeVariablesNatives ; VarSimplexe < Spx->NombreDeVariablesDuProblemeSansCoupes ; VarSimplexe++ ) { + + if ( PositionDeLaVariableSPX[VarSimplexe] != EN_BASE_LIBRE ) continue; + + Cnt = NumeroDeContrainte[Cdeb[VarSimplexe]]; + /* La variable est en base, la colonne de la variable doit avoir un seul terme */ + Cnt_E = CorrespondanceCntSimplexeCntEntree[Cnt]; + if ( Cnt_E >= 0 && Cnt_E < Spx->NombreDeContraintesDuProblemeSansCoupes ) { + ComplementDeLaBase[*NbVarDeBaseComplementaires] = Cnt_E; + *NbVarDeBaseComplementaires = *NbVarDeBaseComplementaires + 1; + } +} + +return; +} + +/*---------------------------------------------------------------------------------*/ +/* Recuperation de la solution sur les coupes. La seule information interessante + est "la coupe est saturee ou pas". Si la variable d'ecart est basique, la coupe + n'est pas saturee (ce qui n'est pas tout a fait vrai). Si la variable d'ecart + n'est pas basique, la coupe est saturee. */ + +void SPX_RecupererLaSolutionSurLesCoupes( PROBLEME_SPX * Spx, + int NombreDeContraintesCoupes ,int * NbTermCoupes, + char * PositionDeLaVariableDEcart ) +{ +int Cnt; int il; int ilMax; int Cnt_E; char * OrigineDeLaVariable; +int * Mdeb; int * NbTerm; int * Indcol; char * PositionDeLaVariable; int Var; + +NombreDeContraintesCoupes = 0; /* Pour ne pas avoir de warning a la compilation */ + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +PositionDeLaVariable = Spx->PositionDeLaVariable; +OrigineDeLaVariable = Spx->OrigineDeLaVariable; + +Cnt_E = 0; + +goto NewCode; + +for ( Cnt = Spx->NombreDeContraintesDuProblemeSansCoupes ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + /* On cherche la variable Cnt_E correspondante */ + while ( NbTermCoupes[Cnt_E] <= 0 ) Cnt_E++; + /* Recherche de la variable d'ecart de la coupe (ce n'est pas forcement la derniere) attention, maintenant + c'est la derniere donc on pourrait simplifier cela */ + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( OrigineDeLaVariable[Var] == ECART ) { + /* Variable d'ecart */ + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) PositionDeLaVariableDEcart[Cnt_E] = HORS_BASE_SUR_BORNE_INF; + else PositionDeLaVariableDEcart[Cnt_E] = EN_BASE; + break; + } + il++; + } + Cnt_E++; +} +return; + +NewCode: + +for ( Cnt = Spx->NombreDeContraintesDuProblemeSansCoupes ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + /* On cherche la variable Cnt_E correspondante */ + while ( NbTermCoupes[Cnt_E] <= 0 ) Cnt_E++; + /* Recherche de la variable d'ecart de la coupe c'est la derniere */ + il = Mdeb[Cnt] + NbTerm[Cnt] - 1; + /* Variable d'ecart */ + if ( PositionDeLaVariable[Indcol[il]] == HORS_BASE_SUR_BORNE_INF ) PositionDeLaVariableDEcart[Cnt_E] = HORS_BASE_SUR_BORNE_INF; + else PositionDeLaVariableDEcart[Cnt_E] = EN_BASE; + Cnt_E++; +} + +return; +} + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_recuperer_solution_exploration_rapide_en_profondeur.c b/src/ext/Sirius_Solver/simplexe/spx_recuperer_solution_exploration_rapide_en_profondeur.c new file mode 100644 index 0000000000..6dc344622b --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_recuperer_solution_exploration_rapide_en_profondeur.c @@ -0,0 +1,102 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Recuperation de la solution lorsqu'elle est entiere pendant + l'exploration rapide en profondeur. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +#include "pne_define.h" + +#include "bb_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_RecupererLaSolutionSiExplorationRapide( PROBLEME_SPX * Spx, + void * PneProb, + void * BbProb, + void * Noeud, + int * TypeInstanciation ) +{ +PROBLEME_PNE * Pne; BB * Bb; NOEUD * NoeudEnExamen; int VarPne; int i; +int VarSpx; double X; int NombreDeVariablesBinairesPne; int * NumeroDesVariablesBinairesPne; +int * CorrespondanceVarEntreeVarSimplexe; + +if ( Spx->YaUneSolution != OUI_SPX ) return; + +Pne = (PROBLEME_PNE *) PneProb; +Bb = (BB *) BbProb; + +/* Le calcul du cout est fait dans SPX_ChoisirLaVariableAInstancier */ +SPX_UnScaling( Spx ); + +/* On met dans X la valeur d'instanciation */ +NombreDeVariablesBinairesPne = Bb->NombreDeVariablesEntieresDuProbleme; +NumeroDesVariablesBinairesPne = Bb->NumerosDesVariablesEntieresDuProbleme; + +CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; + +for ( i = 0 ; i < NombreDeVariablesBinairesPne ; i++ ) { + VarPne = NumeroDesVariablesBinairesPne[i]; + if ( TypeInstanciation[VarPne] == SORT_PAS ) continue; + /* La variable a ete instanciee */ + VarSpx = CorrespondanceVarEntreeVarSimplexe[VarPne]; + if ( VarSpx < 0 || VarSpx >= Spx->NombreDeVariables ) continue; + + Spx->X[VarSpx] = 0.; + if ( TypeInstanciation[VarPne] == SORT_SUR_XMAX ) Spx->X[VarSpx] = 1.; + +} + +NoeudEnExamen = (NOEUD *) Noeud; + +Pne->NombreDeVariablesAValeurFractionnaire = 0; +Pne->NormeDeFractionnalite = 0.0; + +Bb->NombreDeSolutionsEntieresTrouvees++; +NoeudEnExamen->LaSolutionRelaxeeEstEntiere = OUI; +NoeudEnExamen->MinorantDuCritereAuNoeud = Spx->Cout; + +/*printf("Cout %e CoutMax %e\n",Spx->Cout,Spx->CoutMax);*/ + +/* Il faut mettre a jour Pne->UTrav car c'est utilise pour stocker la solution optimale + entiere courante quand on passe dans NettoyerLArbre */ + +for ( VarPne = 0 ; VarPne < Pne->NombreDeVariablesTrav ; VarPne++ ) { + if ( Pne->TypeDeBorneTrav[VarPne] == VARIABLE_FIXE ) continue; + VarSpx = Spx->CorrespondanceVarEntreeVarSimplexe[VarPne]; + X = Spx->X[VarSpx]; + + if ( Spx->TypeDeVariable[VarSpx] == BORNEE || Spx->TypeDeVariable[VarSpx] == BORNEE_INFERIEUREMENT ) { + Pne->UTrav[VarPne] = X + Spx->XminEntree[VarSpx]; + } + else Pne->UTrav[VarPne] = X; + + if ( Pne->TypeDeBorneTrav[VarPne] == VARIABLE_BORNEE_SUPERIEUREMENT ) Pne->UTrav[VarPne] = -Pne->UTrav[VarPne]; + +} + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_reinit_couts_natif.c b/src/ext/Sirius_Solver/simplexe/spx_reinit_couts_natif.c new file mode 100644 index 0000000000..1efd605387 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_reinit_couts_natif.c @@ -0,0 +1,135 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On essaie de reinitialiser les couts natifs sur les variables + hors base si cela ne cree pas d'infaisabilite duale. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_fonctions.h" + +# define ITERATIONS_MIN 500 +# define ITERATIONS_MAX 1500 + +# define TRACES 1 + +/*----------------------------------------------------------------------------*/ + +void SPX_ReinitialiserLesCoutsNatifSiCestPossible( PROBLEME_SPX * Spx ) +{ +int Var; int i; char * TypeDeVariable; double * CBarre; char * PositionDeLaVariable; +double * C; double * Csv; char * CorrectionDuale; double XCBarre; int NombreDeCoutsBruite; +int NombreDeCoutesRestaures; int * NumerosDesVariablesHorsBase; double X; +double * SeuilDAmissibiliteDuale; +# if TRACES == 1 + double VolumeDeBruitage; +# endif + +return; + +if ( Spx->Iteration < Spx->ProchaineIterationDeReinitDesCouts ) return; + +Spx->A1 = PNE_Rand( Spx->A1 ); /* Nombre aleatoire entre 0 et 1 */ +X = ITERATIONS_MIN; +X += Spx->A1 * ( ITERATIONS_MAX - ITERATIONS_MIN ); +Spx->ProchaineIterationDeReinitDesCouts = (int) ceil( X ) + Spx->Iteration; + +if ( Spx->CBarreAEteCalculeParMiseAJour == OUI_SPX ) { + SPX_CalculerPi( Spx ); /* Calcul de Pi = c_B * B^{-1} */ + SPX_CalculerLesCoutsReduits( Spx ); /* Calcul de CBarre = c_N - < Pi , N > */ + Spx->CalculerCBarre = NON_SPX; +} + +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +TypeDeVariable = Spx->TypeDeVariable; +CBarre = Spx->CBarre; +PositionDeLaVariable = Spx->PositionDeLaVariable; +C = Spx->C; +Csv = Spx->Csv; +CorrectionDuale = Spx->CorrectionDuale; + +SeuilDAmissibiliteDuale = Spx->SeuilDAmissibiliteDuale1; + +NombreDeCoutsBruite = 0; +NombreDeCoutesRestaures = 0; +# if TRACES == 1 + VolumeDeBruitage = 0.0; +# endif + +/* Examen des couts reduits pour chaque type de variable */ +for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + if ( C[Var] == Csv[Var] ) continue; + NombreDeCoutsBruite++; + # if TRACES == 1 + VolumeDeBruitage += fabs( Csv[Var] - C[Var] ); + # endif + XCBarre = CBarre[Var] - C[Var] + Csv[Var]; + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + if ( XCBarre >= -SeuilDAmissibiliteDuale[Var] ) { + # if TRACES == 1 + VolumeDeBruitage -= fabs( Csv[Var] - C[Var] ); + # endif + CBarre[Var] = XCBarre; + C[Var] = Csv[Var]; + CorrectionDuale[Var] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + NombreDeCoutesRestaures++; + } + } + else if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + if ( XCBarre <= SeuilDAmissibiliteDuale[Var] ) { + # if TRACES == 1 + VolumeDeBruitage -= fabs( Csv[Var] - C[Var] ); + # endif + CBarre[Var] = XCBarre; + C[Var] = Csv[Var]; + CorrectionDuale[Var] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + NombreDeCoutesRestaures++; + } + } + else if ( PositionDeLaVariable[Var] == HORS_BASE_A_ZERO ) { + if ( fabs( XCBarre ) <= SEUIL_ADMISSIBILITE_DUALE_2 ) { + # if TRACES == 1 + VolumeDeBruitage -= fabs( Csv[Var] - C[Var] ); + # endif + CBarre[Var] = XCBarre; + C[Var] = Csv[Var]; + CorrectionDuale[Var] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + NombreDeCoutesRestaures++; + } + } +} + +#if TRACES == 1 + if ( NombreDeCoutesRestaures > 0 ) { + printf("Iteration %d , nombre de couts restaures: %d sur %d , restent %d couts bruites , volume de bruitage %e\n",Spx->Iteration,NombreDeCoutesRestaures,NombreDeCoutsBruite, + NombreDeCoutsBruite-NombreDeCoutesRestaures,VolumeDeBruitage); + } +#endif + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_resolution_de_systeme.c b/src/ext/Sirius_Solver/simplexe/spx_resolution_de_systeme.c new file mode 100644 index 0000000000..86e0e5ec18 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_resolution_de_systeme.c @@ -0,0 +1,100 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resoudre B x = b + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +/*----------------------------------------------------------------------------*/ +void SPX_ResolutionDeSysteme( PROBLEME_SPX * Spx, + char TypeDEntree, /* Mode de stockage du vecteur second membre */ + double * A , /* Second membre et solution */ + int * IndexDesTermesNonNuls, + int * NombreDeTermesNonNuls, + char * TypeDeSortie, /* Mode de stockage demande pour la solution */ + + char CalculEnHyperCreux, /* Vaut OUI_SPX ou NON_SPX */ + char Save, /* Sauvegarde ou non du resultat de la triangulaire inferieure */ + char SecondMembreCreux /* Vaut OUI_LU ou NON_LU */ + ) +{ +int CodeRetour; int NbIterRaffinement; double PrecisionDemandee; +MATRICE_A_FACTORISER Matrice; + +CodeRetour = 0; + +if ( Spx->UtiliserLaBaseReduite == NON_SPX ) { + Matrice.ValeurDesTermesDeLaMatrice = Spx->ACol; + Matrice.IndicesDeLigne = Spx->NumeroDeContrainte; + Matrice.IndexDebutDesColonnes = Spx->CdebBase; + Matrice.NbTermesDesColonnes = Spx->NbTermesDesColonnesDeLaBase; +} +else { + if ( Spx->RangDeLaMatriceFactorisee <= 0 ) return; + Matrice.ValeurDesTermesDeLaMatrice = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; + Matrice.IndicesDeLigne = Spx->IndicesDeLigneDesTermesDuProblemeReduit; + Matrice.IndexDebutDesColonnes = Spx->CdebBase; + Matrice.NbTermesDesColonnes = Spx->NbTermesDesColonnesDeLaBase; +} + +NbIterRaffinement = 0; +if ( Spx->UtiliserLaLuUpdate == OUI_SPX ) { + if ( Spx->FaireDuRaffinementIteratif > 0 ) { + NbIterRaffinement = 1; + + printf("SPX_ResolutionDeSysteme raffinement iteratif sur le systeme reduit\n"); + + } +} + +PrecisionDemandee = SEUIL_DE_VIOLATION_DE_BORNE; + +if ( Spx->UtiliserLaLuUpdate != OUI_SPX ) Save = NON_LU; + +if ( CalculEnHyperCreux == NON_SPX ) { + /* On appelle toujours LU_LuSolvLuUpdate qui de toutes facons appelle LU_LuSolv. + Mais si on ne fait pas de LuUpdate, on force Save a NON_LU */ + LU_LuSolvLuUpdate( Spx->MatriceFactorisee, A, &CodeRetour, Save, SecondMembreCreux, + &Matrice, NbIterRaffinement, PrecisionDemandee ); + +} +else { + LU_LuSolvSecondMembreHyperCreux( Spx->MatriceFactorisee, A, IndexDesTermesNonNuls, + NombreDeTermesNonNuls, TypeDEntree, Save, TypeDeSortie ); +} + +if ( CodeRetour == PRECISION_DE_RESOLUTION_NON_ATTEINTE ) { + /* Tant pis on continue quand-meme */ + CodeRetour = 0; +} + +return; +} + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_resolution_de_systeme_transposee.c b/src/ext/Sirius_Solver/simplexe/spx_resolution_de_systeme_transposee.c new file mode 100644 index 0000000000..6d5611f289 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_resolution_de_systeme_transposee.c @@ -0,0 +1,99 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution de systeme avec B transposee. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +/*----------------------------------------------------------------------------*/ +void SPX_ResolutionDeSystemeTransposee( PROBLEME_SPX * Spx, + char TypeDEntree, /* Mode de stockage du vecteur second membre */ + double * U, /* Second membre et resultat */ + int * IndexDesTermesNonNuls, + int * NombreDeTermesNonNuls, + + char * TypeDeSortie, + char CalculEnHyperCreux, /* Vaut OUI_SPX ou NON_SPX */ + char SecondMembreCreux /* Vaut OUI_LU ou NON_LU */ + ) +{ +int CodeRetour; int NbIterRaffinement; double PrecisionDemandee; +MATRICE_A_FACTORISER Matrice; + +CodeRetour = 0; + +if ( Spx->UtiliserLaBaseReduite == NON_SPX ) { + Matrice.ValeurDesTermesDeLaMatrice = Spx->ACol; + Matrice.IndicesDeLigne = Spx->NumeroDeContrainte; + Matrice.IndexDebutDesColonnes = Spx->CdebBase; + Matrice.NbTermesDesColonnes = Spx->NbTermesDesColonnesDeLaBase; +} +else { + if ( Spx->RangDeLaMatriceFactorisee <= 0 ) return; + Matrice.ValeurDesTermesDeLaMatrice = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; + Matrice.IndicesDeLigne = Spx->IndicesDeLigneDesTermesDuProblemeReduit; + Matrice.IndexDebutDesColonnes = Spx->CdebBase; + Matrice.NbTermesDesColonnes = Spx->NbTermesDesColonnesDeLaBase; +} + +/* Attention: on peut faire du raffinement en faisant attention y compris si pas LuUpdate */ + +NbIterRaffinement = 0; +if ( Spx->UtiliserLaLuUpdate == OUI_SPX ) { + if ( Spx->FaireDuRaffinementIteratif > 0 ) { + NbIterRaffinement = 1; + + printf("SPX_ResolutionDeSystemeTransposee raffinement iteratif sur le systeme reduit\n"); + + } +} +PrecisionDemandee = SEUIL_ADMISSIBILITE_DUALE_2; + +if ( CalculEnHyperCreux == NON_SPX ) { + /* On appelle toujours LU_LuSolvTransposeeLuUpdate qui de toutes facons + appelle LU_LuSolvTransposee */ + LU_LuSolvTransposeeLuUpdate( Spx->MatriceFactorisee, + U, /* Le vecteur second membre et solution */ + &CodeRetour, /* Le code retour ( 0 si tout s'est bien passe ) */ + SecondMembreCreux, + &Matrice, NbIterRaffinement, PrecisionDemandee + ); +} +else { + LU_LuSolvTransposeeSecondMembreHyperCreux( Spx->MatriceFactorisee, U, IndexDesTermesNonNuls, + NombreDeTermesNonNuls, TypeDEntree, TypeDeSortie ); +} + +if ( CodeRetour == PRECISION_DE_RESOLUTION_NON_ATTEINTE ) { + /* Tant pis on continue quand-meme */ + CodeRetour = 0; +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_resoudre_by_egal_a.c b/src/ext/Sirius_Solver/simplexe/spx_resoudre_by_egal_a.c new file mode 100644 index 0000000000..1947182060 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_resoudre_by_egal_a.c @@ -0,0 +1,62 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resoudre B y = a en utilisant la forme produit de + l'inverse si necessaire. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_ResoudreBYegalA( PROBLEME_SPX * Spx, + char TypeDEntree, /* Mode de stockage du vecteur second membre */ + double * A, /* Second membre et solution */ + int * IndexDesTermesNonNuls, + int * NombreDeTermesNonNuls, + char * TypeDeSortie, /* Mode de stockage demande pour la solution */ + + char CalculEnHyperCreux, /* Vaut OUI_SPX ou NON_SPX */ + char Save, /* Sauvegarde ou non du resultat de la triangulaire inferieure */ + char SecondMembreCreux /* Vaut OUI_LU ou NON_LU */ + ) +{ +/* Il faut d'abord resoudre B y = a en prenant pour B la derniere base factorisee + et eventuellement appliquer les eta vecteurs dans le cas de la forme produit de + l'inverse */ + +SPX_ResolutionDeSysteme( Spx, TypeDEntree, A, IndexDesTermesNonNuls, NombreDeTermesNonNuls, + TypeDeSortie, CalculEnHyperCreux, Save, SecondMembreCreux ); + +/* Si necessaire, on applique les eta vecteurs (cas: forme produit de l'inverse) */ +if ( Spx->UtiliserLaLuUpdate == OUI_SPX ) return; + +SPX_AppliquerLesEtaVecteurs( Spx, A, IndexDesTermesNonNuls, NombreDeTermesNonNuls, CalculEnHyperCreux, *TypeDeSortie ); + +/* On ne cherche pas a passer en mode plein apres application des eta vecteurs */ + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_resoudre_ub_egal_c.c b/src/ext/Sirius_Solver/simplexe/spx_resoudre_ub_egal_c.c new file mode 100644 index 0000000000..c112f7c074 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_resoudre_ub_egal_c.c @@ -0,0 +1,58 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Calcul de pi = Cb * B_MOINS_1 c'est a dire + resolution de u B = c + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "lu_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_ResoudreUBEgalC( PROBLEME_SPX * Spx, + char TypeDEntree, /* Mode de stockage du vecteur second membre */ + double * U, /* Second membre et resultat */ + int * IndexDesTermesNonNuls, + int * NombreDeTermesNonNuls, + char * TypeDeSortie, + char CalculEnHyperCreux /* Vaut OUI_SPX ou NON_SPX */ + ) +{ +char SecondMembreCreux; + +if ( Spx->UtiliserLaLuUpdate == NON_SPX ) { + SPX_AppliquerLesEtaVecteursTransposee( Spx, U, IndexDesTermesNonNuls, NombreDeTermesNonNuls, + CalculEnHyperCreux, TypeDEntree ); +} + +/* Terminer par la resolution avec la derniere base factorisee */ + +SecondMembreCreux = NON_LU; +SPX_ResolutionDeSystemeTransposee( Spx, TypeDEntree, U, IndexDesTermesNonNuls, NombreDeTermesNonNuls, + TypeDeSortie, CalculEnHyperCreux, SecondMembreCreux ); + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_sauvegardes_branch_and_bound.c b/src/ext/Sirius_Solver/simplexe/spx_sauvegardes_branch_and_bound.c new file mode 100644 index 0000000000..ef2e398675 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_sauvegardes_branch_and_bound.c @@ -0,0 +1,75 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Translater les bornes en sortie pour tout remettre + en ordre + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_SauvegardesBranchAndBoundAndCut( PROBLEME_SPX * Spx ) +{ + int Cnt; int Var; /*int i;*/ + +/* Sauvegardes pour le strong branching */ + +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + Spx->XSV [Var] = Spx->X[Var]; + Spx->PositionDeLaVariableSV [Var] = Spx->PositionDeLaVariable[Var]; + Spx->CBarreSV [Var] = Spx->CBarre[Var]; + Spx->InDualFrameworkSV [Var] = Spx->InDualFramework[Var]; + Spx->ContrainteDeLaVariableEnBaseSV[Var] = Spx->ContrainteDeLaVariableEnBase[Var]; +} + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + Spx->BBarreSV [Cnt] = Spx->BBarre[Cnt]; + Spx->DualPoidsSV [Cnt] = Spx->DualPoids[Cnt]; + Spx->VariableEnBaseDeLaContrainteSV[Cnt] = Spx->VariableEnBaseDeLaContrainte[Cnt]; + Spx->CdebBaseSV [Cnt] = Spx->CdebBase[Cnt]; + Spx->NbTermesDesColonnesDeLaBaseSV [Cnt] = Spx->NbTermesDesColonnesDeLaBase[Cnt]; +} + +return; +} + + + + + + + + + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_scaling.c b/src/ext/Sirius_Solver/simplexe/spx_scaling.c new file mode 100644 index 0000000000..c586a9983e --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_scaling.c @@ -0,0 +1,982 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Scaling + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_fonctions.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +# define SEUIL_ADMISSIBILITE_FONCTION_DE_LA_MATRICE OUI_SPX /*OUI_SPX*/ +# define SEUIL_ADMISSIBILITE_DUALE_FONCTION_DU_SCALING OUI_SPX /*OUI_SPX*/ + +# define NOMBRE_MAX_DE_PASSES_DE_SCALING 20 /* 20 */ +# define MIN_DE_PASSES_DE_SCALING 5 +# define ARRONDI_EN_PUISSANCES_DE_2 OUI_SPX /* OUI_SPX */ + +# define RAPPORT_INHIBITION_SCALING 1000. +# define RAPPORT_INHIBITION_SCALING_EN_SERVICE OUI_SPX /* OUI_SPX */ + +/* Permet de faire un equilibrage apres la moyenne geometrique. Consiste a diviser + iterativement les lignes et colonnes par la norme L infini (abs du plus grand terme) + de la ligne ou de la colonne */ +# define EQUILIBRAGE_APRES_MOYENNE_GEOMETRIQUE OUI_SPX /*OUI_SPX*/ +# define SEUIL_POUR_EQUILIBRAGE_MATRICE 10. /* 10. */ /* Seuil a partir duquel on fait un equilibrage de la matrice */ +# define ARRONDI_EN_PUISSANCES_DE_2_POUR_EQUILIBRAGE OUI_SPX /* NON_SPX*/ + /* l'arrondi n'est peut-etre pas necessaire car on ne fait generalement */ + /* pas plus de 2 passes */ +# define SEUIL_ECART_UN 1.e-1 /* Permet de sortir prematurement de la boucle d'equilibrage de la matrice */ + +# define ZERO 1.e-12 /*1.e-12*/ + +# define RAPPORT_MAX_COUTS 1.e+4 /*1.e+5*/ +# define RAPPORT_INACCEPTABLE_COUTS (100*RAPPORT_MAX_COUTS) /*1.e+9*/ + +# define DEGRADATION_MAX_DU_RAPPORT 10 /*10*/ +# define RAPPORT_ACCEPTABLE 1.e+4 /*1.e+4*/ + +# define MIN_SCALE_LIGNE_COUTS 1.e-6 /*1.e-6*/ + + +# define VERBOSE_SPX_SCALING 0 + + +void SPX_InitMatriceEtCoutsAvantScaling( PROBLEME_SPX *, double * , double * ); +void SPX_AppliquerScalingSurMatriceDeTravail( PROBLEME_SPX * , double *, double * ); + +/*----------------------------------------------------------------------------*/ + +void SPX_InitMatriceEtCoutsAvantScaling( PROBLEME_SPX * Spx, double * A, double * C ) +{ +int il; int ilMax; int Cnt; int Var; int * Mdeb; int * NbTerm; double * ScaleX; +double * Aspx; double * Cspx; int NombreDeVariables; int NombreDeContraintes; +double * ScaleB; + +NombreDeVariables = Spx->NombreDeVariables; +NombreDeContraintes = Spx->NombreDeContraintes; +Aspx = Spx->A; +Cspx = Spx->Csv; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +ScaleX = Spx->ScaleX; +ScaleB = Spx->ScaleB; +Spx->ScaleLigneDesCouts = 1.; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + ScaleX[Var] = 1.; + C[Var] = fabs( Cspx[Var] ); +} +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + ScaleB[Cnt ] = 1.; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + A[il] = fabs( Aspx[il] ); + il++; + } +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_AppliquerScalingSurMatriceDeTravail( PROBLEME_SPX * Spx, double * A, double * C ) +{ +int il; int ilMax; int Cnt; int Var; int * Mdeb; int * NbTerm; double * ScaleX; +double * Aspx; double * Cspx; int NombreDeVariables; int NombreDeContraintes; +double * ScaleB; int * Indcol; double ScaleLigneDesCouts; + +NombreDeVariables = Spx->NombreDeVariables; +NombreDeContraintes = Spx->NombreDeContraintes; +ScaleLigneDesCouts = Spx->ScaleLigneDesCouts; +Aspx = Spx->A; +Cspx = Spx->Csv; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +ScaleX = Spx->ScaleX; +ScaleB = Spx->ScaleB; + +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) C[Var] = fabs( Cspx[Var] ) * ScaleX[Var] * ScaleLigneDesCouts; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + A[il] = fabs( Aspx[il] ) * ScaleB[Cnt] * ScaleX[Indcol[il]]; + il++; + } +} +return; +} + +/*----------------------------------------------------------------------------*/ + +void SPX_CalculerLeScaling( PROBLEME_SPX * Spx ) +{ +int il; int ilMax; int k; double X; double UnSurX; int Phase; double PlusGrandTerme; +double PlusPetitTerme; double Rapport; int Flag; double RapportPrecedent; double SeuilRapport; +double * A; double * C; int NombreDeVariables; int NombreDeContraintes; double ScaleLigneDesCoutsOpt; +double PlusGrandTermeCouts; double PlusPetitTermeCouts; double * ScaleXOpt; double * ScaleBOpt; +char FaireScalingDesCouts; char EquilibrageApresMoyenneGeometrique; char LignesOk; +char ColonnesOk; int kMin; double RapportOpt; double * ScaleX ; double * ScaleB; +double ScaleLigneDesCouts; double * XMult; double * PlusGrandTermeColonne; double * PlusPetitTermeColonne; +int * Mdeb; int * NbTerm; int * Indcol; double RapportIntialDesCouts; double RapportOptCouts; +int Var; int Cnt; + +if ( Spx->FaireDuScalingSPX == NON_SPX ) return; + +NombreDeVariables = Spx->NombreDeVariables; +NombreDeContraintes = Spx->NombreDeContraintes; + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; + +A = (double *) malloc( Spx->NbTermesAlloues * sizeof( double ) ); +C = (double *) malloc( NombreDeVariables * sizeof( double ) ); +ScaleX = (double *) malloc( NombreDeVariables * sizeof( double ) ); + +PlusGrandTermeColonne = (double *) malloc( NombreDeVariables * sizeof( double ) ); +PlusPetitTermeColonne = (double *) malloc( NombreDeVariables * sizeof( double ) ); +XMult = (double *) malloc( NombreDeVariables * sizeof( double ) ); + +ScaleB = (double *) malloc( NombreDeContraintes * sizeof( double ) ); + +ScaleXOpt = (double *) malloc( NombreDeVariables * sizeof( double ) ); +ScaleBOpt = (double *) malloc( NombreDeContraintes * sizeof( double ) ); + +if ( A == NULL || C == NULL || ScaleX == NULL || PlusGrandTermeColonne == NULL || PlusPetitTermeColonne == NULL || + XMult == NULL || ScaleB == NULL || ScaleXOpt == NULL || ScaleBOpt == NULL ) { + printf("Simplexe, sous-programme SPX_FaireScaling : \n"); + printf(" -> memoire insuffisante pour l allocation de l espace de travail \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); +} + +SPX_InitMatriceEtCoutsAvantScaling( Spx, A, C ); + +PlusGrandTermeCouts = -1.; +PlusPetitTermeCouts = LINFINI_SPX; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if ( C[Var] == 0.0 ) continue; + if ( C[Var] < PlusPetitTermeCouts ) PlusPetitTermeCouts = C[Var]; + if ( C[Var] > PlusGrandTermeCouts ) PlusGrandTermeCouts = C[Var]; +} + +RapportIntialDesCouts = 1.; +if ( PlusPetitTermeCouts < LINFINI_SPX ) RapportIntialDesCouts = PlusGrandTermeCouts / PlusPetitTermeCouts; + +EquilibrageApresMoyenneGeometrique = EQUILIBRAGE_APRES_MOYENNE_GEOMETRIQUE; + +RapportPrecedent = 0.0; +ScaleLigneDesCouts = 1.0; +SeuilRapport = 1.e-6; + +FaireScalingDesCouts = NON_SPX; +kMin = 1; +Phase = 1; + +RapportOpt = LINFINI_PNE; /* Juste pour eviter les warning de compilation */ +RapportOptCouts = LINFINI_PNE; /* Juste pour eviter les warning de compilation */ +ScaleLigneDesCoutsOpt = 1; /* Juste pour eviter les warning de compilation */ + +DebutDesPassesDeScaling: +/* Plusieurs passes */ + +for ( k = 0 ; k < NOMBRE_MAX_DE_PASSES_DE_SCALING ; k++ ) { + + /* Controle du conditionnement avant la passe de scaling */ + PlusGrandTermeCouts = -1.; + PlusPetitTermeCouts = LINFINI_SPX; + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_SPX; + for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + X = A[il]; + if( X != 0.0 ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + il++; + } + } + + Rapport = PlusGrandTerme / PlusPetitTerme; + + #if VERBOSE_SPX_SCALING == 1 + printf(" Avant passe de scaling PlusPetitTerme %20.10lf PlusGrandTerme %20.10lf rapport %20.10lf \n",PlusPetitTerme,PlusGrandTerme,Rapport); + #endif + + if ( k == 0 ) { + if ( Rapport < RAPPORT_INHIBITION_SCALING && RAPPORT_INHIBITION_SCALING_EN_SERVICE == OUI_SPX && Phase == 1 ) { + #if VERBOSE_SPX_SCALING == 1 + printf("Rapport des termes de la matrice %e RAPPORT_INHIBITION_SCALING %e => on ne fait pas de scaling sur la matrice\n", + Rapport, RAPPORT_INHIBITION_SCALING); + # endif + break; + } + } + + if ( k >= kMin ) { + if ( fabs ( RapportPrecedent - Rapport ) < SeuilRapport * RapportPrecedent ) { + break; + } + if ( RapportPrecedent < Rapport ) { + /* On recupere les coeff de l'etape precedente et on arrete */ + Spx->ScaleLigneDesCouts = ScaleLigneDesCouts; + memcpy( (char *) Spx->ScaleX, (char *) ScaleX, Spx->NombreDeVariables * sizeof( double ) ); + memcpy( (char *) Spx->ScaleB, (char *) ScaleB, Spx->NombreDeContraintes * sizeof( double ) ); + break; + } + } + + RapportPrecedent = Rapport; + + /* Stockage du scaling precedent */ + ScaleLigneDesCouts = Spx->ScaleLigneDesCouts; + memcpy( (char *) ScaleX, (char *) Spx->ScaleX, NombreDeVariables * sizeof( double ) ); + memcpy( (char *) ScaleB, (char *) Spx->ScaleB, NombreDeContraintes * sizeof( double ) ); + + /*-------------------- Scaling des lignes ------------------------*/ + + /* On regarde les couts pour savoir s'il est necessaire de faire un scaling dessus */ + if ( FaireScalingDesCouts == OUI_SPX ) { + Flag = 0; + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_SPX; + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + X = C[Var]; + if( X != 0.0 ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) { PlusPetitTerme = X; Flag = 1; } + } + } + if ( Flag == 1 ) { + FaireScalingDesCouts = OUI_SPX; + X = PlusGrandTerme * PlusPetitTerme; + X = sqrt( X ); + UnSurX = 1. / X; + if ( ARRONDI_EN_PUISSANCES_DE_2 == OUI_SPX ) SPX_ArrondiEnPuissanceDe2( &UnSurX ); + Spx->ScaleLigneDesCouts *= UnSurX; + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) C[Var] *= UnSurX; + } + } + + /* Lignes */ + for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + Flag = 0; + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_SPX; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + X = A[il]; + if( X != 0.0 ) { + if ( X > PlusGrandTerme ) { PlusGrandTerme = X; Flag = 1; } + if ( X < PlusPetitTerme ) { PlusPetitTerme = X; Flag = 1; } + } + il++; + } + X = 1.; + UnSurX = 1.; + if ( Flag == 1 ) { + X = PlusGrandTerme * PlusPetitTerme; + X = sqrt( X ); + UnSurX = 1. / X; + } + + if ( ARRONDI_EN_PUISSANCES_DE_2 == OUI_SPX ) SPX_ArrondiEnPuissanceDe2( &UnSurX ); + + Spx->ScaleB[Cnt] *= UnSurX; + + /* Scaling de A */ + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + A[il] *= UnSurX; + il++; + } + } + + /*-------------------- Scaling des colonnes ------------------------*/ + + /* Recherche PlusPetitTerme PlusGrandTerme */ + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + PlusGrandTermeColonne[Var] = -1.; + PlusPetitTermeColonne[Var] = LINFINI_SPX; + } + + for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + X = A[il]; + if( X != 0.0 ) { + if ( X > PlusGrandTermeColonne[Indcol[il]] ) PlusGrandTermeColonne[Indcol[il]] = X; + if ( X < PlusPetitTermeColonne[Indcol[il]] ) PlusPetitTermeColonne[Indcol[il]] = X; + } + il++; + } + } + /* Objectif */ + if ( FaireScalingDesCouts == OUI_SPX ) { + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + X = C[Var]; + if( X != 0.0 ) { + if ( X > PlusGrandTermeColonne[Var] ) PlusGrandTermeColonne[Var] = X; + if ( X < PlusPetitTermeColonne[Var] ) PlusPetitTermeColonne[Var] = X; + } + } + } + + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + X = 1.; + UnSurX = 1.; + if ( PlusGrandTermeColonne[Var] > 0.0 && PlusPetitTermeColonne[Var] < LINFINI_SPX ) { + X = PlusGrandTermeColonne[Var] * PlusPetitTermeColonne[Var]; + X = sqrt( X ); + UnSurX = 1. / X; + } + if ( ARRONDI_EN_PUISSANCES_DE_2 == OUI_SPX ) SPX_ArrondiEnPuissanceDe2( &UnSurX ); + + XMult[Var] = UnSurX; + Spx->ScaleX[Var] *= UnSurX; + /* Scaling du cout */ + C[Var] *= UnSurX; + } + + /* Application de la participation au scaling de A */ + for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + A[il] *= XMult[Indcol[il]]; + il++; + } + } + +/* Fin Boucle generale de scaling */ +} + +if ( EquilibrageApresMoyenneGeometrique == OUI_SPX && Rapport > SEUIL_POUR_EQUILIBRAGE_MATRICE ) { + + # if VERBOSE_SPX_SCALING == 1 + printf("Phase d'equilibrage ...\n"); + # endif + + /* Il faut appliquer le scaling obtenu juste avant car les coeff de scaling ne correspondent pas toujours a + l'etat de la matrice */ + SPX_AppliquerScalingSurMatriceDeTravail( Spx, A, C ); + + for ( k = 0 ; k < NOMBRE_MAX_DE_PASSES_DE_SCALING ; k++ ) { + + LignesOk = OUI_SPX; + ColonnesOk = OUI_SPX; + + if ( FaireScalingDesCouts == OUI_SPX ) { + Flag = 0; + PlusGrandTerme = -1.; + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + X = C[Var]; + if( X != 0.0 ) { + if ( X > PlusGrandTerme ) { PlusGrandTerme = X; Flag = 1; } + } + } + if ( Flag == 1 ) { + X = PlusGrandTerme; + UnSurX = 1. / X; + if ( ARRONDI_EN_PUISSANCES_DE_2 == OUI_SPX ) SPX_ArrondiEnPuissanceDe2( &UnSurX ); + Spx->ScaleLigneDesCouts *= UnSurX; + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) C[Var] *= UnSurX; + } + } + + /* Lignes */ + for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + PlusGrandTerme = -1.; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( A[il] > PlusGrandTerme ) PlusGrandTerme = A[il]; + il++; + } + if ( fabs( PlusGrandTerme - 1.0 ) > SEUIL_ECART_UN ) LignesOk = NON_SPX; + + X = 1; + UnSurX = 1; + if ( PlusGrandTerme > 0 ) { + X = PlusGrandTerme; + UnSurX = 1. / X; + } + + if ( ARRONDI_EN_PUISSANCES_DE_2_POUR_EQUILIBRAGE == OUI_SPX ) SPX_ArrondiEnPuissanceDe2( &UnSurX ); + + Spx->ScaleB[Cnt] *= UnSurX; + + /* Scaling de A */ + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + A[il] *= UnSurX; + il++; + } + } + + /* Colonnes */ + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) PlusGrandTermeColonne[Var] = -1.; + + for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( A[il] > PlusGrandTermeColonne[Indcol[il]] ) PlusGrandTermeColonne[Indcol[il]] = A[il]; + il++; + } + } + + if ( FaireScalingDesCouts == OUI_SPX ) { + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + X = C[Var]; + if( X != 0.0 ) { + if ( X > PlusGrandTermeColonne[Var] ) PlusGrandTermeColonne[Var] = X; + } + } + } + + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + X = PlusGrandTermeColonne[Var]; + if ( X <= 0.0 ) continue; + if ( fabs( X - 1.0 ) > SEUIL_ECART_UN ) ColonnesOk = NON_SPX; + + UnSurX = 1.; + if ( X > 0 ) { + UnSurX = 1. / X; + } + if ( ARRONDI_EN_PUISSANCES_DE_2_POUR_EQUILIBRAGE == OUI_SPX ) SPX_ArrondiEnPuissanceDe2( &UnSurX ); + + XMult[Var] = UnSurX; + Spx->ScaleX[Var] *= UnSurX; + + /* Scaling du cout */ + C[Var] *= UnSurX; + } + /* Application de la participation au scaling de A */ + for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + A[il] *= XMult[Indcol[il]]; + il++; + } + } + + if ( LignesOk == OUI_SPX && ColonnesOk == OUI_SPX ) break; + + } + +} + +/* Recalcul du rapport */ +PlusGrandTerme = -1.; +PlusPetitTerme = LINFINI_SPX; +for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + X = A[il]; + if( X != 0.0 ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + il++; + } +} + +# if VERBOSE_SPX_SCALING == 1 + printf("Apres equilibrage eventuel:\n"); + printf(" Matrice: PlusPetitTerme %e PlusGrandTerme %e Rapport %e\n",PlusPetitTerme,PlusGrandTerme,PlusGrandTerme/PlusPetitTerme); + printf(" ScaleLigneDesCouts: %e\n",Spx->ScaleLigneDesCouts); +# endif + +if ( Phase == 1 ) { + /* Stockage des coeff de scaling et calcul du rapport obtenu sur les termes de la matrice */ + RapportOpt = PlusGrandTerme / PlusPetitTerme; + ScaleLigneDesCoutsOpt = Spx->ScaleLigneDesCouts; + memcpy( (char *) ScaleXOpt, (char *) Spx->ScaleX, Spx->NombreDeVariables * sizeof( double ) ); + memcpy( (char *) ScaleBOpt, (char *) Spx->ScaleB, Spx->NombreDeContraintes * sizeof( double ) ); +} +else { + + /*Spx->ScaleLigneDesCouts = 1;*/ + + if ( Spx->ScaleLigneDesCouts < MIN_SCALE_LIGNE_COUTS ) Spx->ScaleLigneDesCouts = MIN_SCALE_LIGNE_COUTS; + + Rapport = PlusGrandTerme / PlusPetitTerme; + if ( Rapport > DEGRADATION_MAX_DU_RAPPORT * RapportOpt && Rapport > RAPPORT_ACCEPTABLE && RapportOptCouts < RAPPORT_INACCEPTABLE_COUTS ) { + /* Le rapport s'est trop degrade on conserve les premiers coefficients */ + # if VERBOSE_SPX_SCALING == 1 + printf("Prise en compte des couts dans le scaling:\n"); + printf(" Matrice: PlusPetitTerme %e PlusGrandTerme %e Rapport %e\n",PlusPetitTerme,PlusGrandTerme,PlusGrandTerme/PlusPetitTerme); + PlusGrandTerme = -1.; + PlusPetitTerme = LINFINI_SPX; + for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + X = C[Var]; + if( X != 0.0 ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + } + Rapport = PlusGrandTerme / PlusPetitTerme; + printf(" Couts: PlusPetitTerme %e PlusGrandTerme %e Rapport %e\n",PlusPetitTerme,PlusGrandTerme,PlusGrandTerme/PlusPetitTerme); + printf(" Le rapport sur la matrice se degrade trop => on prend les coeffs de scaling de la premiers passe (sans le scaling des couts)\n"); + # endif + Spx->ScaleLigneDesCouts = ScaleLigneDesCoutsOpt; + memcpy( (char *) Spx->ScaleX, (char *) ScaleXOpt, Spx->NombreDeVariables * sizeof( double ) ); + memcpy( (char *) Spx->ScaleB, (char *) ScaleBOpt, Spx->NombreDeContraintes * sizeof( double ) ); + goto FinScaling; + } +} + +Phase++; + +/* Controle du scaling resultant des cout: si le rapport est trop grand, on refait un scaling + en tenant compte des cout */ + +PlusGrandTerme = -1.; +PlusPetitTerme = LINFINI_SPX; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + X = C[Var]; + if( X != 0.0 ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } +} +Rapport = PlusGrandTerme / PlusPetitTerme; +RapportOptCouts = Rapport; + +# if VERBOSE_SPX_SCALING == 1 + printf(" Couts: PlusPetitTerme %e PlusGrandTerme %e Rapport %e Rapport initial %e\n",PlusPetitTerme,PlusGrandTerme, + Rapport,RapportIntialDesCouts); +# endif + +if ( FaireScalingDesCouts == NON_SPX ) { + Rapport = PlusGrandTerme / PlusPetitTerme; + if ( Rapport > RAPPORT_MAX_COUTS && Rapport > RapportIntialDesCouts ) { + # if VERBOSE_SPX_SCALING == 1 + printf(" Rapport des couts / Rapport initial trop degrade . On refait un scaling avec les couts \n"); + # endif + FaireScalingDesCouts = OUI_SPX; + kMin = 2; + + /* On reinitialise la matrice et les coefficients de scaling */ + SPX_InitMatriceEtCoutsAvantScaling( Spx, A, C ); + + goto DebutDesPassesDeScaling; + } + else { + # if VERBOSE_SPX_SCALING == 1 + printf(" Pas de scaling des couts \n"); + # endif + } +} + +/* Si le cout max est inferieur a 1 on le remonte a 1 */ +PlusGrandTerme = -1; +for ( Var = 0 ; Var < NombreDeVariables ; Var++ ) { + if( C[Var] != 0.0 ) { + if ( C[Var] > PlusGrandTerme ) PlusGrandTerme = C[Var]; + } +} + +if ( PlusGrandTerme > 0 ) { + if ( PlusGrandTerme < 10 ) Spx->ScaleLigneDesCouts *= 10./PlusGrandTerme; + else if ( PlusGrandTerme > 1000. ) Spx->ScaleLigneDesCouts *= 1000./PlusGrandTerme; +} + +FinScaling: + +/* Liberation memoire */ +free( A ); +free( C ); +free( PlusGrandTermeColonne ); +free( PlusPetitTermeColonne ); +free( XMult ); +free( ScaleX ); +free( ScaleB ); +free( ScaleXOpt ); +free( ScaleBOpt ); + +return; +} + +/*------------------------------------------------------------------------*/ + +void SPX_ArrondiEnPuissanceDe2( double * ValeurRetenue ) +{ +double X; double ValeurPuissanceInferieure; double ValeurPuissanceSuperieure; int P2; + +X = *ValeurRetenue; +frexp( X , &P2 ); + +ValeurPuissanceInferieure = ldexp( 1. , P2-1 ); +ValeurPuissanceSuperieure = ldexp( 1. , P2 ); + +if ( fabs( X - ValeurPuissanceInferieure ) > fabs ( X - ValeurPuissanceSuperieure ) ) { + *ValeurRetenue = ValeurPuissanceSuperieure; +} +else { + *ValeurRetenue = ValeurPuissanceInferieure; +} + +return; +} + +/*------------------------------------------------------------------------*/ +/* Scaling */ +/* Apres avoir calcule les matrices de scaling, on fait le scaling. */ + +void SPX_Scaling( PROBLEME_SPX * Spx ) +{ +int i; int il; int ilMax; double X; double UnSurX; double Seuil; double PlusGrandTerme; +double PlusPetitTerme; int Var; double * InfScaleBSurA; double ScaleLigneDesCouts; +#if VERBOSE_SPX_SCALING == 1 + double Rapport; +# endif +double UnSurXFoisUnSurSupXmax ; int * Mdeb; int * NbTerm; int * Indcol; double * A; +char * TypeDeVariable; double * ScaleX; double * Csv ; double * XArray; double * Xmin ; +double * Xmax; double * SeuilDeViolationDeBorne; double * B; double * ScaleB; double ScB; +double MoyenneB; int Nmoy; char SeuilDeViolationdeBorneFonctionDeLaMatrice; +char SeuilDAmissibiliteDualeFonctionDuScaling; double Smin1; double Smax1; double Smin2; +double Smax2; double * SeuilDAmissibiliteDuale1; double * SeuilDAmissibiliteDuale2; + +if ( Spx->FaireDuScalingSPX == NON_SPX ) { + + # ifdef UTILISER_BORNES_AUXILIAIRES + /* On calcule quand-meme la valeur moyenne du second membre */ + B = Spx->B; + MoyenneB = 0.0; + Nmoy = 0; + for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + if ( B[i] != 0.0 ) { + MoyenneB+= fabs( B[i] ); + Nmoy++; + } + } + Spx->ValeurMoyenneDuSecondMembre = MoyenneB / Nmoy; + # endif + + return; +} + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; + +ScaleX = Spx->ScaleX; +Csv = Spx->Csv; +XArray = Spx->X; +Xmin = Spx->Xmin; +Xmax = Spx->Xmax; +SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; + +TypeDeVariable = Spx->TypeDeVariable; + +B = Spx->B; +ScaleB = Spx->ScaleB; + +ScaleLigneDesCouts = Spx->ScaleLigneDesCouts; + +MoyenneB = 0.0; +Nmoy = 0; + +/* Maintenant on fait le scaling effectif */ +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + X = ScaleX[i]; + UnSurX = 1. / X; + /* Scaling du cout */ + Csv[i]*= X; + /* Scaling des variables */ + UnSurXFoisUnSurSupXmax = UnSurX; + if ( TypeDeVariable[i] != NON_BORNEE ) Xmin[i]*= UnSurXFoisUnSurSupXmax; + if ( TypeDeVariable[i] == BORNEE ) Xmax[i]*= UnSurXFoisUnSurSupXmax; + /* Ne concerne que les variables natives */ + Seuil = SeuilDeViolationDeBorne[i] * UnSurXFoisUnSurSupXmax; + if ( Seuil < SEUIL_MIN_DE_VIOLATION_DE_BORNE ) Seuil = SEUIL_MIN_DE_VIOLATION_DE_BORNE; + else if ( Seuil > SEUIL_MAX_DE_VIOLATION_DE_BORNE ) Seuil = SEUIL_MAX_DE_VIOLATION_DE_BORNE; + SeuilDeViolationDeBorne[i] = Seuil; +} + +/* Scaling vertical de A */ +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + A[il] *= ScaleX[Indcol[il]]; + il++; + } +} + +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) Csv[i] *= ScaleLigneDesCouts; + +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + X = ScaleB[i]; + /* Scaling de B */ + B[i] *= X; + if ( B[i] != 0.0 ) { + MoyenneB+= fabs( B[i] ); + Nmoy++; + } + /* Scaling de A */ + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + A[il] *= X; + il++; + } +} + +Spx->ValeurMoyenneDuSecondMembre = MoyenneB / (Nmoy+1.e-6); /* Pour eviter les divisions pas 0 */ + +SeuilDAmissibiliteDualeFonctionDuScaling = SEUIL_ADMISSIBILITE_DUALE_FONCTION_DU_SCALING; +if ( SeuilDAmissibiliteDualeFonctionDuScaling == OUI_SPX ) { + Smin1 = COEFF_MIN_SEUIL_DUAL * SEUIL_ADMISSIBILITE_DUALE_1; + Smax1 = COEFF_MAX_SEUIL_DUAL * SEUIL_ADMISSIBILITE_DUALE_1; + Smin2 = COEFF_MIN_SEUIL_DUAL * SEUIL_ADMISSIBILITE_DUALE_2; + Smax2 = COEFF_MAX_SEUIL_DUAL * SEUIL_ADMISSIBILITE_DUALE_2; + + SeuilDAmissibiliteDuale1 = Spx->SeuilDAmissibiliteDuale1; + SeuilDAmissibiliteDuale2 = Spx->SeuilDAmissibiliteDuale2; + for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + X = SEUIL_ADMISSIBILITE_DUALE_1 * ScaleLigneDesCouts * ScaleX[i]; + if ( X < Smin1 ) { + /*printf("Ecretage %e -> %e\n",X,Smin1);*/ + X = Smin1; + } + else if ( X > Smax1 ) { + /*printf("Ecretage %e -> %e\n",X,Smax1);*/ + X = Smax1; + } + SeuilDAmissibiliteDuale1[i] = X; + /* printf("SeuilDAmissibiliteDuale1[%d] = %e\n",i,SeuilDAmissibiliteDuale1[i]); */ + X = SEUIL_ADMISSIBILITE_DUALE_2 * ScaleLigneDesCouts * ScaleX[i]; + if ( X < Smin2 ) { + /*printf("Ecretage %e -> %e\n",X,Smin2 );*/ + X = Smin2; + } + else if ( X > Smax2 ) { + /*printf("Ecretage %e -> %e\n",X,Smax2);*/ + X = Smax2; + } + SeuilDAmissibiliteDuale2[i] = X; + /* printf("SeuilDAmissibiliteDuale2[%d] = %e\n",i,SeuilDAmissibiliteDuale2[i]); */ + } +} + +SeuilDeViolationdeBorneFonctionDeLaMatrice = SEUIL_ADMISSIBILITE_FONCTION_DE_LA_MATRICE; +InfScaleBSurA = NULL; +if ( SeuilDeViolationdeBorneFonctionDeLaMatrice == OUI_SPX ) { + InfScaleBSurA = (double *) malloc( Spx->NombreDeVariables * sizeof( double ) ); + if ( InfScaleBSurA == NULL ) SeuilDeViolationdeBorneFonctionDeLaMatrice = NON_SPX; + else { + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) InfScaleBSurA[Var] = LINFINI_SPX; + } +} + +PlusGrandTerme = -1.; +PlusPetitTerme = LINFINI_SPX; +if ( SeuilDeViolationdeBorneFonctionDeLaMatrice == OUI_SPX ) { + for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + ScB = ScaleB[i]; + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + X = fabs( A[il] ); + if( X > ZERO ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + X = ScB / X; + Var = Indcol[il]; + if ( X < InfScaleBSurA[Var] ) InfScaleBSurA[Var] = X; + } + il++; + } + } + for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) { + Seuil = SEUIL_DE_VIOLATION_DE_BORNE * InfScaleBSurA[Var]; + if ( Seuil < SEUIL_MIN_DE_VIOLATION_DE_BORNE ) Seuil = SEUIL_MIN_DE_VIOLATION_DE_BORNE; + else if ( Seuil > SEUIL_MAX_DE_VIOLATION_DE_BORNE ) Seuil = SEUIL_MAX_DE_VIOLATION_DE_BORNE; + SeuilDeViolationDeBorne[Var] = Seuil; + } + free( InfScaleBSurA ); +} +else { + for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + il = Mdeb[i]; + ilMax = il + NbTerm[i]; + while ( il < ilMax ) { + X = fabs( A[il] ); + if( X > ZERO ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + il++; + } + } +} +Spx->PlusGrandTermeDeLaMatrice = PlusGrandTerme; +Spx->PlusPetitTermeDeLaMatrice = PlusPetitTerme; +Spx->RapportDeScaling = PlusGrandTerme/PlusPetitTerme; + +#if VERBOSE_SPX_SCALING == 1 + +/* Verification */ + +printf("Verification apres application effective du scaling:\n"); + +PlusGrandTerme = -1.; +PlusPetitTerme = LINFINI_SPX; +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + il = Spx->Mdeb[i]; + ilMax = il + Spx->NbTerm[i]; + while ( il < ilMax ) { + X = fabs( Spx->A[il] ); + if( X != 0.0 ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } + il++; + } +} + +Rapport = PlusGrandTerme/PlusPetitTerme; +printf(" Matrice: PlusPetitTerme %e PlusGrandTerme %e Rapport %e\n",PlusPetitTerme,PlusGrandTerme,Rapport); + +PlusGrandTerme = -1.; +PlusPetitTerme = LINFINI_SPX; +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + X = fabs( Spx->Csv[i] ); + if( X != 0.0 ) { + if ( X > PlusGrandTerme ) PlusGrandTerme = X; + if ( X < PlusPetitTerme ) PlusPetitTerme = X; + } +} + +printf(" ScaleLigneDesCouts: %e\n",Spx->ScaleLigneDesCouts); +Rapport = PlusGrandTerme/PlusPetitTerme; +printf(" Couts: PlusPetitTerme %e PlusGrandTerme %e Rapport %e \n",PlusPetitTerme,PlusGrandTerme,Rapport); + +#endif + +return; +} + +/*------------------------------------------------------------------------*/ +/* Cas particulier pour les variables entieres */ + +void SPX_AjusterTolerancesVariablesEntieres( PROBLEME_SPX * Spx ) +{ +PROBLEME_PNE * Pne; int NombreDeVariablesEntieres; int * NumerosDesVariablesEntieres; +int * CorrespondanceVarEntreeVarSimplexe; double * SeuilDeFractionnalite; +int VarPne; int i; int Var; double * SeuilDeViolationDeBorne; int ic; int icMax; +double InfScaleBSurAmax; int * NumeroDeContrainte; +int * Cdeb; int * CNbTerm; double * ACol; double X; double * ScaleB; double Seuil; +int NombreDeContraintesDuProblemeSansCoupes; + +return; /* Pas evident que ce soit une bonne idee */ + +if ( SEUIL_ADMISSIBILITE_FONCTION_DE_LA_MATRICE == NON_PNE ) return; +if ( Spx->ToleranceSurLesVariablesEntieresAjustees == OUI_SPX ) return; +/* Cas particulier pour les variables entieres */ +Pne = (PROBLEME_PNE *) Spx->ProblemePneDeSpx; +if ( Pne == NULL ) return; +Spx->ToleranceSurLesVariablesEntieresAjustees = OUI_SPX; +NombreDeVariablesEntieres = Pne->NombreDeVariablesEntieresTrav; +if ( NombreDeVariablesEntieres <= 0 ) return; +SeuilDeViolationDeBorne = Spx->SeuilDeViolationDeBorne; +NumerosDesVariablesEntieres = Pne->NumerosDesVariablesEntieresTrav; +CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe; +SeuilDeFractionnalite = Pne->SeuilDeFractionnalite; +ScaleB = Spx->ScaleB; +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +ACol = Spx->ACol; +NumeroDeContrainte = Spx->NumeroDeContrainte; +NombreDeContraintesDuProblemeSansCoupes = Spx->NombreDeContraintesDuProblemeSansCoupes; + +for ( i = 0 ; i < NombreDeVariablesEntieres ; i++ ) { + VarPne = NumerosDesVariablesEntieres[i]; + Var = CorrespondanceVarEntreeVarSimplexe[VarPne]; + if ( Var >= 0 ) { + InfScaleBSurAmax = LINFINI_SPX; + ic = Cdeb[Var]; + icMax = ic + CNbTerm[Var]; + while ( ic < icMax ) { + X = fabs( ACol[ic] ); + if( X > ZERO && NumeroDeContrainte[ic] < NombreDeContraintesDuProblemeSansCoupes ) { + X = ScaleB[NumeroDeContrainte[ic]] / X; + if ( X < InfScaleBSurAmax ) InfScaleBSurAmax = X; + } + ic++; + } + Seuil = SeuilDeFractionnalite[VarPne] * InfScaleBSurAmax; + /*printf("%d Seuil %e SeuilDeFractionnalite %e InfScaleBSurAmax %e\n",Var,Seuil,SeuilDeFractionnalite[VarPne],InfScaleBSurAmax);*/ + /*if ( Seuil > SEUIL_DE_VIOLATION_DE_BORNE ) Seuil = SEUIL_DE_VIOLATION_DE_BORNE;*/ + if ( Seuil < 1.e-3 * SEUIL_DE_VIOLATION_DE_BORNE ) Seuil = 1.e-3 * SEUIL_DE_VIOLATION_DE_BORNE; + SeuilDeViolationDeBorne[Var] = Seuil; + } +} + +return; +} + +/*------------------------------------------------------------------------*/ +/* UnScaling */ + +void SPX_UnScaling( PROBLEME_SPX * Spx ) +{ +int i; double * X; double * ScaleX; + +if ( Spx->FaireDuScalingSPX == NON_SPX ) return; + +X = Spx->X; +ScaleX = Spx->ScaleX; + +/* Quand on fait l'unscaling, on corrige les toutes petites valeurs de X en placant X + sur la borne lorsqu'elle est hors base, car apres l'unscaling il se peut qu'on viole + des contraintes */ +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) X[i] *= ScaleX[i]; + +return; +} + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_simplexe.c b/src/ext/Sirius_Solver/simplexe/spx_simplexe.c new file mode 100644 index 0000000000..9ac68b2830 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_simplexe.c @@ -0,0 +1,118 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution de Min c x sous contrainte Ax = b par un + simplexe (forme revisee du simplexe) en matrices + creuses : appel de la routine principale. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + # include "spx_memoire.h" +# endif + +void SPX_InitSetJmp( jmp_buf ); + +/*---------------------------------------------------------------------------------------------------------*/ + +void SPX_InitSetJmp( jmp_buf BufferDeStockage ) +{ +setjmp( BufferDeStockage ); +return; +} + +/*---------------------------------------------------------------------------------------------------------*/ + +PROBLEME_SPX * SPX_Simplexe( PROBLEME_SIMPLEXE * Probleme , PROBLEME_SPX * Spx ) +{ +void * Tas; + +if ( Spx == NULL ) { + # ifdef SPX_UTILISER_LES_OUTILS_DE_GESTION_MEMOIRE_PROPRIETAIRE + Tas = MEM_Init(); + Spx = (PROBLEME_SPX *) MEM_Malloc( Tas, sizeof( PROBLEME_SPX ) ); + if ( Spx == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet PROBLEME_SPX\n"); + Probleme->ExistenceDUneSolution = SPX_ERREUR_INTERNE; + return( Spx ); + } + memset( (char *) Spx, 0, sizeof( PROBLEME_SPX ) ); + Spx->Tas = Tas; + # else + Tas = NULL; + Spx = (PROBLEME_SPX *) malloc( sizeof( PROBLEME_SPX ) ); + if ( Spx == NULL ) { + printf("Saturation memoire, impossible d'allouer un objet PROBLEME_SPX\n"); + Probleme->ExistenceDUneSolution = SPX_ERREUR_INTERNE; + return( Spx ); + } + memset( (char *) Spx, 0, sizeof( PROBLEME_SPX ) ); + Spx->Tas = Tas; + # endif +} + +Spx->AnomalieDetectee = NON_SPX; + +setjmp( Spx->EnvSpx ); + +/* Pour ne pas avoir de warning a la compilation */ +/* Attention, il ne faut pas faire appel ŕ a une autre routine pour faire le setjmp + car lorsque le longjmp arrive, au return de la routine en question on se retrouve + n'importe ou et ça plante */ +/*SPX_InitSetJmp( Spx->EnvSpx );*/ + +if ( Spx->AnomalieDetectee != NON_SPX ) { + /* Liberation du probleme */ + /* Meme si une anomalie a ete detectee il est preferable de ne pas liberer le probleme + ici. Le probleme est de toute facon libere en fin de PNE . */ + /* SPX_LibererProbleme( Spx ); */ + Probleme->ExistenceDUneSolution = SPX_ERREUR_INTERNE; + if ( Spx->AnomalieDetectee == SPX_MATRICE_DE_BASE_SINGULIERE ) { + Probleme->ExistenceDUneSolution = SPX_MATRICE_DE_BASE_SINGULIERE; + /*printf("Trace simplexe: Matrice de base singuliere\n");*/ + } + return( Spx ); +} +else { + /* Optimisation */ + SPX_SimplexeCalculs( Probleme , Spx ); + /* On ne renvoie pas de pointeur a la structure si sa desallocation + a ete demandee par l'appelant */ + if ( Probleme->LibererMemoireALaFin == OUI_SPX ) Spx = NULL; +} + +return( Spx ); +} + + + + + + + + + + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_simplexe_calculs.c b/src/ext/Sirius_Solver/simplexe/spx_simplexe_calculs.c new file mode 100644 index 0000000000..dd7f4d6616 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_simplexe_calculs.c @@ -0,0 +1,666 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Resolution de Min c x sous contrainte Ax = b par un + simplexe (forme revisee du simplexe) en matrices + creuses + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_SimplexeCalculs( PROBLEME_SIMPLEXE * Probleme , PROBLEME_SPX * Spx ) +{ +/* Le probleme d'entree */ +int Contexte; int NombreMaxDIterations; +double * C_E ; double * X_E; double * Xmin_E; double * Xmax_E; int NbVar_E; int * TypeVar_E; +int NbContr_E; int * Mdeb_E; int * NbTerm_E; int * Indcol_E; double * A_E; char * TypeDeContrainte_E; double * B_E; +int ChoixDeLAlgorithme; int BaseDeDepartFournie_E; +int * PositionDeLaVariable_E; int * NbVarDeBaseComplementaires_E; int * ComplementDeLaBase_E; +int * ExistenceDUneSolution; int LibererMemoireALaFin; +double CoutMax; int UtiliserCoutMax; +int NombreDeContraintesCoupes; double * BCoupes; char * PositionDeLaVariableDEcartCoupes; +int * MdebCoupes; int * NbTermCoupes; int * NuvarCoupes; double * ACoupes; +double * CoutsMarginauxDesContraintes; +double * CoutsReduits; int Var; +/* */ +int Cnt; int i; double UnSurScaleLigneDesCouts; double C; double u; int il_E; int il_EMx; int Cnt_E; +int * CorrespondanceCntEntreeCntSimplexe; double * Pi; double * ScaleB; char * CorrectionDuale; +/*int * CorrespondanceVarEntreeVarSimplexe;*/ + +/*----------------------------------------------------------------------------------------------------*/ + +/*printf("Debut SPX_SimplexeCalculs\n");*/ + +Contexte = Probleme->Contexte; +NombreMaxDIterations = Probleme->NombreMaxDIterations; + +C_E = Probleme->CoutLineaire; +X_E = Probleme->X; +Xmin_E = Probleme->Xmin; +Xmax_E = Probleme->Xmax; +NbVar_E = Probleme->NombreDeVariables; +TypeVar_E = Probleme->TypeDeVariable; + +NbContr_E = Probleme->NombreDeContraintes; +Mdeb_E = Probleme->IndicesDebutDeLigne; +NbTerm_E = Probleme->NombreDeTermesDesLignes; +Indcol_E = Probleme->IndicesColonnes; +A_E = Probleme->CoefficientsDeLaMatriceDesContraintes; +TypeDeContrainte_E = Probleme->Sens; +B_E = Probleme->SecondMembre; + +/*ChoixDeLAlgorithme = Probleme->ChoixDeLAlgorithme;*/ +ChoixDeLAlgorithme = SPX_DUAL; + +BaseDeDepartFournie_E = Probleme->BaseDeDepartFournie; +PositionDeLaVariable_E = Probleme->PositionDeLaVariable; +NbVarDeBaseComplementaires_E = &Probleme->NbVarDeBaseComplementaires; +ComplementDeLaBase_E = Probleme->ComplementDeLaBase; + +ExistenceDUneSolution = &Probleme->ExistenceDUneSolution; +LibererMemoireALaFin = Probleme->LibererMemoireALaFin; + +/* Pour tenir compte de petites erreurs pendant l'algorithme on augment CoutMax */ +C = 0.0; /* Car la marge est ajoutee ensuite */ +CoutMax = Probleme->CoutMax + C; +UtiliserCoutMax = Probleme->UtiliserCoutMax; + +NombreDeContraintesCoupes = Probleme->NombreDeContraintesCoupes; +BCoupes = Probleme->BCoupes; +PositionDeLaVariableDEcartCoupes = Probleme->PositionDeLaVariableDEcartCoupes; +MdebCoupes = Probleme->MdebCoupes; +NbTermCoupes = Probleme->NbTermCoupes; +NuvarCoupes = Probleme->NuvarCoupes; +ACoupes = Probleme->ACoupes; + +CoutsMarginauxDesContraintes = Probleme->CoutsMarginauxDesContraintes; +CoutsReduits = Probleme->CoutsReduits; + +Spx->AffichageDesTraces = Probleme->AffichageDesTraces; + +Spx->NbCycles = 0; + +Spx->TypeDePricing = (char) Probleme->TypeDePricing; +if ( Spx->TypeDePricing != PRICING_DANTZIG && Spx->TypeDePricing != PRICING_STEEPEST_EDGE ) { + printf("TypeDePricing pas correctement renseigne\n"); + exit(0); +} + +Spx->FaireDuScalingSPX = (char) Probleme->FaireDuScaling; +if ( Spx->FaireDuScalingSPX != OUI_SPX && Spx->FaireDuScalingSPX != NON_SPX ) { + printf("FaireDuScalingSPX pas correctement renseigne\n"); + exit(0); +} +Spx->StrategieAntiDegenerescence = (char) Probleme->StrategieAntiDegenerescence; +if ( Spx->StrategieAntiDegenerescence != AGRESSIF && Spx->StrategieAntiDegenerescence != PEU_AGRESSIF ) { + printf("StrategieAntiDegenerescence pas correctement renseigne\n"); + exit(0); +} + +Spx->DureeMaxDuCalcul = Probleme->DureeMaxDuCalcul; +if ( Spx->DureeMaxDuCalcul > 0. ) SPX_InitDateDebutDuCalcul( Spx ); + +Spx->ExplorationRapideEnCours = NON_SPX; + +/*----------------------------------------------------------------------------------------------------*/ + +#if VERBOSE_SPX + printf("Entree dans le simplexe: \n"); + printf(" nombre de variables : %d\n",NbVar_E); + printf(" nombre de contraintes: %d\n",NbContr_E); + fflush(stdout); +#endif + +*ExistenceDUneSolution = NON_SPX; /* Precaution. En realite la mise a jour est faite au moment + du return c'est pour ca qu'il n'en faut qu'un seul */ + +Spx->YaUneSolution = OUI_SPX; +Spx->PremierSimplexe = NON_SPX; + +if ( Spx->StrategieAntiDegenerescence == AGRESSIF ) { + Spx->CycleDeControleDeDegenerescence = CYCLE_DE_CONTROLE_DE_DEGENERESCENCE_AGRESSIF; +} +else { + Spx->CycleDeControleDeDegenerescence = CYCLE_DE_CONTROLE_DE_DEGENERESCENCE_PEU_AGRESSIF; +} + +if ( Contexte == BRANCH_AND_BOUND_OU_CUT ) Spx->Contexte = BRANCH_AND_BOUND_OU_CUT; +else if ( Contexte == BRANCH_AND_BOUND_OU_CUT_NOEUD ) Spx->Contexte = BRANCH_AND_BOUND_OU_CUT_NOEUD; +else if ( Contexte == SIMPLEXE_SEUL ) Spx->Contexte = SIMPLEXE_SEUL; +else { + printf("Erreur dans les donnees du simplexe, l'indicateur de contexte d'utilisation est mal initialisé:\n"); + printf(" les valeurs acceptées sont BRANCH_AND_BOUND_OU_CUT, BRANCH_AND_BOUND_OU_CUT_NOEUD et SIMPLEXE_SEUL.\n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +if ( BaseDeDepartFournie_E == OUI_SPX ) Spx->LaBaseDeDepartEstFournie = OUI_SPX; +else if ( BaseDeDepartFournie_E == NON_SPX ) Spx->LaBaseDeDepartEstFournie = NON_SPX; +else if ( BaseDeDepartFournie_E == UTILISER_LA_BASE_DU_PROBLEME_SPX ) { + if ( NombreDeContraintesCoupes > 0 ) { + printf("Erreur dans les donnees du simplexe, l'indicateur de fourniture de base n est pas correctement initialise \n"); + printf("Vous demandez a utiliser la base courante du probleme simplexe mais vous demandez aussi de modifier le probleme\n"); + printf("en y ajoutant des coupes. C'est incompatible car la dimension de la base change.\n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } + Spx->LaBaseDeDepartEstFournie = UTILISER_LA_BASE_DU_PROBLEME_SPX; + /* Dans ce cas, on force le contexte a etre BRANCH_AND_BOUND_OU_CUT_NOEUD ce qui permet a l'appelant + de mettre SIMPLEXE_SEUL et de faire du hot start d'un facon differente de celle du branch and bound + ainsi c'est moins destabilisant pour lui que de mettre BRANCH_AND_BOUND_OU_CUT_NOEUD alors qu'il + n'en fait pas */ + Contexte = BRANCH_AND_BOUND_OU_CUT_NOEUD; + Spx->Contexte = BRANCH_AND_BOUND_OU_CUT_NOEUD; +} +else { + printf("Erreur dans les donnees du simplexe, l'indicateur de fourniture de base n est pas initialise \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +if ( ChoixDeLAlgorithme == SPX_PRIMAL ) { + Spx->AlgorithmeChoisi = SPX_PRIMAL; + printf("Algorithme primal a valider, ne pas l utiliser\n"); + exit(0); +} +else if ( ChoixDeLAlgorithme == SPX_DUAL ) Spx->AlgorithmeChoisi = SPX_DUAL; +else { + printf("Erreur dans les donnees du simplexe, l argument qui precise l'algorithme choisi est incorrect \n"); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ +} + +Spx->FlagStabiliteDeLaFactorisation = 0; +Spx->ProblemeDeStabiliteDeLaFactorisation = NON_SPX; + +/* Pour etre certain de ne pas utiliser a tort les infos sur les coupes. Ainsi en dehors d'un contexte de branch and bound + avec possibilités de coupes, l'appelant n'a pas a initialiser NombreDeContraintesCoupes */ +if ( Spx->Contexte == SIMPLEXE_SEUL || Spx->Contexte == BRANCH_AND_BOUND_OU_CUT ) NombreDeContraintesCoupes = 0; + +if ( Spx->Contexte == SIMPLEXE_SEUL || Spx->Contexte == BRANCH_AND_BOUND_OU_CUT ) { + SPX_AllouerProbleme( Spx , NbVar_E , NbContr_E , Mdeb_E , NbTerm_E ); + SPX_ConstruireLeProbleme( Spx , C_E , X_E , Xmin_E , Xmax_E , NbVar_E , TypeVar_E , + NbContr_E , Mdeb_E , NbTerm_E , Indcol_E , A_E , + TypeDeContrainte_E , B_E , + PositionDeLaVariable_E , *NbVarDeBaseComplementaires_E , + ComplementDeLaBase_E , CoutMax , UtiliserCoutMax ); +} +else { + SPX_ModifierLeProbleme( Spx , C_E, X_E, Xmin_E, Xmax_E, NbVar_E, TypeVar_E, + CoutMax , UtiliserCoutMax ); + if ( Spx->LaBaseDeDepartEstFournie != UTILISER_LA_BASE_DU_PROBLEME_SPX ) { + /* Si on a choisi d'utiliser la base du probleme simplexe courant, alors il est inutile de la reconstruire. + De plus, on ne peut pas ajouter de coupes (donc de contraintes) sinon le probleme change et la base + n'a meme plus la bonne dimension */ + SPX_ConstruireLaBaseDuProblemeModifie( Spx , NbVar_E, PositionDeLaVariable_E, *NbVarDeBaseComplementaires_E, + ComplementDeLaBase_E ); + + /* Les coupes */ + SPX_AjouterLesCoupes( Spx , NombreDeContraintesCoupes, PositionDeLaVariableDEcartCoupes, + MdebCoupes , NbTermCoupes , + NuvarCoupes , ACoupes , + BCoupes ); + + SPX_CompleterLaBaseDuProblemeModifie( Spx , NbVar_E, NbContr_E , PositionDeLaVariable_E ); + + /* Maintenant il faut faire le chainage de la transposee */ + /* Pour l'instant: si on fait de la relaxation de contraintes on refait systeůatiquement le chainage a cause + de Spx->CNbTermSansCoupes */ + if ( NombreDeContraintesCoupes > 2 * Spx->NombreDeContraintesDuProblemeSansCoupes ) { + SPX_ChainageDeLaTransposee( Spx , COMPACT ); + } + else { + SPX_ModifierLeChainageDeLaTransposee( Spx ); + } + } + else { + Spx->LaBaseDeDepartEstFournie = OUI_SPX; + /* Reinitialisation des corrections duales meme si on repart de la base du probleme SPX */ + CorrectionDuale = Spx->CorrectionDuale; + for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) CorrectionDuale[i] = NOMBRE_MAX_DE_PERTURBATIONS_DE_COUT; + } +} + +if ( Spx->YaUneSolution == NON_SPX ) goto FinDuSimplexe; + +SPX_BruitageInitialDesCouts( Spx ); + +SPX_AjusterTolerancesVariablesEntieres( Spx ); + +SPX_InitialiserLeTableauDesVariablesHorsBase( Spx ); + +Spx->UtiliserLaLuUpdate = OUI_SPX /*OUI_SPX*/; +Spx->UtiliserLaBaseReduite = NON_SPX; +Spx->ForcerUtilisationDeLaBaseComplete = 0; +Spx->NombreDeFactorisationsDeBaseReduite = 0; +Spx->NombreDeReactivationsDeLaBaseReduite = 0; + +Spx->NombreDeBasesCompletesSuccessives = NB_DE_BASES_COMPLETES_SUCCESSIVES; +Spx->NombreDeBasesReduitesSuccessives = NB_DE_BASE_REDUITE_SUCCESSIVES_SANS_PRISE_EN_COMPTE_DES__VIOLATIONS; +Spx->NombreDinfaisabilitesSiBaseReduite = Spx->NombreDeContraintes; +Spx->NbEchecsReductionNombreDinfaisabilitesSiBaseReduite = 0; +Spx->InitBaseReduite = OUI_SPX; + +for ( Var = 0 ; Var < Spx->NombreDeVariables ; Var++ ) Spx->PositionHorsBaseReduiteAutorisee[Var] = OUI_1_FOIS; + +Spx->Iteration = 0; +Spx->NombreDeChangementsDeBase = 0; +Spx->NombreMaxDIterations = NOMBRE_MAX_DITERATIONS; +if ( Spx->NombreMaxDIterations <= ( 5 * Spx->NombreDeContraintes ) ) { + Spx->NombreMaxDIterations = 5 * Spx->NombreDeContraintes; +} +/* Prise en compte de la valeur fournie si elle est valide */ +if ( NombreMaxDIterations > 0 ) Spx->NombreMaxDIterations = NombreMaxDIterations; + +if ( Spx->AlgorithmeChoisi == SPX_PRIMAL ) Spx->CycleDeRefactorisation = CYCLE_DE_REFACTORISATION; +else Spx->CycleDeRefactorisation = CYCLE_DE_REFACTORISATION_DUAL; + +/*Spx->LastEta = -1;*/ +Spx->RemplissageMaxDeLaFPI = (int) floor( 0.6 * Spx->NombreDeContraintes * Spx->CycleDeRefactorisation ) + 1; + +#if VERBOSE_SPX + printf("Dans le simplexe: \n"); + printf(" nombre de variables : %d\n",Spx->NombreDeVariables); + printf(" nombre de contraintes: %d\n",Spx->NombreDeContraintes); fflush(stdout); +#endif + +Spx->StrongBranchingEnCours = NON_SPX; + +/* Factoriser la premiere base */ +Spx->BaseInversibleDisponible = NON_SPX; +SPX_FactoriserLaBase( Spx ); + +if ( Spx->YaUneSolution == NON_SPX ) goto FinDuSimplexe; + +/* Et c'est parti dans les iterations: que la force soit avec nous ! */ +if ( Spx->AlgorithmeChoisi == SPX_PRIMAL ) { + return; +} +else { + SPX_DualSimplexe( Spx ); +} + +#if VERBOSE_SPX + printf("Fin du simplexe a l iteration %d\n",Spx->Iteration); +#endif + +# ifdef UTILISER_BORNES_AUXILIAIRES + /* Controle: il ne doit JAMAIS rester de bornes auxilaires */ + if ( Spx->NombreDeBornesAuxiliairesUtilisees != 0 ) { + printf("BUG, le nombre de bornes auxiliaires doit etre nul en fin de simplexe: %d\n",Spx->NombreDeBornesAuxiliairesUtilisees); + exit(0); + } +# endif + +FinDuSimplexe: + +if ( Spx->YaUneSolution == OUI_SPX ) { + + /* Recalcul systematique des variables duales car elle ne sont pas mise a jour a chaque iteration */ + /* Calcul de Pi = c_B * B^{-1} */ + + SPX_CalculerPi( Spx ); + + /* On initialise les valeurs des variables en fonction de leur position */ + SPX_FixerXEnFonctionDeSaPosition( Spx ); + + /* Dans le cas d'un contexte de Branch And Bound ou de Branch And Cut on sauvegarde les donnees + qui seront necessaires pour faire du strong branching voire des coupes de Gomory. Si la base + ne vient pas d'ętre factorisée, on la factorise. */ + if ( Spx->Contexte != SIMPLEXE_SEUL ) SPX_SauvegardesBranchAndBoundAndCut( Spx ); + + /* Ecretage Xmin Xmax avant recuperation de la solution */ + /* + for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + if ( Spx->OrigineDeLaVariable[i] != NATIVE ) continue; + if ( Spx->TypeDeVariable[i] == BORNEE_INFERIEUREMENT ) { + if ( Spx->X[i] < 0. ) { + printf("Variables internes ecretage var %d a xmin %lf car x = %lf Position %d\n", + i,Spx->Xmin[i],Spx->X[i],Spx->PositionDeLaVariable[i]); + if ( Spx->X[i] < -0.001 ) exit(0); + Spx->X[i] = 0.; + } + } + else if ( Spx->TypeDeVariable[i] == BORNEE ) { + if ( Spx->X[i] < 0. ) { + printf("Variables internes ecretage var %d a xmin %lf car x = %lf Position %d\n", + i,Spx->Xmin[i],Spx->X[i],Spx->PositionDeLaVariable[i]); + if ( Spx->X[i] < -0.001 ) exit(0); + Spx->X[i] = 0.; + } + else if ( Spx->X[i] > Spx->Xmax[i] ) { + printf("Variables internes ecretage var %d a xmax %lf car x = %lf Position %d\n", + i,Spx->Xmax[i],Spx->X[i],Spx->PositionDeLaVariable[i]); + if ( Spx->X[i] > Spx->Xmax[i] + 0.001 ) exit(0); + Spx->X[i] = Spx->Xmax[i]; + } + } + } + */ + + /* Traces: verification de l'admissibilite primale dans les variables du simplexe */ + /* + { int il; int ilMax; double Seuil; double S; + printf("Attention verification admissibilite primale systematique\n"); + Seuil = 1.e-5; + for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + il = Spx->Mdeb[Cnt]; + ilMax = il + Spx->NbTerm[Cnt]; + S = 0.0; + while ( il < ilMax ) { + S += Spx->A[il] * Spx->X[Spx->Indcol[il]]; + il++; + } + if ( fabs( Spx->B[Cnt] - S ) / ( Spx->ScaleB[Cnt] * Spx->SupXmax ) > Seuil ) { + printf("1- Probleme d'admissibilite primale sur la contrainte %d \n",Cnt); + printf("B = %e S = %e ecart = %e\n",Spx->B[Cnt],S,fabs( Spx->B[Cnt] - S )); + exit(0); + } + if ( fabs( Spx->B[Cnt] - S ) > Seuil ) { + printf("2- Probleme d'admissibilite primale sur la contrainte %d \n",Cnt); + printf("B = %e S = %e ecart = %e\n",Spx->B[Cnt],S,fabs( Spx->B[Cnt] - S )); + exit(0); + } + } + } + */ + + /* */ + SPX_RecupererLaSolution( Spx, NbVar_E, X_E, TypeVar_E , NbContr_E , PositionDeLaVariable_E , + NbVarDeBaseComplementaires_E , ComplementDeLaBase_E /* , InDualFramework_E , DualPoids_E */ ); + if ( Spx->Contexte != SIMPLEXE_SEUL && NombreDeContraintesCoupes > 0 ) { + SPX_RecupererLaSolutionSurLesCoupes( Spx , NombreDeContraintesCoupes, NbTermCoupes, PositionDeLaVariableDEcartCoupes ); + } + + /* Recuperation des couts marginaux et des couts reduits */ + /* Afin d'avoir les couts reduits sur les variables fixes en entree */ + if ( CoutsReduits != NULL ) memcpy( (char *) CoutsReduits, (char *) C_E, NbVar_E * sizeof( double ) ); + + UnSurScaleLigneDesCouts = 1. / Spx->ScaleLigneDesCouts; + CorrespondanceCntEntreeCntSimplexe = Spx->CorrespondanceCntEntreeCntSimplexe; + Pi = Spx->Pi; + ScaleB = Spx->ScaleB; + /* Les contraintes */ + for ( Cnt_E = 0 ; Cnt_E < NbContr_E ; Cnt_E++ ) { + Cnt = CorrespondanceCntEntreeCntSimplexe[Cnt_E]; + if ( Cnt < 0 && CoutsMarginauxDesContraintes != NULL ) { + CoutsMarginauxDesContraintes[Cnt_E] = 0.0; + continue; + } + u = UnSurScaleLigneDesCouts * Pi[Cnt] * ScaleB[Cnt]; + if ( CoutsMarginauxDesContraintes != NULL ) CoutsMarginauxDesContraintes[Cnt_E] = u; + if ( CoutsReduits != NULL ) { + il_E = Mdeb_E[Cnt_E]; + il_EMx = il_E + NbTerm_E[Cnt_E]; + while ( il_E < il_EMx ) { + CoutsReduits[Indcol_E[il_E]]-= u * A_E[il_E]; + il_E++; + } + } + } + /* Les coupes */ + /* Par convention, si la partie branch and bound veut desactiver certaines coupes sans les renumeroter, + il lui suffit de mettre a 0 les valeurs de NbTermCoupes pour les coupes en question. Il est donc necessaire + de faire le traitement special qui suit lorsque l'on retourne les valeurs des variables duales */ + if ( CoutsMarginauxDesContraintes != NULL ) { + for ( Cnt = Spx->NombreDeContraintesDuProblemeSansCoupes ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + CoutsMarginauxDesContraintes[Cnt] = UnSurScaleLigneDesCouts * Pi[Cnt] * ScaleB[Cnt]; + } + } + + if ( CoutsReduits != NULL ) { + Cnt = Spx->NombreDeContraintesDuProblemeSansCoupes; + for ( i = 0 ; i < NombreDeContraintesCoupes ; i++ ) { + if ( NbTermCoupes[i] > 0 ) { + if ( CoutsMarginauxDesContraintes != NULL ) u = CoutsMarginauxDesContraintes[Cnt]; + else u = UnSurScaleLigneDesCouts * Pi[Cnt] * ScaleB[Cnt]; + il_E = MdebCoupes[i]; + il_EMx = il_E + NbTermCoupes[i]; + while ( il_E < il_EMx ) { + CoutsReduits[NuvarCoupes[il_E]]-= u * ACoupes[il_E]; + il_E++; + } + Cnt++; + } + } + } + + /* Precaution pour eviter les petites derives */ + /*CorrespondanceVarEntreeVarSimplexe = Spx->CorrespondanceVarEntreeVarSimplexe;*/ + for ( i = 0 ; i < NbVar_E ; i++ ) { + /*if ( CorrespondanceVarEntreeVarSimplexe[i] < 0 ) continue;*/ + if ( TypeVar_E[i] != VARIABLE_FIXE && TypeVar_E[i] != VARIABLE_NON_BORNEE ) { + /* Pour les tests */ + /* + if ( X_E[i] < Xmin_E[i] ) { + printf("ecretage var %d a xmin %lf car x = %lf\n",i,Xmin_E[i],X_E[i]) ; + if ( X_E[i] < Xmin_E[i] - 0.0001 ) exit(0); + } + if ( X_E[i] > Xmax_E[i] ) { + printf("ecretage var %d a xmax %lf car x = %lf\n",i,Xmax_E[i],X_E[i]); + if ( X_E[i] > Xmax_E[i] + 0.0001 ) exit(0); + } + */ + /* Fin tests */ + if ( X_E[i] < Xmin_E[i] ) { + X_E[i] = Xmin_E[i]; + } + else if ( X_E[i] > Xmax_E[i] ) { + X_E[i] = Xmax_E[i]; + } + } + } + +goto PasDeTraces; + +printf(" Lancement d'une verification d'admissiblite par le simplexe lui-meme ... a n utiliser que pour la mise au point\n"); + +/* Traces */ +{ + int Cnt_E; int il; int ilMax; double S; int OnSort; int OnEcrit; double Seuil; double Ec; int CntSpx; + + Seuil = 1.e-5; + + for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + + if ( Spx->OrigineDeLaVariable[i] != BASIQUE_ARTIFICIELLE ) continue; + + if( Spx->PositionDeLaVariable[i] != HORS_BASE_SUR_BORNE_INF ) { + /* La variable est en base. La base doit etre degeneree et la variable sur borne inf. */ + if (Spx->PositionDeLaVariable[i] != EN_BASE_SUR_BORNE_INF ) { + /* printf("*** Pas de solution car variable de base %d valeur %lf EN_BASE Xmax %lf \n", + i,Spx->BBarre[Spx->ContrainteDeLaVariableEnBase[i]],Spx->Xmax[i]); */ + if ( Spx->Xmax[i] > 1.1 * SEUIL_DE_DEGENERESCENCE ) { + printf("*** Pas de solution car variable de base %d valeur %lf EN_BASE Xmax %lf \n", + i,Spx->BBarre[Spx->ContrainteDeLaVariableEnBase[i]],Spx->Xmax[i]); + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); /* rq: le 2eme argument ne sera pas utilise */ + } + } + else { + Cnt = Spx->ContrainteDeLaVariableEnBase[i]; + Cnt_E = Spx->CorrespondanceCntSimplexeCntEntree[Cnt]; + /* printf("*** Variable de base %d valeur %lf EN_BASE sur borne inf contrainte %d type %c\n", + i,Spx->X[i],Cnt_E,TypeDeContrainte_E[Cnt_E]); */ + } + } + } + OnSort = NON_SPX; + for ( Cnt_E = 0 ; Cnt_E < NbContr_E ; Cnt_E++ ) { + il = Mdeb_E[Cnt_E]; + ilMax = il + NbTerm_E[Cnt_E]; + S = 0.; + OnEcrit = NON_SPX; + while ( il < ilMax ) { + S+= A_E[il] * X_E[Indcol_E[il]]; + il++; + } + if ( TypeDeContrainte_E[Cnt_E] == '=' ) { + if ( fabs( B_E[Cnt_E] - S ) > Seuil ) { + printf(" Erreur admissibilite contrainte %d type = B %e Calcul %e depassement %e ",Cnt_E,B_E[Cnt_E],S,fabs( B_E[Cnt_E] - S )); + if ( Spx->CorrespondanceCntEntreeCntSimplexe[Cnt_E] >= 0 ) { + printf(" ScaleB %e B_spx %e ",Spx->ScaleB[Spx->CorrespondanceCntEntreeCntSimplexe[Cnt_E]], + B_E[Cnt_E]*Spx->ScaleB[Spx->CorrespondanceCntEntreeCntSimplexe[Cnt_E]]); + } + printf("\n"); + OnSort = OUI_SPX; + OnEcrit = OUI_SPX; + } + } + if ( TypeDeContrainte_E[Cnt_E] == '<' ) { + if ( S > B_E[Cnt_E] + Seuil ) { + printf(" Erreur admissibilite contrainte %d type < B %e Calcul %e depassement %e ",Cnt_E,B_E[Cnt_E],S,fabs( B_E[Cnt_E] - S )); + if ( Spx->CorrespondanceCntEntreeCntSimplexe[Cnt_E] >= 0 ) { + printf(" ScaleB %e ",Spx->ScaleB[Spx->CorrespondanceCntEntreeCntSimplexe[Cnt_E]]); + } + printf("\n"); + OnSort = OUI_SPX; + OnEcrit = OUI_SPX; + } + } + if ( TypeDeContrainte_E[Cnt_E] == '>' ) { + if ( S < B_E[Cnt_E] - Seuil ) { + printf(" Erreur admissibilite contrainte %d type > B %e Calcul %e depassement %e ",Cnt_E,B_E[Cnt_E],S,fabs( B_E[Cnt_E] - S )); + if ( Spx->CorrespondanceCntEntreeCntSimplexe[Cnt_E] >= 0 ) { + printf(" ScaleB %e ",Spx->ScaleB[Spx->CorrespondanceCntEntreeCntSimplexe[Cnt_E]]); + } + printf("\n"); + OnSort = OUI_SPX; + OnEcrit = OUI_SPX; + } + } + if( OnEcrit == OUI_SPX ) { + CntSpx = Spx->CorrespondanceCntEntreeCntSimplexe[Cnt_E]; + printf("B[Cnt] %e Contrainte Spx numero %d NbTermes spx %d ScaleB %e\n",Spx->B[CntSpx],CntSpx,Spx->NbTerm[CntSpx],Spx->ScaleB[CntSpx]); + + il = Spx->Mdeb[CntSpx]; + ilMax = il + Spx->NbTerm[CntSpx]; + S = 0.0; + while ( il < ilMax ) { + printf("Valeur de la variable SPX %e xmin %e xmax %e scale %e\n", + Spx->X[Spx->Indcol[il]] / Spx->ScaleX[Spx->Indcol[il]], + Spx->Xmin[Spx->Indcol[il]],Spx->Xmax[Spx->Indcol[il]],Spx->ScaleX[Spx->Indcol[il]]); + + printf("VarSpx %d X ecart scaleB %e\n",Spx->Indcol[il],Spx->X[Spx->Indcol[il]] / ( Spx->ScaleX[Spx->Indcol[il]] * Spx->ScaleB[CntSpx] )); + + S += Spx->A[il] * ( Spx->X[Spx->Indcol[il]] / Spx->ScaleX[Spx->Indcol[il]] ); + il++; + } + printf("Ecart sur Cnt Spx %d \n",CntSpx); + S /= Spx->ScaleB[CntSpx]; + printf("B = %e S = %e ecart = %e B/ScaleB = %e ScaleB = %e\n",Spx->B[CntSpx]/Spx->ScaleB[CntSpx],S, + fabs( (Spx->B[CntSpx]/Spx->ScaleB[CntSpx]) - S ),Spx->B[CntSpx]/Spx->ScaleB[CntSpx],Spx->ScaleB[CntSpx]); + + Ec = 0.0; + il = Mdeb_E[Cnt_E]; + ilMax = il + NbTerm_E[Cnt_E]; + while ( il < ilMax ) { + printf(" Entree: Var %d X %e Xmin %e Xmax %e A %e ",Indcol_E[il],X_E[Indcol_E[il]],Xmin_E[Indcol_E[il]],Xmax_E[Indcol_E[il]],A_E[il]); + if ( Spx->CorrespondanceVarEntreeVarSimplexe[Indcol_E[il]] >= 0 ) { + + i = Spx->CorrespondanceVarEntreeVarSimplexe[Indcol_E[il]]; + S = Spx->X[i] / Spx->ScaleX[i]; /* Valeur SPX */ + + printf("\n Simplexe: Var %d X %e SeuilViolation %e A %e Xmin %e Xmax %e Position %d ScaleX %e \n", + i, + S, + Spx->SeuilDeViolationDeBorne[i], + A_E[il]*Spx->ScaleB[Spx->CorrespondanceCntEntreeCntSimplexe[Cnt_E]]*Spx->ScaleX[i], + Spx->Xmin[i], + Spx->Xmax[i], + Spx->PositionDeLaVariable[i], + Spx->ScaleX[i]); + + if ( TypeVar_E[Indcol_E[il]] == VARIABLE_FIXE ) printf("Var_E est FIXE\n"); + else if ( TypeVar_E[Indcol_E[il]] == VARIABLE_BORNEE_DES_DEUX_COTES ) printf("Var_E est VARIABLE_BORNEE_DES_DEUX_COTES\n"); + else if ( TypeVar_E[Indcol_E[il]] == VARIABLE_BORNEE_INFERIEUREMENT ) printf("Var_E est VARIABLE_BORNEE_INFERIEUREMENT\n"); + else if ( TypeVar_E[Indcol_E[il]] == VARIABLE_BORNEE_SUPERIEUREMENT ) printf("Var_E est VARIABLE_BORNEE_SUPERIEUREMENT\n"); + else if ( TypeVar_E[Indcol_E[il]] == VARIABLE_NON_BORNEE ) printf("Var_E est VARIABLE_NON_BORNEE\n"); + else printf("Variable de type inconnu\n"); + + if ( Spx->TypeDeVariable[i] == BORNEE ) printf("VarSpx est BORNEE\n"); + else if ( Spx->TypeDeVariable[i] == BORNEE_INFERIEUREMENT ) printf("VarSpx est BORNEE_INFERIEUREMENT\n"); + else if ( Spx->TypeDeVariable[i] == BORNEE_SUPERIEUREMENT ) printf("VarSpx est BORNEE_SUPERIEUREMENT\n"); + else if ( Spx->TypeDeVariable[i] == NON_BORNEE ) printf("VarSpx est NON_BORNEE\n"); + else printf("Variable Spx de type inconnu\n"); + + printf("produit A*X = %e produit A*X du simplexe = %e ecart = %e\n", + A_E[il] * X_E[Indcol_E[il]], A_E[il]*Spx->ScaleX[i] * S,(A_E[il] * X_E[Indcol_E[il]])-(A_E[il]*Spx->ScaleX[i] * S) ); + + Ec += X_E[Indcol_E[il]] - (S*Spx->ScaleX[i]); + + if ( S < Spx->Xmin[i] - Spx->SeuilDeViolationDeBorne[i] || + S > Spx->Xmax[i] + Spx->SeuilDeViolationDeBorne[i] ) { + printf("Violation de borne sur la variable simplexe %d\n",Spx->CorrespondanceVarEntreeVarSimplexe[Indcol_E[il]]); + printf("X %e\n",S); + printf("Xmin %e\n",Spx->Xmin[Spx->CorrespondanceVarEntreeVarSimplexe[Indcol_E[il]]]); + printf("Xmax %e\n",Spx->Xmax[Spx->CorrespondanceVarEntreeVarSimplexe[Indcol_E[il]]]); + } + + } + printf("\n"); + il++; + } + printf("Ec = %e\n",Ec); + } + } + + if( OnSort == OUI_SPX ) { + /* Constitution d'un fichier MPS avant l'exit */ + SPX_EcrireProblemeSpxAuFormatMPS( Spx ); + exit(0); + /* + Spx->AnomalieDetectee = OUI_SPX; + longjmp( Spx->EnvSpx , Spx->AnomalieDetectee ); + */ + } + +printf(" CONTROLE D AMISSIBILITE EN SORTIE DE SIMPLEXE SATISFAISANT\n"); +} +/* Fin traces */ + +} +else { + #if VERBOSE_SPX + printf("Pas de solution \n"); + #endif + /* On recupere quand meme les resultats sur les coupes. Pourquoi (au contraire, c'est idiot) ? */ + /* + if ( Spx->Contexte != SIMPLEXE_SEUL && NombreDeContraintesCoupes > 0 ) { + SPX_RecupererLaSolutionSurLesCoupes( Spx , PositionDeLaVariableDEcartCoupes ); + } + */ +} + +PasDeTraces: + +*ExistenceDUneSolution = Spx->YaUneSolution; + +if ( LibererMemoireALaFin == OUI_SPX ) SPX_LibererProbleme( Spx ); + +return; + +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_simplexe_generalise.c b/src/ext/Sirius_Solver/simplexe/spx_simplexe_generalise.c new file mode 100644 index 0000000000..2990d2dbb8 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_simplexe_generalise.c @@ -0,0 +1,435 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Programmation lineaire generalisee (pour Metrix) + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define TRACES +# undef TRACES + +# define ZERO_CR SEUIL_ADMISSIBILITE_DUALE_1 + +# define COEFF_NB_VAR_DEPART 10 /* Sert a multiplier le nombre de contraintes pour + determiner le nombre de variables a prendre en + compte dans le 1er simplexe d'un simplexe generalise */ + +# define COEFF_INCREMENTATION 2 /* Il n'est pas impossible que dans le premier simplexe + du simplexe generalise, il n'y ait pas de solution admissible. + En effet, comme on optimise sur un ensemble reduit de variable, + le nombre de degres de liberte s'en trouve reduit. Il est donc + necessaire de prevoir un mecanisme d'augmentation du nombre + de variables optimisees. + La valeur de ce parametre permet de determiner un nouveau + nombre de variables sur lequel on relancera un simplexe si le + simplexe precedent n'a pas trouve de solution admissible */ + +# define COEFF_POUR_VIOLATION_MAX 1.0 /*1.0*/ + +# define INCONNU 1 +# define POSITIF 2 +# define NEGATIF 3 +# define POSITIF_ET_NEGATIF 4 + +void SPX_ControlerOptimaliteSpxGeneralise( int , double * , int * , int * , int * , int * , int * , int * + # ifdef TRACES + ,double * + ,double * , + ,int * + ,int * + # endif + ); + +int cptSpxClassique = 0; +int cptSpxGen = 0; +double sumRatioVarContraintes = 0.; + +/*---------------------------------------------------------------------------------------------------------*/ + +void SPX_ControlerOptimaliteSpxGeneralise( int NombreDeVariables, double * CoutsReduits_PbSpx, + int * ReferencePositionDesVariables, int * TypeDeVariable_PbSpx, + int * PositionDeLaVariable_PbSpx, int * NbVarNonOptimisees, + int * NumeroDeVariableNonOptimisee, int * NbErreurs + # ifdef TRACES + ,double * Xmin_PbSpx + ,double * Xmax_PbSpx, + ,int * NbVariablesOptimisees + ,int * NbVariablesDansLOptimisation + # endif + ) +{ int Var; int NombreDErreurs; +# ifdef TRACES +int NombreDeVariablesOptimisees; +int NombreDeVariablesDansLOptimisation; +# endif +int NbVarNonOpt; int i; + +NombreDeVariables = 0; /* Pour ne pas avoir de warning a la compilation */ + +/* Controle */ +NombreDErreurs = 0; + +# ifdef TRACES + NombreDeVariablesOptimisees = *NbVariablesOptimisees; + NombreDeVariablesDansLOptimisation = *NbVariablesDansLOptimisation; +# endif + +NbVarNonOpt = *NbVarNonOptimisees; + +for ( i = 0 ; i < NbVarNonOpt ; i++ ) { + Var = NumeroDeVariableNonOptimisee[i]; + if ( CoutsReduits_PbSpx[Var] > ZERO_CR ) { + /* La variable aurait du etre sur borne inf */ + if ( ReferencePositionDesVariables[Var] != HORS_BASE_SUR_BORNE_INF ) { + NombreDErreurs++; + # ifdef TRACES + printf(" La variable %d n'est pas HORS_BASE_SUR_BORNE_INF hors son cout reduit est %e Xmin = %e Xmax = %e\n", + Var,CoutsReduits_PbSpx[Var],Xmin_PbSpx[Var],Xmax_PbSpx[Var]); + # endif + /* Il faut remettre le type de la variable */ + TypeDeVariable_PbSpx [Var] = VARIABLE_BORNEE_DES_DEUX_COTES; + PositionDeLaVariable_PbSpx[Var] = HORS_BASE_SUR_BORNE_INF; + /* On inverse avec la derniere variable non optimisee */ + if ( NbVarNonOpt > 1 ) { + NumeroDeVariableNonOptimisee[i] = NumeroDeVariableNonOptimisee[NbVarNonOpt-1]; + NbVarNonOpt--; + i--; + } + # ifdef TRACES + NombreDeVariablesOptimisees++; + NombreDeVariablesDansLOptimisation++; + # endif + } + } + else if ( CoutsReduits_PbSpx[Var] < -ZERO_CR ) { + /* La variable aurait du etre sur borne sup */ + if ( ReferencePositionDesVariables[Var] != HORS_BASE_SUR_BORNE_SUP ) { + NombreDErreurs++; + # ifdef TRACES + printf(" La variable %d n'est pas HORS_BASE_SUR_BORNE_SUP hors son cout reduit est %e Xmin = %e Xmax = %e\n", + Var,CoutsReduits_PbSpx[Var],Xmin_PbSpx[Var],Xmax_PbSpx[Var]); + # endif + /* Il faut remettre le type de la variable */ + TypeDeVariable_PbSpx [Var] = VARIABLE_BORNEE_DES_DEUX_COTES; + PositionDeLaVariable_PbSpx[Var] = HORS_BASE_SUR_BORNE_SUP; + /* On inverse avec la derniere variable non optimisee */ + if ( NbVarNonOpt > 1 ) { + NumeroDeVariableNonOptimisee[i] = NumeroDeVariableNonOptimisee[NbVarNonOpt-1]; + NbVarNonOpt--; + i--; + } + # ifdef TRACES + NombreDeVariablesOptimisees++; + NombreDeVariablesDansLOptimisation++; + # endif + } + } +} + +*NbErreurs = NombreDErreurs; +*NbVarNonOptimisees = NbVarNonOpt; + +# ifdef TRACES + *NbVariablesOptimisees = NombreDeVariablesOptimisees; + *NbVariablesDansLOptimisation = NombreDeVariablesDansLOptimisation; +# endif + +return; +} + +/*---------------------------------------------------------------------------------------------------------*/ + +PROBLEME_SPX * SPX_SimplexeGeneralise( PROBLEME_SIMPLEXE * PbSpx, + PROBLEME_SPX * Spx, + char FaireProgrammationLineaireGeneralisee, /* OUI_SPX ou NON_SPX */ + double ViolationMaximale, + int * VecteurDeTravail_1, /* dimensionnement PbSpx->NombreDeVariables */ + char * VecteurDeTravail_2, /* dimensionnement PbSpx->NombreDeVariables */ + int * VecteurDeTravail_3, /* dimensionnement PbSpx->NombreDeVariables */ + int * VecteurDeTravail_4, /* dimensionnement PbSpx->NombreDeVariables */ + double * VecteurDeTravail_5, /* dimensionnement PbSpx->NombreDeVariables */ + char ClasserLesCoutsReduits, /* OUI_SPX ou NON_SPX. Attention: obsolete */ + char ControlerOptimaliteDeLaSolution /* OUI_SPX ou NON_SPX Attention: obsolete */ + ) +{ +int Cnt; int il ; int ilMax; int i; /*int k; */ +int Var; /*double u;*/ +# ifdef TRACES + int NombreDeVariablesOptimisees; +# endif +int NombreDErreurs; +int * ReferencePositionDesVariables; /*int NbVarMxDeDepart;*/ +int * TypeDeVariableReference; PROBLEME_SPX * SpxRetour; + +int * PositionDeLaVariable_PbSpx; int * TypeDeVariable_PbSpx; double * X_PbSpx; double * Xmin_PbSpx; +double * Xmax_PbSpx ; double * CoutsReduits_PbSpx; double * CoutLineaire_PbSpx ; +double * CoutsMarginauxDesContraintes_PbSpx ; int * IndicesDebutDeLigne_PbSpx ; +int * NombreDeTermesDesLignes_PbSpx ; int * IndicesColonnes_PbSpx ; +double * CoefficientsDeLaMatriceDesContraintes_PbSpx ; +/*double MargeDisponibleALaHausse; double MargeRequiseALaHausse;*/ +/*double MargeDisponibleALaBaisse; double MargeRequiseALaBaisse;*/ +/*int IndiceDuDernier; int VarDernier; double X; int NombreDeValeursAClasser;*/ +/*int NombreTotalDeValeursClassees; int NombreDeValeursClassees;*/ +/*int DebutPourLaProchaineRecherche; int DebutDeLaRecherche;*/ +/*char ClasserToutesLesValeurs*/ char * SigneCoeff; double * A_PbSpx; +double A; char * Sens_PbSpx; int NombreDeVariables_PbSpx; int NombreDeContraintes_PbSpx; +/*int varFixe; double valCourant; int NombreDeVariablesDansLOptimisation;*/ +/*double valPrec;*/ char SensCnt; char Sgn; int NbVarNonOptimisees; int * NumeroDeVariableNonOptimisee; +/*int nbVarDansPb;*/ +int premiereCtre; /*int nbContr;*/ +/*int nbVarBaseComp;int * ComplementDeLaBase;*/ +/*double cout;*/ + +ViolationMaximale = 0.0; /* Pour ne pas avoir de warning a la compilation */ +PositionDeLaVariable_PbSpx = (int*) VecteurDeTravail_2; /* Pour ne pas avoir de warning a la compilation */ +ClasserLesCoutsReduits = 0; /* Pour ne pas avoir de warning a la compilation */ +ControlerOptimaliteDeLaSolution = 0; /* Pour ne pas avoir de warning a la compilation */ + +PositionDeLaVariable_PbSpx = PbSpx->PositionDeLaVariable; +TypeDeVariable_PbSpx = PbSpx->TypeDeVariable; +X_PbSpx = PbSpx->X; +Xmin_PbSpx = PbSpx->Xmin; +Xmax_PbSpx = PbSpx->Xmax; +CoutsReduits_PbSpx = PbSpx->CoutsReduits; +CoutLineaire_PbSpx = PbSpx->CoutLineaire; +NombreDeVariables_PbSpx = PbSpx->NombreDeVariables; +NombreDeContraintes_PbSpx = PbSpx->NombreDeContraintes; + +# ifdef TRACES + varFixe = 0 ; + for ( Var = 0 ; Var < PbSpx->NombreDeVariables ; Var++ ) { + if ( TypeDeVariable_PbSpx[Var] == VARIABLE_FIXE ) varFixe++; + } + printf(" Spx Gen %d Spx Classique %d nb de Var non fixes %d var Fixe %d\n", + cptSpxGen, cptSpxClassique,PbSpx->NombreDeVariables - varFixe, varFixe ); + + if (PbSpx->NombreDeContraintes > 1 && (cptSpxClassique + cptSpxGen) > 0){ + sumRatioVarContraintes += ((PbSpx->NombreDeVariables - varFixe)/PbSpx->NombreDeContraintes); + printf(" ratio (moyen sur les precedents simplexe) variables(non fixes)/nb contraintes %f ratio courant %f \n", + sumRatioVarContraintes/(cptSpxClassique + cptSpxGen) , (PbSpx->NombreDeVariables - varFixe)*1.0/PbSpx->NombreDeContraintes); + } +# endif + +if ( FaireProgrammationLineaireGeneralisee == NON_SPX || PbSpx->BaseDeDepartFournie == NON_SPX ) { + cptSpxClassique ++ ; + # ifdef TRACES + printf(" simplexe classique ... \n"); + # endif + SpxRetour = SPX_Simplexe( PbSpx , Spx ); + VecteurDeTravail_1[0] = PbSpx->NombreDeContraintes ; + + return( SpxRetour ); +} +cptSpxGen++; + +/* Utilisation du simplexe generalise */ +/* Si on passe lŕ, la base de depart est toujours fournie */ +if ( PbSpx->BaseDeDepartFournie == NON_SPX ) { + printf("Buuuug: la base de depart n'est pas fournie et on veut faire du simplexe generalise\n"); + exit(0); +} + +premiereCtre = VecteurDeTravail_1[0]; +# ifdef TRACES + printf(" premiere contrainte %d \n",premiereCtre); +# endif + +CoutsMarginauxDesContraintes_PbSpx = PbSpx->CoutsMarginauxDesContraintes; +IndicesDebutDeLigne_PbSpx = PbSpx->IndicesDebutDeLigne; +NombreDeTermesDesLignes_PbSpx = PbSpx->NombreDeTermesDesLignes; +IndicesColonnes_PbSpx = PbSpx->IndicesColonnes; +CoefficientsDeLaMatriceDesContraintes_PbSpx = PbSpx->CoefficientsDeLaMatriceDesContraintes; +A_PbSpx = PbSpx->CoefficientsDeLaMatriceDesContraintes; +Sens_PbSpx = PbSpx->Sens; + + +/* On utilise le contexte SIMPLEXE_SEUL car il est inutile de faire des sauvegardes internes necessaires + au mecanisme des coupes. D'autre part en mode BRANCH and BOUND il n'est pas prevu que le type de + borne des variables puisse changer */ +PbSpx->Contexte = SIMPLEXE_SEUL; +/* Du coup on libere la memoire a la fin */ +PbSpx->LibererMemoireALaFin = OUI_SPX; + +ReferencePositionDesVariables = VecteurDeTravail_3; +TypeDeVariableReference = VecteurDeTravail_4; + +memcpy( (char *) ReferencePositionDesVariables, (char *) PositionDeLaVariable_PbSpx, NombreDeVariables_PbSpx * sizeof( int ) ); + +memcpy( (char *) TypeDeVariableReference, (char *) TypeDeVariable_PbSpx, NombreDeVariables_PbSpx * sizeof( int ) ); + +# ifdef TRACES + NombreDeVariablesOptimisees = 0; + NombreDeVariablesDansLOptimisation = 0; +# endif + +/* +On garde toutes les variables qui etaient en base. Pour les variables qui etaient hors base, on enleve: +- Les variables hors base sur borne sup dont tous les coeff sont negatifs. Explication: si une variable a un +coeff positif et qu'elle est sur borne sup, on peut avoir interet a lui faire quitter sa borne pour diminuer +une contrainte. +- Les variables hors base sur borne inf dont tous les coefficients sont positifs. Explication: si une variable a un +coeff negatitf et qu'elle est sur borne inf, on peut avoir interet a lui faire quitter sa borne pour diminuer +une contrainte. +*/ +/* La base est fournie, on met les variables en base dans la liste des variables a optimiser */ + +SigneCoeff = (char *) VecteurDeTravail_5; +memset( (char * ) SigneCoeff, INCONNU, NombreDeVariables_PbSpx * sizeof( char ) ); + +NumeroDeVariableNonOptimisee = (int *) (&SigneCoeff[NombreDeVariables_PbSpx]); + +for ( Cnt = premiereCtre ; Cnt < NombreDeContraintes_PbSpx ; Cnt++ ) { + SensCnt = Sens_PbSpx[Cnt]; + il = IndicesDebutDeLigne_PbSpx[Cnt]; + ilMax = il + NombreDeTermesDesLignes_PbSpx[Cnt]; + while (il ' ) A = -A_PbSpx[il]; + else break; + if ( A >= 1.e-4 ) { + if ( Sgn == INCONNU ) SigneCoeff[Var] = POSITIF; + else if ( Sgn == NEGATIF ) SigneCoeff[Var] = POSITIF_ET_NEGATIF; + } + else if (A <= -1.e-4){ + if ( Sgn == INCONNU ) SigneCoeff[Var] = NEGATIF; + else if ( Sgn == POSITIF ) SigneCoeff[Var] = POSITIF_ET_NEGATIF; + } + il++; + } +} + +NbVarNonOptimisees = 0; + +for ( Var = 0 ; Var < NombreDeVariables_PbSpx ; Var++ ) { + + if ( TypeDeVariable_PbSpx[Var] == VARIABLE_FIXE ) { + # ifdef TRACES + NombreDeVariablesDansLOptimisation++; + # endif + continue; + } + + if ( PositionDeLaVariable_PbSpx[Var] == EN_BASE ) { + # ifdef TRACES + NombreDeVariablesOptimisees++; + NombreDeVariablesDansLOptimisation++; + # endif + } + else if ( PositionDeLaVariable_PbSpx[Var] == HORS_BASE_SUR_BORNE_SUP ) { + if ( SigneCoeff[Var] != NEGATIF ) { + # ifdef TRACES + NombreDeVariablesOptimisees++; + NombreDeVariablesDansLOptimisation++; + # endif + } + else { /* La variable n'est pas optimisee */ + TypeDeVariable_PbSpx[Var] = VARIABLE_FIXE; + X_PbSpx[Var] = Xmax_PbSpx[Var]; + NumeroDeVariableNonOptimisee[NbVarNonOptimisees] = Var; + NbVarNonOptimisees++; + } + } + else if ( PositionDeLaVariable_PbSpx[Var] == HORS_BASE_SUR_BORNE_INF ) { + if ( SigneCoeff[Var] != POSITIF ) { + # ifdef TRACES + NombreDeVariablesOptimisees++; + NombreDeVariablesDansLOptimisation++; + # endif + } + else { /* La variable n'est pas optimisee */ + TypeDeVariable_PbSpx[Var] = VARIABLE_FIXE; + X_PbSpx[Var] = Xmin_PbSpx[Var]; + NumeroDeVariableNonOptimisee[NbVarNonOptimisees] = Var; + NbVarNonOptimisees++; + } + } +} + + +# ifdef TRACES + printf(" nombre de variables fixes %d\n", varFixe); + printf(" variables en base: NombreDeVariablesOptimisees = %d,PbSpx->NombreDeVariables=%d \n", + NombreDeVariablesOptimisees,PbSpx->NombreDeVariables); +# endif + +/* Resolution du probleme reduit */ + +SIMPLEXE: + +SpxRetour = SPX_Simplexe( PbSpx , Spx ); + # ifdef TRACES +if ( PbSpx->ExistenceDUneSolution != OUI_SPX ) { + printf("Simplexe reduit: pas de solution \n"); + printf("poursuivre le developpement de l'algorithme en ajoutant des variables\n"); + exit(0); +} + # endif +/* Controle */ + +SPX_ControlerOptimaliteSpxGeneralise( NombreDeVariables_PbSpx, CoutsReduits_PbSpx, + ReferencePositionDesVariables, TypeDeVariable_PbSpx, + PositionDeLaVariable_PbSpx, &NbVarNonOptimisees, + NumeroDeVariableNonOptimisee, &NombreDErreurs + # ifdef TRACES + , Xmin_PbSpx + , Xmax_PbSpx, + , &NbVariablesOptimisees + , &NbVariablesDansLOptimisation + # endif + ); +if ( NombreDErreurs > 0 ) { + # ifdef TRACES + printf("NombreDeVariablesOptimisees: %d au lieu de %d\n",NombreDeVariablesOptimisees,PbSpx->NombreDeVariables); + printf("NombreDErreurs %d sur %d\n",NombreDErreurs,PbSpx->NombreDeVariables-NombreDeVariablesOptimisees); + printf(" => relance du simplexe apres avoir ajoute %d variables\n",NombreDErreurs); + # endif + /* On repart avec des variables supplementaires, les variables ont ete positionnees donc la base de + depart est fournie */ + PbSpx->BaseDeDepartFournie = OUI_SPX; + Spx = SpxRetour; + goto SIMPLEXE; +} + +/* Remettre la position de la variable comme elle etait en entree si la variable n'a pas ete optimisee car le simplexe a mis -1 + ainsi que le type initial de variable */ +# ifdef TRACES + printf("NombreDeVariablesOptimisees: %d au lieu de %d\n",NombreDeVariablesOptimisees,PbSpx->NombreDeVariables - varFixe); +# endif + +for ( i = 0 ; i < NbVarNonOptimisees ; i++ ) { + Var = NumeroDeVariableNonOptimisee[i]; + TypeDeVariable_PbSpx [Var] = TypeDeVariableReference[Var]; + PositionDeLaVariable_PbSpx[Var] = ReferencePositionDesVariables[Var]; +} + +# ifdef TRACES + printf(" Le Simplexe a trouve une solution \n"); +# endif + +VecteurDeTravail_1[0] = PbSpx->NombreDeContraintes; +return( SpxRetour ); +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_standalone.c b/src/ext/Sirius_Solver/simplexe/spx_standalone.c new file mode 100644 index 0000000000..035e7e3279 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_standalone.c @@ -0,0 +1,302 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Main de la SPX pour le standalone + + AUTEUR: R. GONZALEZ, N. LHUILLIER + +************************************************************************/ + +# define CPLUSPLUS + # undef CPLUSPLUS + +# include "spx_sys.h" +# include "pne_fonctions.h" + +# ifdef __cplusplus + # include "spx_definition_arguments.h" + # include "spx_constantes_externes.h" + # include "spx_define.h" + extern "C" + { + PROBLEME_SPX * SPX_Simplexe( PROBLEME_SIMPLEXE * Probleme , PROBLEME_SPX * Spx ); + void PNE_LireJeuDeDonneesMPS(void); + } +# else + # include "spx_fonctions.h" + # include "spx_constantes_externes.h" + # include "spx_define.h" +# endif + +# include "mps_define.h" +# include "mps_extern_global.h" + + +PROBLEME_SIMPLEXE probleme; +PROBLEME_SPX *resultat; + + +int main( int argc , char ** argv ) { +int i ; int j; int YaUneSolution; double Critere; int Cnt; double S; +int il; int ilMax; int CntMx; double Smx; double EcX; int Mip; double EcMoy; +char AfficherLesValeursDesVariables=NON_SPX; char VerifierLesContraintes=NON_SPX; +int Nbn; +FILE * FlotDeSortie; + +for ( i = 1 ; i < argc ; i++ ) { + if ( strcmp( argv[i] , "-help" ) == 0 || strcmp( argv[i] , "-h" ) == 0 ) { + printf("\n"); + printf("Options disponibles:\n"); + printf(" -help ou -h Pour obtenir la liste des options disponibles\n"); + printf(" -printv Pour afficher la valeur des variables en fin d'optimisation\n"); + printf(" -verif Pour verifier que toutes les contraintes sont satisfaites par la solution trouvee\n"); + printf(" -all Pour faire l'equivalent de -printv et -verif\n"); + printf("\n"); + exit(0); + } + if ( strcmp( argv[i] , "-printv" ) == 0 ) { + AfficherLesValeursDesVariables = OUI_SPX; + continue; + } + if ( strcmp( argv[i] , "-verif" ) == 0 ) { + VerifierLesContraintes = OUI_SPX; + continue; + } + if ( strcmp( argv[i] , "-all" ) == 0 ) { + AfficherLesValeursDesVariables = OUI_SPX; + VerifierLesContraintes = OUI_SPX; + continue; + } + printf("Option %s inconnue, taper l'option -help pour connaitre la liste des options disponibles\n",argv[i]); + exit(0); +} + +FlotDeSortie = fopen( "RESULTAT.csv", "w" ); +if( FlotDeSortie == NULL ) { + printf("Erreur ouverture du fichier de resultats \n"); + exit(0); +} + +/* Lecture du jeu de donnees */ +/* +printf("Debut de la lecture des donnees \n"); fflush(stdout); +*/ +PNE_LireJeuDeDonneesMPS(); + +/* +printf("Fin de la lecture des donnees \n"); fflush(stdout); +*/ +/* Mip: indicateur positionne a OUI_MPS si on veut optimiser en variables entieres + et positionne a NON_MPS si on veut juste faire un simplexe */ + +Mip = OUI_MPS; +if ( Mip == NON_MPS ) { + for ( j = 0 ; j < Mps.NbVar ; j++ ) Mps.TypeDeVariable[j] = REEL; +} + +/* +printf("********** Attention on fait une maximisation i.e Cout = -Cout ******************\n"); +for ( j = 0 ; j < Mps.NbVar ; j++ ) Mps.L[j] = -Mps.L[j]; +*/ + +/* +printf("Verification des bornes des variables\n"); +for ( j = 0 ; j < Mps.NbVar ; j++ ) { + if ( Mps.Umin[j] > Mps.Umax[j] ) {printf("Erreur Umin %lf Umax %lf Var %d\n",Mps.Umin[j],Mps.Umax[j],j); exit(0);} +} +*/ +/* +printf("Appel du solveur de PNE \n"); fflush(stdout); +*/ + +/* Resolution */ + +for ( j = 0 ; j < 1 ; j++ ) { /* Pour tester les fuites memoire on enchaine les resolutions du meme probleme */ + probleme.TypeDePricing = PRICING_STEEPEST_EDGE;//PRICING_STEEPEST_EDGE PRICING_DANTZIG() + probleme.FaireDuScaling = OUI_SPX; // Vaut OUI_SPX ou NON_SPX + probleme.StrategieAntiDegenerescence = AGRESSIF; // Vaut AGRESSIF ou PEU_AGRESSIF + probleme.NombreMaxDIterations = -1; // si i < 0 , alors le simplexe prendre sa valeur par defaut + probleme.DureeMaxDuCalcul = -1; // si i < 0 , alors le simplexe prendre sa valeur par defaut + probleme.CoutLineaire = Mps.L; + probleme.X = Mps.U; + probleme.Xmin = Mps.Umin; + probleme.Xmax = Mps.Umax; + probleme.NombreDeVariables = Mps.NbVar; + probleme.TypeDeVariable = Mps.TypeDeBorneDeLaVariable; + probleme.NombreDeContraintes = Mps.NbCnt; + probleme.IndicesDebutDeLigne = Mps.Mdeb; + probleme.NombreDeTermesDesLignes = Mps.NbTerm; + probleme.IndicesColonnes = Mps.Nuvar; + probleme.CoefficientsDeLaMatriceDesContraintes = Mps.A; + probleme.Sens = Mps.SensDeLaContrainte; + probleme.SecondMembre = Mps.B; + probleme.CoutsMarginauxDesContraintes = Mps.VariablesDualesDesContraintes; + probleme.ChoixDeLAlgorithme = SPX_DUAL; + + probleme.LibererMemoireALaFin = OUI_SPX; + probleme.AffichageDesTraces = OUI_SPX; + probleme.CoutMax = -1; + probleme.UtiliserCoutMax = NON_SPX; + + probleme.Contexte = SIMPLEXE_SEUL; + probleme.BaseDeDepartFournie = NON_SPX ; + + //Instantiation du résultat + probleme.ComplementDeLaBase = (int*) malloc( Mps.NbCnt * sizeof(int)); + probleme.PositionDeLaVariable = (int*) malloc( Mps.NbVar * sizeof(int)); + probleme.CoutsReduits = (double*) malloc( Mps.NbVar * sizeof(double)); + + // Appel du simplexe + SPX_Simplexe(&probleme, NULL); + + YaUneSolution = probleme.ExistenceDUneSolution; + + /* + for ( j = 0 ; j < Mps.NbVar ; j++ ){ + if ( Mps.TypeDeVariable[j] == ENTIER ) Mps.L[j] = 0.0; + } + */ + + + Nbn = 0; + printf("Dual variables count %d\n",Mps.NbCnt); + for ( Cnt = 0 ; Cnt < Mps.NbCnt ; Cnt++ ) { + goto ABS; + printf("Sense[%d] %c B = %e dual variable = %e\n",Cnt,Mps.SensDeLaContrainte[Cnt],Mps.B[Cnt], + Mps.VariablesDualesDesContraintes[Cnt]); +ABS: + if ( fabs( Mps.VariablesDualesDesContraintes[Cnt] ) < 1.e-8 ) Nbn++; + } + printf("Zero dual variables count %d over %d\n",Nbn,Mps.NbCnt); + + /* Resultats */ + + if ( YaUneSolution == NON_SPX ) printf("No solution found\n"); + if ( YaUneSolution == SPX_ERREUR_INTERNE ) printf("Internal error\n"); + if ( YaUneSolution == SPX_MATRICE_DE_BASE_SINGULIERE ) printf("Problem is infeasible\n"); + if ( YaUneSolution == OUI_SPX) { + + Critere = 0.; + for ( i = 0 ; i < Mps.NbVar ; i++ ) { + Critere+= Mps.L[i] * Mps.U[i]; + fprintf( FlotDeSortie , "%s;%e\n" , Mps.LabelDeLaVariable[i], Mps.U[i] ); + if ( AfficherLesValeursDesVariables == OUI_SPX ) { + printf("Variable number %d name %s value %lf ",i, Mps.LabelDeLaVariable[i], Mps.U[i]); + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_FIXE ) printf(" FIXED variable\n"); + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( Mps.TypeDeVariable[i] == ENTIER ) printf(" min %lf max %lf binary variable\n",Mps.Umin[i], Mps.Umax[i]); + else printf(" min %lf max %lf\n",Mps.Umin[i], Mps.Umax[i]); + } + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_INFERIEUREMENT ) + printf(" min %lf max +INFINI\n",Mps.Umin[i]); + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) + printf(" min -INFINI max %lf\n",Mps.Umax[i]); + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_NON_BORNEE ) + printf(" min -INFINI max +INFINI\n"); + } + } + + printf("\n********** Optimal solution found, objective %e **********\n\n",Critere); + + if ( VerifierLesContraintes == OUI_SPX ) { + + for ( i = 0 ; i < Mps.NbVar ; i++ ) { + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_DES_DEUX_COTES ) { + if ( Mps.U[i] < Mps.Umin[i] - 1.e-6 ) { + printf("Variable number %d name %s violated lower bound: lo= %e value= %e violation= %e\n", + i, Mps.LabelDeLaVariable[i],Mps.Umin[i],Mps.U[i],Mps.Umin[i]-Mps.U[i]); + } + else if ( Mps.U[i] > Mps.Umax[i] + 1.e-6 ) { + printf("Variable number %d name %s violated upper bound: up= %e value= %e violation= %e\n", + i, Mps.LabelDeLaVariable[i],Mps.Umax[i],Mps.U[i],Mps.U[i]-Mps.Umax[i]); + } + continue; + } + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_INFERIEUREMENT ) { + if ( Mps.U[i] < Mps.Umin[i] - 1.e-6 ) { + printf("Variable number %d name %s violated lower bound: lo= %e value= %e violation= %e\n", + i, Mps.LabelDeLaVariable[i],Mps.Umin[i],Mps.U[i],Mps.Umin[i]-Mps.U[i]); + } + continue; + } + if ( Mps.TypeDeBorneDeLaVariable[i] == VARIABLE_BORNEE_SUPERIEUREMENT ) { + if ( Mps.U[i] > Mps.Umax[i] + 1.e-6 ) { + printf("Variable number %d name %s violated upper bound: up= %e value= %e violation= %e\n", + i, Mps.LabelDeLaVariable[i],Mps.Umax[i],Mps.U[i],Mps.U[i]-Mps.Umax[i]); + } + continue; + } + } + + Smx = -1.; + EcX = 1.e-6; + CntMx = -1; + EcMoy = 0.; + for ( Cnt = 0 ; Cnt < Mps.NbCnt ; Cnt++ ) { + S = 0.; + il = Mps.Mdeb[Cnt]; + ilMax = il + Mps.NbTerm[Cnt]; + while ( il < ilMax ) { + i = Mps.Nuvar[il]; + S+= Mps.A[il] * Mps.U[i]; + il++; + } + if ( Mps.SensDeLaContrainte[Cnt] == '=' ) { + EcMoy+= fabs( S - Mps.B[Cnt] ); + if ( fabs( S - Mps.B[Cnt] ) > EcX ) { + EcX = fabs( S - Mps.B[Cnt] ); + Smx = S; + CntMx = Cnt; + } + } + if ( Mps.SensDeLaContrainte[Cnt] == '>' && S < Mps.B[Cnt] ) { + EcMoy+= fabs( S - Mps.B[Cnt] ); + if ( fabs( S - Mps.B[Cnt] ) > EcX ) { + EcX = fabs( S - Mps.B[Cnt] ); + Smx = S; + CntMx = Cnt; + } + } + if ( Mps.SensDeLaContrainte[Cnt] == '<' && S > Mps.B[Cnt] ) { + EcMoy+= fabs( S - Mps.B[Cnt] ); + if ( fabs( S - Mps.B[Cnt] ) > EcX ) { + EcX = fabs( S - Mps.B[Cnt] ); + Smx = S; + CntMx = Cnt; + } + } + /*printf("cnt %ld S %e B %e\n",Cnt,S,Mps.B[Cnt]);*/ + } + if ( CntMx >= 0 ) { + printf("Higher violation:\n"); + if ( Mps.SensDeLaContrainte[CntMx] == '=' ) printf("Cnt num %d - %s -- type = ",CntMx,Mps.LabelDeLaContrainte[CntMx]); + if ( Mps.SensDeLaContrainte[CntMx] == '<' ) printf("Cnt num %d - %s -- type < ",CntMx,Mps.LabelDeLaContrainte[CntMx]); + if ( Mps.SensDeLaContrainte[CntMx] == '>' ) printf("Cnt num %d - %s -- type > ",CntMx,Mps.LabelDeLaContrainte[CntMx]); + printf(" B %e computed %e violation %e\n",Mps.B[CntMx],Smx,fabs(Smx-Mps.B[CntMx])); + } + EcMoy/= Mps.NbCnt; + printf("Violations average value: %e\n",EcMoy); + + } + + } + + printf("\n"); +} +exit(0); +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_supprimer_une_borne_auxilaire.c b/src/ext/Sirius_Solver/simplexe/spx_supprimer_une_borne_auxilaire.c new file mode 100644 index 0000000000..8813b57e04 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_supprimer_une_borne_auxilaire.c @@ -0,0 +1,72 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Remet la borne native d'une variable. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_define.h" +# include "spx_fonctions.h" + +# ifdef UTILISER_BORNES_AUXILIAIRES + +/*----------------------------------------------------------------------------*/ + +void SPX_SupprimerUneBorneAuxiliaire( PROBLEME_SPX * Spx, int Var ) +{ + +/* Si la variable entrante avait sur une borne sup auxiliaire on libere la borne */ + +if ( Spx->StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_BORNEE_INFERIEUREMENT ) { + Spx->TypeDeVariable [Var] = BORNEE_INFERIEUREMENT; + Spx->StatutBorneSupCourante [Var] = BORNE_NATIVE; + Spx->Xmax[Var] = LINFINI_SPX; + Spx->NombreDeBornesAuxiliairesUtilisees--; + if ( Spx->NombreDeBornesAuxiliairesUtilisees < 0 ) { + printf("BUG dans SPX_SupprimerUneBorneAuxiliaire : NombreDeBornesAuxiliairesUtilisees = %d\n",Spx->NombreDeBornesAuxiliairesUtilisees); + exit(0); + } +} +else if ( Spx->StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE ) { + /* Si la variable etait sur borne inf alors cela signifie qu'on avait cree une borne inf + de valeur non nulle */ + if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + Spx->CalculerBBarre = OUI_SPX; + } + Spx->TypeDeVariable [Var] = NON_BORNEE; + Spx->StatutBorneSupCourante [Var] = BORNE_NATIVE; + Spx->Xmax[Var] = LINFINI_SPX; + Spx->Xmin[Var] = -LINFINI_SPX; + Spx->NombreDeBornesAuxiliairesUtilisees--; + if ( Spx->NombreDeBornesAuxiliairesUtilisees < 0 ) { + printf("BUG, le nombre de bornes auxiliaires utilisees est negatif: %d\n",Spx->NombreDeBornesAuxiliairesUtilisees); + exit(0); + } +} + +return; +} +/*----------------------------------------------------------------------------*/ + +# endif + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_sys.h b/src/ext/Sirius_Solver/simplexe/spx_sys.h new file mode 100644 index 0000000000..0a8ebcc163 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_sys.h @@ -0,0 +1,27 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +# include +# include +# include +# include +# include +/* # include */ +# include +# include +# include +# include + diff --git a/src/ext/Sirius_Solver/simplexe/spx_translater_bornes.c b/src/ext/Sirius_Solver/simplexe/spx_translater_bornes.c new file mode 100644 index 0000000000..c4571fe18f --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_translater_bornes.c @@ -0,0 +1,88 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Translater les bornes en entree pour mettre le + probleme sous la forme standard + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_TranslaterLesBornes( PROBLEME_SPX * Spx ) +{ +int i; int Var; int Cnt; int il; int ilMax; double S; double * XminEntree; +double * XmaxEntree; double * Xmin; double * Xmax; char * TypeDeVariable; +double * XEntree; int * Mdeb; int * NbTerm; double * X; double * A; +double * B; int * Indcol; + +XminEntree = Spx->XminEntree; +XmaxEntree = Spx->XmaxEntree; +Xmin = Spx->Xmin; +Xmax = Spx->Xmax; +TypeDeVariable = Spx->TypeDeVariable; +XEntree = Spx->XEntree; +X = Spx->X; + +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + + XminEntree[i] = Xmin[i]; + XmaxEntree[i] = Xmax[i]; + + if ( TypeDeVariable[i] == NON_BORNEE ) continue; + + if ( TypeDeVariable[i] == BORNEE ) { + Xmax[i] = XmaxEntree[i] - XminEntree[i]; + } + Xmin[i] = 0.; + + XEntree[i] = X[i]; + + if ( TypeDeVariable[i] == BORNEE || TypeDeVariable[i] == BORNEE_INFERIEUREMENT ) { + X[i]= XEntree[i] - XminEntree[i]; + } + +} + + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; +B = Spx->B; + +for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + S = 0.; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( TypeDeVariable[Var] != NON_BORNEE ) S+= A[il] * XminEntree[Var]; + il++; + } + B[Cnt]-=S; +} + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_verification_des_vecteurs_de_travail.c b/src/ext/Sirius_Solver/simplexe/spx_verification_des_vecteurs_de_travail.c new file mode 100644 index 0000000000..5cc88c1fb8 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_verification_des_vecteurs_de_travail.c @@ -0,0 +1,60 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Verification de vecteurs de travail. Utilise en mode debug + pour verifier qu'on a bien remis la bonne valeur dans tous les + vecteurs de travail. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +/*----------------------------------------------------------------------------*/ + +void SPX_VerifierLesVecteursDeTravail( PROBLEME_SPX * Spx ) +{ +int i; + +for ( i = 0 ; i < Spx->NombreDeVariables ; i++ ) { + if ( Spx->T[i] != -1 ) { + printf("SPX_VerifierLesVecteursDeTravail: T incorrect\n"); + exit(0); + } +} +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) { + if ( Spx->Marqueur[i] != -1 ) { + printf("SPX_VerifierLesVecteursDeTravail: Marqueur incorrect Marqueur[%d] = %d\n",i,Spx->Marqueur[i]); + exit(0); + } + if ( Spx->AReduit[i] != 0 ) { + printf("SPX_VerifierLesVecteursDeTravail: AReduit incorrect AReduit[%d] = %e\n",i,Spx->AReduit[i]); + exit(0); + } + if ( Spx->Tau[i] != 0 ) { + printf("SPX_VerifierLesVecteursDeTravail: Tau incorrect Tau[%d] = %e\n",i,Spx->Tau[i]); + exit(0); + } +} + +return; +} diff --git a/src/ext/Sirius_Solver/simplexe/spx_verifier_a_barre_s.c b/src/ext/Sirius_Solver/simplexe/spx_verifier_a_barre_s.c new file mode 100644 index 0000000000..10509ef3b4 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_verifier_a_barre_s.c @@ -0,0 +1,61 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Verification de A_BARRE_S = B-1 * AS + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define CYCLE_DE_VERIFICATION_DE_ABARRES 10 +# define CYCLE_DE_VERIFICATION_DE_ABARRES_HYPER_CREUX 20 + +/*----------------------------------------------------------------------------*/ +/* Verification du calcul de ABarreS pour savoir s'il faut + refactoriser la base: on verifie sur k contraintes tirees + au hasard */ + +void SPX_VerifierABarreS( PROBLEME_SPX * Spx ) +{ + +if ( Spx->TypeDeStockageDeABarreS == COMPACT_SPX ) { + if ( Spx->Iteration % CYCLE_DE_VERIFICATION_DE_ABARRES_HYPER_CREUX != 0 ) return; +} +else { + if ( Spx->Iteration % CYCLE_DE_VERIFICATION_DE_ABARRES != 0 ) return; +} + +/* +printf("Verification de ABarreS dans SPX_VerifierABarreS iteration %d\n",Spx->Iteration); +*/ + +if ( Spx->UtiliserLaBaseReduite == OUI_SPX ) { + SPX_VerifierABarreSAvecBaseReduite( Spx ); +} +else { + SPX_VerifierABarreSAvecBaseComplete( Spx ); +} + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_verifier_a_barre_s_avec_base_complete.c b/src/ext/Sirius_Solver/simplexe/spx_verifier_a_barre_s_avec_base_complete.c new file mode 100644 index 0000000000..e746910c1e --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_verifier_a_barre_s_avec_base_complete.c @@ -0,0 +1,185 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Verification de A_BARRE_S = B-1 * AS + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_fonctions.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +# define SEUIL_DE_VERIFICATION_DE_ABarreS_1 1.e-6 /*1.e-7*/ +# define SEUIL_DE_VERIFICATION_DE_ABarreS_2 1.e-6 /*1.e-7*/ +# define NOMBRE_DE_VERIFICATIONS 100 /*100*/ + +# define NBITER_RAFFINEMENT 1 + +# define VERBOSE_SPX 0 + +/*----------------------------------------------------------------------------*/ +/* Verification du calcul de ABarreS pour savoir s'il faut + refactoriser la base: on verifie sur k contraintes tirees + au hasard */ + +void SPX_VerifierABarreSAvecBaseComplete( PROBLEME_SPX * Spx ) +{ +int il; int ilMax; int Cnt; int Var; double X; int NbFois; int Nombre; int i; +int NombreDeVerifications; double * Bs; int * Cdeb; int * CNbTerm; int * NumeroDeContrainte; +double * ACol; int * Mdeb; int * NbTerm; int * Indcol; double * A; int LimiteContraintes; +int * ContrainteDeLaVariableEnBase; double * ABarreS; int NombreDeContraintes; int NmX; +double Ecart; char Imprecision; int * CntDeABarreSNonNuls; int j; int ic; int icMax; +int * VariableEnBaseDeLaContrainte; double * ErBMoinsUn; char * PositionDeLaVariable; + +Imprecision = NON_SPX; + +NombreDeContraintes = Spx->NombreDeContraintes; +LimiteContraintes = NombreDeContraintes; + +A = Spx->A; +Bs = Spx->Bs; +ABarreS = Spx->ABarreS; +if ( Spx->TypeDeStockageDeABarreS == COMPACT_SPX ) { + ErBMoinsUn = Spx->ErBMoinsUn; + for ( i = 0 ; i < NombreDeContraintes ; i++ ) ErBMoinsUn[i]= 0; + + CntDeABarreSNonNuls = Spx->CntDeABarreSNonNuls; + for ( j = 0 ; j < Spx->NbABarreSNonNuls ; j++ ) ErBMoinsUn[CntDeABarreSNonNuls[j]] = ABarreS[j]; + ABarreS = ErBMoinsUn; +} + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +NumeroDeContrainte = Spx->NumeroDeContrainte; +ACol = Spx->ACol; +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +PositionDeLaVariable = Spx->PositionDeLaVariable; + +NombreDeVerifications = NOMBRE_DE_VERIFICATIONS; + +NmX = (int) ceil( 0.5 * LimiteContraintes ); +if ( NombreDeVerifications > NmX ) NombreDeVerifications = NmX; + +/* On tire un nombre au hasard le nombre de verifications qu'on va faire */ + # if UTILISER_PNE_RAND == OUI_SPX + Spx->A1 = PNE_Rand( Spx->A1 ); + X = Spx->A1 * (float) NombreDeVerifications; + # else + X = rand() * Spx->UnSurRAND_MAX * (float) NombreDeVerifications; + # endif + +NombreDeVerifications = (int) X; +if ( NombreDeVerifications <= 0 ) NombreDeVerifications = 1; + +Var = Spx->VariableEntrante; +ic = Cdeb[Var]; +icMax = ic + CNbTerm[Var]; +while ( ic < icMax ) { + Bs[NumeroDeContrainte[ic]] = -ACol[ic]; + ic++; +} + +NbFois = 0; +while ( NbFois < NombreDeVerifications ) { + /* On tire un nombre au hasard compris entre 0 et NombreDeContraintes - 1 */ + # if UTILISER_PNE_RAND == OUI_SPX + Spx->A1 = PNE_Rand( Spx->A1 ); + X = Spx->A1 * (LimiteContraintes - 1); + # else + X = rand() * Spx->UnSurRAND_MAX * (LimiteContraintes - 1); + # endif + + Nombre = (int) X; + if ( Nombre >= LimiteContraintes - 1 ) Nombre = LimiteContraintes - 1; + Cnt = Nombre; + X = Bs[Cnt]; + /* Verification */ + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( PositionDeLaVariable[Indcol[il]] == EN_BASE_LIBRE ) { + X += A[il] * ABarreS[ContrainteDeLaVariableEnBase[Indcol[il]]]; + } + il++; + } + if ( fabs( X ) > SEUIL_DE_VERIFICATION_DE_ABarreS_1 ) { + Imprecision = OUI_SPX; + if ( Spx->NombreDeChangementsDeBase < 10 ) { + /* Si ca se produit dans les premieres iterations apres une factorisation */ + Spx->FlagStabiliteDeLaFactorisation = 1; + } + break; + } + NbFois++; +} + +if ( Imprecision == OUI_SPX ) { + /* Suspiscion: on recalcule l'ecart moyen pour voir s'il faut refactoriser */ + VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + + for ( Cnt = 0 ; Cnt < Spx->NombreDeContraintes ; Cnt++ ) { + Var = VariableEnBaseDeLaContrainte[Cnt]; + X = ABarreS[Cnt]; + ic = Cdeb[Var]; + icMax = ic + CNbTerm[Var]; + while ( ic < icMax ) { + Bs[NumeroDeContrainte[ic]] += ACol[ic] * X; + ic++; + } + } + + Ecart = 0.0; + for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) Ecart+= fabs( Bs[Cnt] ); + Ecart/= NombreDeContraintes; + + if ( Ecart > SEUIL_DE_VERIFICATION_DE_ABarreS_2 && Spx->NombreDeChangementsDeBase > 0 ) { + #if VERBOSE_SPX + printf("SPX_VerifierABarreS Iteration %d erreur de resolution sur ABarreS: %e ",Spx->Iteration,Ecart); + printf(" ecart trop grand on refactorise la base\n"); + #endif + Spx->FactoriserLaBase = OUI_SPX; + /*Spx->FaireDuRaffinementIteratif = NBITER_RAFFINEMENT;*/ + /* On augmente le seuil dual de pivotage */ + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + + Spx->FaireChangementDeBase = NON_SPX; + + } + else { + Spx->FaireDuRaffinementIteratif = NBITER_RAFFINEMENT; + Spx->FaireChangementDeBase = NON_SPX; + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + } +} + +for ( i = 0 ; i < Spx->NombreDeContraintes ; i++ ) Bs[i] = 0; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_verifier_a_barre_s_avec_base_reduite.c b/src/ext/Sirius_Solver/simplexe/spx_verifier_a_barre_s_avec_base_reduite.c new file mode 100644 index 0000000000..fae0527a9e --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_verifier_a_barre_s_avec_base_reduite.c @@ -0,0 +1,201 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Verification de A_BARRE_S = B-1 * AS + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_fonctions.h" + +# include "lu_define.h" +# include "lu_fonctions.h" + +# define SEUIL_DE_VERIFICATION_DE_ABarreS_1 1.e-6 /*1.e-7*/ +# define SEUIL_DE_VERIFICATION_DE_ABarreS_2 1.e-6 /*1.e-7*/ +# define NOMBRE_DE_VERIFICATIONS 100 /*100*/ + +# define NBITER_RAFFINEMENT 1 + +# define VERBOSE_SPX 0 + +/*----------------------------------------------------------------------------*/ +/* Verification du calcul de ABarreS pour savoir s'il faut + refactoriser la base: on verifie sur k contraintes tirees + au hasard */ + +void SPX_VerifierABarreSAvecBaseReduite( PROBLEME_SPX * Spx ) +{ +int il; int ilMax; int Cnt; int Var; double X; int NbFois; int Nombre; int i; +int NombreDeVerifications; double * Bs; int * CdebProblemeReduit; int * CNbTermProblemeReduit; +int * IndicesDeLigneDesTermesDuProblemeReduit; double * ValeurDesTermesDesColonnesDuProblemeReduit; +int * Mdeb; int * NbTerm; int * Indcol; double * A; int LimiteContraintes; +int * ContrainteDeLaVariableEnBase; double * ABarreS; int NmX; double Ecart; char Imprecision; +int * CntDeABarreSNonNuls; int j; int ic; int icMax; int * VariableEnBaseDeLaContrainte; +double * ErBMoinsUn; char * PositionDeLaVariable; int RangDeLaMatriceFactorisee; +int * OrdreColonneDeLaBaseFactorisee; int rr; int * LigneDeLaBaseFactorisee; int r; +int * ColonneDeLaBaseFactorisee; + +Imprecision = NON_SPX; + +RangDeLaMatriceFactorisee = Spx->RangDeLaMatriceFactorisee; +OrdreColonneDeLaBaseFactorisee = Spx->OrdreColonneDeLaBaseFactorisee; +ColonneDeLaBaseFactorisee = Spx->ColonneDeLaBaseFactorisee; +LigneDeLaBaseFactorisee = Spx->LigneDeLaBaseFactorisee; + +LimiteContraintes = RangDeLaMatriceFactorisee; + +A = Spx->A; +Bs = Spx->Bs; +ABarreS = Spx->ABarreS; +if ( Spx->TypeDeStockageDeABarreS == COMPACT_SPX ) { + ErBMoinsUn = Spx->ErBMoinsUn; + for ( i = 0 ; i < LimiteContraintes ; i++ ) ErBMoinsUn[i]= 0; + + CntDeABarreSNonNuls = Spx->CntDeABarreSNonNuls; + for ( j = 0 ; j < Spx->NbABarreSNonNuls ; j++ ) ErBMoinsUn[CntDeABarreSNonNuls[j]] = ABarreS[j]; + ABarreS = ErBMoinsUn; +} + +CdebProblemeReduit = Spx->CdebProblemeReduit; +CNbTermProblemeReduit = Spx->CNbTermProblemeReduit; +IndicesDeLigneDesTermesDuProblemeReduit = Spx->IndicesDeLigneDesTermesDuProblemeReduit; +ValeurDesTermesDesColonnesDuProblemeReduit = Spx->ValeurDesTermesDesColonnesDuProblemeReduit; + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; +PositionDeLaVariable = Spx->PositionDeLaVariable; + +NombreDeVerifications = NOMBRE_DE_VERIFICATIONS; + +NmX = (int) ceil( 0.5 * LimiteContraintes ); +if ( NombreDeVerifications > NmX ) NombreDeVerifications = NmX; + +/* On tire un nombre au hasard le nombre de verifications qu'on va faire */ + # if UTILISER_PNE_RAND == OUI_SPX + Spx->A1 = PNE_Rand( Spx->A1 ); + X = Spx->A1 * (float) NombreDeVerifications; + # else + X = rand() * Spx->UnSurRAND_MAX * (float) NombreDeVerifications; + # endif + +NombreDeVerifications = (int) X; +if ( NombreDeVerifications <= 0 ) NombreDeVerifications = 1; + +Var = Spx->VariableEntrante; +ic = CdebProblemeReduit[Var]; +icMax = ic + CNbTermProblemeReduit[Var]; +while ( ic < icMax ) { + Bs[IndicesDeLigneDesTermesDuProblemeReduit[ic]] = -ValeurDesTermesDesColonnesDuProblemeReduit[ic]; + ic++; +} + +NbFois = 0; +while ( NbFois < NombreDeVerifications ) { + /* On tire un nombre au hasard compris entre 0 et LimiteContraintes - 1 */ + # if UTILISER_PNE_RAND == OUI_SPX + Spx->A1 = PNE_Rand( Spx->A1 ); + X = Spx->A1 * (LimiteContraintes - 1); + # else + X = rand() * Spx->UnSurRAND_MAX * (LimiteContraintes - 1); + # endif + + Nombre = (int) X; + if ( Nombre >= LimiteContraintes - 1 ) Nombre = LimiteContraintes - 1; + rr = Nombre; + + X = Bs[rr]; + /* Verification */ + Cnt = LigneDeLaBaseFactorisee[rr]; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + Var = Indcol[il]; + if ( PositionDeLaVariable[Var] != EN_BASE_LIBRE ) goto Next_il_0; + r = OrdreColonneDeLaBaseFactorisee[ContrainteDeLaVariableEnBase[Var]]; + if ( r >= RangDeLaMatriceFactorisee ) goto Next_il_0; /* Normalement ca n'arrive pas */ + X += A[il] * ABarreS[r]; + Next_il_0: + il++; + } + if ( fabs( X ) > SEUIL_DE_VERIFICATION_DE_ABarreS_1 ) { + Imprecision = OUI_SPX; + if ( Spx->NombreDeChangementsDeBase < 10 ) { + /* Si ca se produit dans les premieres iterations apres une factorisation */ + Spx->FlagStabiliteDeLaFactorisation = 1; + } + break; + } + NbFois++; +} + +if ( Imprecision == OUI_SPX ) { + /* Suspiscion: on recalcule l'ecart moyen pour voir s'il faut refactoriser */ + VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + + for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + Var = VariableEnBaseDeLaContrainte[ColonneDeLaBaseFactorisee[r]]; + X = ABarreS[r]; + ic = CdebProblemeReduit[Var]; + icMax = ic + CNbTermProblemeReduit[Var]; + while ( ic < icMax ) { + Bs[IndicesDeLigneDesTermesDuProblemeReduit[ic]] += ValeurDesTermesDesColonnesDuProblemeReduit[ic] * X; + ic++; + } + + } + + Ecart = 0.0; + for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) { + Ecart += fabs( Bs[r] ); + } + Ecart/= RangDeLaMatriceFactorisee; + + if ( Ecart > SEUIL_DE_VERIFICATION_DE_ABarreS_2 && Spx->NombreDeChangementsDeBase > 0 ) { + #if VERBOSE_SPX + printf("SPX_VerifierABarreS Iteration %d erreur de resolution sur ABarreS: %e ",Spx->Iteration,Ecart); + printf(" ecart trop grand on refactorise la base\n"); + #endif + Spx->FactoriserLaBase = OUI_SPX; + /*Spx->FaireDuRaffinementIteratif = NBITER_RAFFINEMENT;*/ + /* On augmente le seuil dual de pivotage */ + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + + Spx->FaireChangementDeBase = NON_SPX; + + } + else { + Spx->FaireDuRaffinementIteratif = NBITER_RAFFINEMENT; + Spx->FaireChangementDeBase = NON_SPX; + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + } +} + +for ( r = 0 ; r < RangDeLaMatriceFactorisee ; r++ ) Bs[r] = 0; + +return; +} + diff --git a/src/ext/Sirius_Solver/simplexe/spx_verifier_admissibilite_duale.c b/src/ext/Sirius_Solver/simplexe/spx_verifier_admissibilite_duale.c new file mode 100644 index 0000000000..803ea2ba72 --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_verifier_admissibilite_duale.c @@ -0,0 +1,348 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: On positionne correctement les variables hors base compte + tenu de la crash base que l'on a determinee ou bien des + valeurs de couts reduits a la fin d'une iteration de phase 1. + Remarque: il est important, pour les variables non bornées + d'un seul ou des 2 cotés, de faire le test par rapport ŕ + SeuilDAmissibiliteDuale2 sachant que la restauration de + l'admissibilité est faite par rapport ŕ un seuil plus petit + SeuilDAmissibiliteDuale1. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# define VERBOSE_SPX 0 + +# define SEUIL_ADMISSIBILITE_DUALE_TOLERE 1.e-10 /* S'il n'y a qu'un petit nombre de seuils violes */ + +/*----------------------------------------------------------------------------*/ + +void SPX_VerifierAdmissibiliteDuale( PROBLEME_SPX * Spx , int * AdmissibiliteRestauree ) +{ +int Var; double SommeDesInfaisabilites; char RestaurerAdmissibiliteDuale; int Iteration; +double PlusGrandeViolation; int VariableDePlusGrandeViolation; double VolumeDeChangementDeBornes; +int NombreDeChangementDeBorne; int NombreMaxDIterations; int * NumerosDesVariablesHorsBase; +int i; char * TypeDeVariable; double * CBarre; char * PositionDeLaVariable; double * Xmax; +double * C; char * OrigineDeLaVariable; char * StatutBorneSupCourante; double * Xmin; +double * SeuilDAmissibiliteDuale; int NbInfDual; int SeuilNbInfDual; int UtiliserLaBaseReduite; +double SeuilAdmDuale; + +if ( Spx->CBarreAEteCalculeParMiseAJour == OUI_SPX ) { + SPX_CalculerPi( Spx ); /* Calcul de Pi = c_B * B^{-1} */ + SPX_CalculerLesCoutsReduits( Spx ); /* Calcul de CBarre = c_N - < Pi , N > */ + Spx->CalculerCBarre = NON_SPX; +} + +VariableDePlusGrandeViolation = -1; +PlusGrandeViolation = 0.; + +UtiliserLaBaseReduite = Spx->UtiliserLaBaseReduite; + +Spx->NbInfaisabilitesDuales = 0; +SommeDesInfaisabilites = 0.0; + +VolumeDeChangementDeBornes = 0.0; +NombreDeChangementDeBorne = 0; + +RestaurerAdmissibiliteDuale = NON_SPX; +*AdmissibiliteRestauree = NON_SPX; + +NumerosDesVariablesHorsBase = Spx->NumerosDesVariablesHorsBase; +TypeDeVariable = Spx->TypeDeVariable; +CBarre = Spx->CBarre; +PositionDeLaVariable = Spx->PositionDeLaVariable; +Xmax = Spx->Xmax; +C = Spx->C; +OrigineDeLaVariable = Spx->OrigineDeLaVariable; +StatutBorneSupCourante = Spx->StatutBorneSupCourante; +Xmin = Spx->Xmin; + +SeuilDAmissibiliteDuale = Spx->SeuilDAmissibiliteDuale2; + +/* Boucle sur les variables hors base */ +/* Examen des couts reduits pour chaque type de variable. On compte le nombre de violations */ +NbInfDual = 0; +SeuilNbInfDual = 5; +for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + + if ( UtiliserLaBaseReduite == NON_SPX ) SeuilAdmDuale = SeuilDAmissibiliteDuale[Var]; + else { + if ( SEUIL_ADMISSIBILITE_DUALE_2 > SeuilDAmissibiliteDuale[Var] ) SeuilAdmDuale = SEUIL_ADMISSIBILITE_DUALE_2; + else SeuilAdmDuale = SeuilDAmissibiliteDuale[Var]; + } + + if ( TypeDeVariable[Var] == BORNEE ) { + if ( CBarre[Var] > SeuilAdmDuale ) { + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) NbInfDual++; + } + else if ( CBarre[Var] < -SeuilAdmDuale ) { + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) NbInfDual++; + } + continue; + } + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + /* La variable est duale realisable si son cout reduit est positif */ + if ( CBarre[Var] < -SeuilAdmDuale ) NbInfDual++; + } + if ( TypeDeVariable[Var] == NON_BORNEE ) { + /* La variable est duale realisable si son cout reduit est nul */ + if ( fabs( CBarre[Var] ) > SeuilAdmDuale ) NbInfDual++; + } +} + +/* Examen des couts reduits pour chaque type de variable */ +for ( i = 0 ; i < Spx->NombreDeVariablesHorsBase ; i++ ) { + Var = NumerosDesVariablesHorsBase[i]; + + if ( UtiliserLaBaseReduite == NON_SPX ) SeuilAdmDuale = SeuilDAmissibiliteDuale[Var]; + else { + if ( SEUIL_ADMISSIBILITE_DUALE_2 > SeuilDAmissibiliteDuale[Var] ) SeuilAdmDuale = SEUIL_ADMISSIBILITE_DUALE_2; + else SeuilAdmDuale = SeuilDAmissibiliteDuale[Var]; + } + + if ( TypeDeVariable[Var] == BORNEE ) { + + if ( CBarre[Var] > SeuilAdmDuale ) { + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) { + if ( NbInfDual <= SeuilNbInfDual && CBarre[Var] < SEUIL_ADMISSIBILITE_DUALE_TOLERE ) { + /* On considere que c'est quand-meme bon */ + continue; + } + + # if VERBOSE_SPX + printf("Iteration %d erreur variable bornee des 2 cotes %d cbarre %e Xmax %e HORS_BASE_SUR_BORNE_SUP SeuilDAmissibiliteDuale %e \n", + Spx->Iteration,Var,Spx->CBarre[Var],Spx->Xmax[Var],SeuilAdmDuale); + # endif + + VolumeDeChangementDeBornes+= Xmax[Var]; + # ifdef UTILISER_BORNES_AUXILIAIRES + if ( Spx->NombreDeBornesAuxiliairesUtilisees > 0 ) { + if ( StatutBorneSupCourante[Var] == BORNE_AUXILIAIRE_DE_VARIABLE_BORNEE_INFERIEUREMENT ) { + /* La variable est devenue duale admissible avec ses bornes natives */ + SPX_SupprimerUneBorneAuxiliaire( Spx, Var ); + } + } + #endif + NombreDeChangementDeBorne++; + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + *AdmissibiliteRestauree = OUI_SPX; + continue; + } + } + else if ( CBarre[Var] < -SeuilAdmDuale ) { + if ( PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) { + if ( NbInfDual <= SeuilNbInfDual && CBarre[Var] > -SEUIL_ADMISSIBILITE_DUALE_TOLERE ) { + /* On considere que c'est quand-meme bon */ + continue; + } + + # if VERBOSE_SPX + printf("Iteration %d erreur variable bornee des 2 cotes %d cbarre %e Xmax %e HORS_BASE_SUR_BORNE_INF SeuilDAmissibiliteDuale %e \n", + Spx->Iteration,Var,Spx->CBarre[Var],Spx->Xmax[Var],SeuilAdmDuale); + # endif + + NombreDeChangementDeBorne++; + PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_SUP; + VolumeDeChangementDeBornes+= Xmax[Var]; + *AdmissibiliteRestauree = OUI_SPX; + continue; + } + } + /* Remarque importante: lorsque la base de part n'est pas fournie, on met initialement toutes les variables hors base + a HORS_BASE_SUR_BORNE_INF donc si les 2 tests ci-dessus ne positionne pas la variable c'est qu'elle est bien + positionnee */ + continue; + } + + if ( TypeDeVariable[Var] == BORNEE_INFERIEUREMENT ) { + if ( PositionDeLaVariable[Var] != HORS_BASE_SUR_BORNE_INF ) { + printf("SPX_VerifierAdmissibiliteDuale:\n"); + printf("Bug iteration %d var %d cbarre %e BORNEE_INFERIEUREMENT pas HORS_BASE_SUR_BORNE_INF\n",Spx->Iteration,Var,Spx->CBarre[Var]); + if ( Spx->PositionDeLaVariable[Var] == EN_BASE_LIBRE ) printf("Position: EN_BASE_LIBRE\n"); + if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) printf("Position: HORS_BASE_SUR_BORNE_INF\n"); + if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) printf("Position: HORS_BASE_SUR_BORNE_SUP\n"); + if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_A_ZERO ) printf("Position: HORS_BASE_A_ZERO\n"); + printf("Xmin %e Xmax %e\n",Spx->Xmin[Var],Spx->Xmax[Var]); + if ( Spx->OrigineDeLaVariable[Var] == NATIVE ) printf("Origine de la variable: NATIVE\n"); + if ( Spx->OrigineDeLaVariable[Var] == ECART ) printf("Origine de la variable: ECART\n"); + if ( Spx->OrigineDeLaVariable[Var] == BASIQUE_ARTIFICIELLE ) printf("Origine de la variable: BASIQUE_ARTIFICIELLE\n"); + printf("IndexDeLaVariableDansLesVariablesHorsBase %d\n",Spx->IndexDeLaVariableDansLesVariablesHorsBase[Var]); + /*exit(0);*/ + } + /* La variable est duale realisable si son cout reduit est positif */ + if ( CBarre[Var] < -SeuilAdmDuale ) { + if ( NbInfDual <= SeuilNbInfDual && CBarre[Var] > -SEUIL_ADMISSIBILITE_DUALE_TOLERE ) { + /* On considere que c'est quand-meme bon */ + continue; + } + + #if VERBOSE_SPX + printf("SPX_VerifierAdmissibiliteDuale Iteration %d erreur iteration %d var %d cbarre %e seuil %e BORNEE_INFERIEUREMENT\n", + Spx->Iteration,Spx->Iteration,Var,Spx->CBarre[Var],-SeuilAdmDuale); + #endif + + # ifndef UTILISER_BORNES_AUXILIAIRES + SommeDesInfaisabilites+= CBarre[Var]; + Spx->NbInfaisabilitesDuales++; + RestaurerAdmissibiliteDuale = OUI_SPX; + #else + /* On cree une borne sup et on change la position de la variable */ + PositionDeLaVariable [Var] = HORS_BASE_SUR_BORNE_SUP; + TypeDeVariable [Var] = BORNEE; + StatutBorneSupCourante[Var] = BORNE_AUXILIAIRE_DE_VARIABLE_BORNEE_INFERIEUREMENT; + Xmax [Var] = SPX_CalculerUneBorneAuxiliaire( Spx, Var ); + # if VERBOSE_SPX + printf("SPX_VerifierAdmissibiliteDuale Iteration %d erreur iteration %d var %d cbarre %e BORNEE_INFERIEUREMENT => On cree une borne auxiliaire valeur %e\n", + Spx->Iteration,Spx->Iteration,Var,Spx->CBarre[Var],Xmax[Var]); + # endif + + Spx->NombreDeBornesAuxiliairesUtilisees++; + *AdmissibiliteRestauree = OUI_SPX; + NombreDeChangementDeBorne++; + VolumeDeChangementDeBornes+= Xmax[Var]; + #endif + continue; + } + continue; + } + + if ( TypeDeVariable[Var] == NON_BORNEE ) { + if ( PositionDeLaVariable[Var] != HORS_BASE_A_ZERO ) { + printf("SPX_VerifierAdmissibiliteDuale:\n"); + printf("Bug iteration %d var %d cbarre %e NON_BORNEE hors base mais pas HORS_BASE_A_ZERO \n",Spx->Iteration,Var,Spx->CBarre[Var]); + if ( Spx->PositionDeLaVariable[Var] == EN_BASE_LIBRE ) printf("Position: EN_BASE_LIBRE\n"); + if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_INF ) printf("Position: HORS_BASE_SUR_BORNE_INF\n"); + if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_SUR_BORNE_SUP ) printf("Position: HORS_BASE_SUR_BORNE_SUP\n"); + if ( Spx->PositionDeLaVariable[Var] == HORS_BASE_A_ZERO ) printf("Position: HORS_BASE_A_ZERO\n"); + printf("Xmin %e Xmax %e\n",Spx->Xmin[Var],Spx->Xmax[Var]); + if ( Spx->OrigineDeLaVariable[Var] == NATIVE ) printf("Origine de la variable: NATIVE\n"); + if ( Spx->OrigineDeLaVariable[Var] == ECART ) printf("Origine de la variable: ECART\n"); + if ( Spx->OrigineDeLaVariable[Var] == BASIQUE_ARTIFICIELLE ) printf("Origine de la variable: BASIQUE_ARTIFICIELLE\n"); + printf("IndexDeLaVariableDansLesVariablesHorsBase %d\n",Spx->IndexDeLaVariableDansLesVariablesHorsBase[Var]); + /*exit(0);*/ + } + /* La variable est duale realisable si son cout reduit est nul */ + if ( fabs( CBarre[Var] ) > SeuilAdmDuale ) { + if ( NbInfDual <= SeuilNbInfDual && CBarre[Var] < SEUIL_ADMISSIBILITE_DUALE_TOLERE ) { + /* On considere que c'est quand-meme bon */ + continue; + } + + #if VERBOSE_SPX + printf("SPX_VerifierAdmissibiliteDuale Iteration %d erreur var %d cbarre %e hors base NON_BORNEE\n",Spx->Iteration,Var,Spx->CBarre[Var]); + #endif + + # ifndef UTILISER_BORNES_AUXILIAIRES + SommeDesInfaisabilites+= CBarre[Var]; + Spx->NbInfaisabilitesDuales++; + RestaurerAdmissibiliteDuale = OUI_SPX; + /* On veut absolument faire des iterations de phase 1 plutot que modifier le cout */ + #else + /* On cree une borne sup et on change la position de la variable */ + + #if VERBOSE_SPX + printf("Iteration %d erreur var %d cbarre %e hors base NON_BORNEE => On cree une borne auxiliaire\n",Spx->Iteration,Var,Spx->CBarre[Var]); + # endif + + TypeDeVariable [Var] = BORNEE; + StatutBorneSupCourante[Var] = BORNE_AUXILIAIRE_DE_VARIABLE_NON_BORNEE; + Xmax[Var] = SPX_CalculerUneBorneAuxiliaire( Spx, Var ); + Xmin[Var] = 0.; + Spx->NombreDeBornesAuxiliairesUtilisees++; + if ( CBarre[Var] < -SeuilAdmDuale ) PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_SUP; + else PositionDeLaVariable[Var] = HORS_BASE_SUR_BORNE_INF; + *AdmissibiliteRestauree = OUI_SPX; + NombreDeChangementDeBorne++; + VolumeDeChangementDeBornes+= Xmax[Var]; + #endif + continue; + } + } + +} + +#if VERBOSE_SPX + if ( NombreDeChangementDeBorne > 0 ) { + printf("Controle d'admissibilite duale, nombre de variables bornees repositionnes %d VolumeDeChangementDeBornes %e\n", + NombreDeChangementDeBorne,VolumeDeChangementDeBornes); + } +#endif + +/* Il faut le laisser car on peut repositionner des bornes sur des variables avec Xmin = Xmax = 0 */ +if ( VolumeDeChangementDeBornes < 1.e-8 ) *AdmissibiliteRestauree = NON_SPX; + +Spx->SommeDesInfaisabilitesDuales = -SommeDesInfaisabilites; + +if ( RestaurerAdmissibiliteDuale == NON_SPX ) { + if ( *AdmissibiliteRestauree == OUI_SPX ) { + SPX_CalculerBBarre( Spx ); + Spx->CalculerBBarre = NON_SPX; + if ( Spx->NombreDeContraintesASurveiller <= 0 ) *AdmissibiliteRestauree = NON_SPX; /* Pour ne pas refaire le travail dans dual simplexe */ + } +} + +if ( RestaurerAdmissibiliteDuale == OUI_SPX ) { + Iteration = Spx->Iteration; + NombreMaxDIterations = Spx->NombreMaxDIterations; + /* On limite a 1000 */ + # ifndef UTILISER_BORNES_AUXILIAIRES + Spx->NombreMaxDIterations = 1000; + # endif + + #if VERBOSE_SPX + printf("Restauration de l'admissibilite duale necessaire a l'iteration %d : ",Spx->Iteration); + printf("Nombre d'infaisabilites duales %5d Somme des infaisabilites duales %e \n",Spx->NbInfaisabilitesDuales,-SommeDesInfaisabilites); + #endif + + SPX_FactoriserLaBase( Spx ); + SPX_DualPhase1Simplexe( Spx ); + + Spx->PhaseEnCours = PHASE_2; + + Spx->Iteration = Iteration; + Spx->NombreMaxDIterations = NombreMaxDIterations; + Spx->CalculerBBarre = OUI_SPX; + Spx->CalculerCBarre = OUI_SPX; + + if ( Spx->LaBaseEstDualeAdmissible == NON_SPX ) { + /* Echec */ + Spx->YaUneSolution = NON_SPX; + Spx->Iteration = 10 * Spx->NombreMaxDIterations; + } + + *AdmissibiliteRestauree = OUI_SPX; + + SPX_CalculerBBarre( Spx ); + Spx->CalculerBBarre = NON_SPX; + *AdmissibiliteRestauree = NON_SPX; /* Pour ne pas refaire le travail dans dual simplexe */ + +} + +return; +} + + diff --git a/src/ext/Sirius_Solver/simplexe/spx_verifier_erbmoins1.c b/src/ext/Sirius_Solver/simplexe/spx_verifier_erbmoins1.c new file mode 100644 index 0000000000..cc9bbf532c --- /dev/null +++ b/src/ext/Sirius_Solver/simplexe/spx_verifier_erbmoins1.c @@ -0,0 +1,273 @@ +/* +** Copyright 2007-2018 RTE +** Author: Robert Gonzalez +** +** This file is part of Sirius_Solver. +** This program and the accompanying materials are made available under the +** terms of the Eclipse Public License 2.0 which is available at +** http://www.eclipse.org/legal/epl-2.0. +** +** This Source Code may also be made available under the following Secondary +** Licenses when the conditions for such availability set forth in the Eclipse +** Public License, v. 2.0 are satisfied: GNU General Public License, version 3 +** or later, which is available at . +** +** SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 +*/ +/*********************************************************************** + + FONCTION: Verification du calcul de l'inverse de la ligne de la base + correspondant a la variable sortante. + + AUTEUR: R. GONZALEZ + +************************************************************************/ + +# include "spx_sys.h" + +# include "spx_fonctions.h" +# include "spx_define.h" + +# include "pne_fonctions.h" + +# define CYCLE_DE_VERIFICATION_DE_ERBMOINS1_HYPER_CREUX 20 + +# define SEUIL_DE_VERIFICATION_DE_ErBMoinsUn_1 1.e-6 /*1.e-6*/ +# define SEUIL_DE_VERIFICATION_DE_ErBMoinsUn_1a 1.e-6 /*1.e-6*/ +# define SEUIL_DE_VERIFICATION_DE_ErBMoinsUn_2 1.e-6 /*1.e-6*/ +# define SEUIL_DE_VERIFICATION_DE_ErBMoinsUn_2a 1.e-6 /*1.e-6*/ +# define NOMBRE_DE_VERIFICATIONS 100 /*10*/ + +# define NBITER_RAFFINEMENT 0 +# define NBITER_RAFFINEMENT_a 0 + +# define VERBOSE_SPX 0 + +/*----------------------------------------------------------------------------*/ +/* Verification du calcule de la ligne de B^{-1} qui + correspond a la variable sortante: on verifie sur k contraintes + tirees au hasard */ + +void SPX_DualVerifierErBMoinsUn( PROBLEME_SPX * Spx ) + +{ +int Cnt; int Var; int il; int ilMax; double S; int NbFois; int Nombre; double X; +int * VariableEnBaseDeLaContrainte; int * Cdeb; int * CNbTerm; int * NumeroDeContrainte; +double * ACol; double * ErBMoinsUn; char Imprecision; int VariableSortante; +int NombreDeContraintes; int NbTermesNonNulsDeErBMoinsUn; int * IndexTermesNonNulsDeErBMoinsUn; int j; +int * T; double * Bs; char * PositionDeLaVariable; int * Mdeb ; int * NbTerm; int * Indcol; double * A; +int * ContrainteDeLaVariableEnBase; int NombreDeValeursNonNulles; int * NumCntNonNul; +int CntCol; int CntBase; char CntBaseControle; + +/* +printf("Attention verif SPX_DualVerifierErBMoinsUn Iteration %d\n",Spx->Iteration); +*/ + +/* Si on est en stockage hyper creux on verifie tout le vecteur */ +if ( Spx->TypeDeStockageDeErBMoinsUn != COMPACT_SPX ) goto CCC; + +if ( Spx->Iteration % CYCLE_DE_VERIFICATION_DE_ERBMOINS1_HYPER_CREUX != 0 ) return; + +VariableSortante = Spx->VariableSortante; + +ErBMoinsUn = Spx->ErBMoinsUn; +IndexTermesNonNulsDeErBMoinsUn = Spx->IndexTermesNonNulsDeErBMoinsUn; +NbTermesNonNulsDeErBMoinsUn = Spx->NbTermesNonNulsDeErBMoinsUn; +T = Spx->T; +Bs = Spx->Bs; + +Mdeb = Spx->Mdeb; +NbTerm = Spx->NbTerm; +Indcol = Spx->Indcol; +A = Spx->A; + +PositionDeLaVariable = Spx->PositionDeLaVariable; + +ContrainteDeLaVariableEnBase = Spx->ContrainteDeLaVariableEnBase; + +NumCntNonNul = (int *) Spx->V; +CntBase = ContrainteDeLaVariableEnBase[VariableSortante]; + +NombreDeValeursNonNulles = 0; +for ( j = 0 ; j < NbTermesNonNulsDeErBMoinsUn ; j++ ) { + X = ErBMoinsUn[j]; + Cnt = IndexTermesNonNulsDeErBMoinsUn[j]; + il = Mdeb[Cnt]; + ilMax = il + NbTerm[Cnt]; + while ( il < ilMax ) { + if ( PositionDeLaVariable[Indcol[il]] == EN_BASE_LIBRE ) { + CntCol = ContrainteDeLaVariableEnBase[Indcol[il]]; + if ( T[CntCol] == 1 ) { + Bs[CntCol] += X * A[il]; + } + else { + T[CntCol] = 1; + Bs[CntCol] = X * A[il]; + NumCntNonNul[NombreDeValeursNonNulles] = CntCol; + NombreDeValeursNonNulles++; + } + } + il++; + } +} + +/*for ( j = 0 ; j < NombreDeValeursNonNulles ; j++ ) T[NumCntNonNul[j]] = -1;*/ + +CntBaseControle = NON_SPX; + +for ( j = 0 ; j < NombreDeValeursNonNulles ; j++ ) { + CntCol = NumCntNonNul[j]; + X = Bs[CntCol]; + if ( CntCol == CntBase ) { + CntBaseControle = OUI_SPX; + S = 1.; + } + else S = 0.0; + if ( fabs( X - S ) > SEUIL_DE_VERIFICATION_DE_ErBMoinsUn_1 ) { + Imprecision = OUI_SPX; + if ( Spx->NombreDeChangementsDeBase < 10 ) { + /* Si ca se produit dans les premieres iterations apres une factorisation */ + Spx->FlagStabiliteDeLaFactorisation = 1; + } + # if VERBOSE_SPX + printf("Controle Hyper Creux SPX_DualVerifierErBMoinsUn Iteration %d Phase %d erreur de resolution sur ErBMoinsUn: %e", + Spx->Iteration,(int) Spx->PhaseEnCours,fabs( X-S )); + printf(" ecart trop grand on refactorise la base Spx->StrongBranchingEnCours %d\n",(int) Spx->StrongBranchingEnCours); + # endif + Spx->FactoriserLaBase = OUI_SPX; + CntBaseControle = OUI_SPX; + /* On augmente le seuil dual de pivotage */ + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + # if VERBOSE_SPX + printf("SeuilDePivotDual -> %e\n",Spx->SeuilDePivotDual); + # endif + Spx->FaireDuRaffinementIteratif = NBITER_RAFFINEMENT; + if ( fabs( X - S ) > SEUIL_DE_VERIFICATION_DE_ErBMoinsUn_1a ) { + Spx->FaireDuRaffinementIteratif = NBITER_RAFFINEMENT_a; + Spx->FaireChangementDeBase = NON_SPX; + # if VERBOSE_SPX + printf("Le changement de base est refuse\n"); + # endif + } + break; + } +} +if ( CntBaseControle == NON_SPX ) { + # if VERBOSE_SPX + printf("Controle Hyper Creux SPX_DualVerifierErBMoinsUn Iteration %d erreur de resolution sur ErBMoinsUn pour la contrainte basique\n", + Spx->Iteration); + printf("NombreDeValeursNonNulles de Bs %d\n",NombreDeValeursNonNulles); + # endif + Spx->FactoriserLaBase = OUI_SPX; + Spx->FaireDuRaffinementIteratif = NBITER_RAFFINEMENT; + /* On augmente le seuil dual de pivotage */ + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + # if VERBOSE_SPX + printf("SeuilDePivotDual -> %e\n",Spx->SeuilDePivotDual); + # endif + Spx->FaireChangementDeBase = NON_SPX; +} + +for ( j = 0 ; j < NombreDeValeursNonNulles ; j++ ) { + Cnt = NumCntNonNul[j]; + T[Cnt] = -1; + Bs[Cnt] = 0; +} + +return; + +CCC: + +VariableEnBaseDeLaContrainte = Spx->VariableEnBaseDeLaContrainte; + +Cdeb = Spx->Cdeb; +CNbTerm = Spx->CNbTerm; +ACol = Spx->ACol; +NumeroDeContrainte = Spx->NumeroDeContrainte; + +NombreDeContraintes = Spx->NombreDeContraintes; +ErBMoinsUn = Spx->ErBMoinsUn; +VariableSortante = Spx->VariableSortante; +Imprecision = NON_SPX; + +NbFois = 0; + +while ( NbFois < NOMBRE_DE_VERIFICATIONS ) { + /* On tire un nombre au hasard compris entre 0 et NombreDeContraintes - 1 */ + + # if UTILISER_PNE_RAND == OUI_SPX + Spx->A1 = PNE_Rand( Spx->A1 ); + X = Spx->A1 * (NombreDeContraintes - 1); + # else + X = rand() * Spx->UnSurRAND_MAX * (NombreDeContraintes - 1); + # endif + + Nombre = (int) X; + if ( Nombre >= NombreDeContraintes ) Nombre = NombreDeContraintes - 1; + Cnt = Nombre; + Var = VariableEnBaseDeLaContrainte[Cnt]; + /* Verification */ + S = 0.; + if ( Var == VariableSortante ) S = -1.; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + S+= ACol[il] * ErBMoinsUn[NumeroDeContrainte[il]]; + il++; + } + if ( fabs( S ) > SEUIL_DE_VERIFICATION_DE_ErBMoinsUn_1 ) { + Imprecision = OUI_SPX; + if ( Spx->NombreDeChangementsDeBase < 10 ) { + /* Si ca se produit dans les premieres iterations apres une factorisation */ + Spx->FlagStabiliteDeLaFactorisation = 1; + } + break; + } + NbFois++; +} + +if ( Imprecision == OUI_SPX ) { + /* Suspiscion: on recalcule l'ecart moyen pour voir s'il faut refactoriser */ + S = 0.0; + for ( Cnt = 0 ; Cnt < NombreDeContraintes ; Cnt++ ) { + Var = VariableEnBaseDeLaContrainte[Cnt]; + X = 0.; + if ( Var == VariableSortante ) X = -1.; + il = Cdeb[Var]; + ilMax = il + CNbTerm[Var]; + while ( il < ilMax ) { + X+= ACol[il] * ErBMoinsUn[NumeroDeContrainte[il]]; + il++; + } + S+= fabs( X ); + } + S/= NombreDeContraintes; + if ( S > SEUIL_DE_VERIFICATION_DE_ErBMoinsUn_2 && Spx->NombreDeChangementsDeBase > 0 ) { + #if VERBOSE_SPX + printf("SPX_DualVerifierErBMoinsUn Iteration %d Phase %d erreur de resolution sur ErBMoinsUn: %e", + Spx->Iteration,(int) Spx->PhaseEnCours,fabs( S )); + printf(" ecart trop grand on refactorise la base \n"); + #endif + Spx->FactoriserLaBase = OUI_SPX; + /* On augmente le seuil dual de pivotage */ + Spx->SeuilDePivotDual = COEFF_AUGMENTATION_VALEUR_DE_PIVOT_ACCEPTABLE * VALEUR_DE_PIVOT_ACCEPTABLE; + #if VERBOSE_SPX + printf("SeuilDePivotDual -> %e\n",Spx->SeuilDePivotDual); + #endif + Spx->FaireDuRaffinementIteratif = NBITER_RAFFINEMENT; + if ( S > SEUIL_DE_VERIFICATION_DE_ErBMoinsUn_2a ) { + Spx->FaireDuRaffinementIteratif = NBITER_RAFFINEMENT_a; + Spx->FaireChangementDeBase = NON_SPX; + #if VERBOSE_SPX + printf("Le changement de base est refuse\n"); + #endif + } + } + else Spx->FaireDuRaffinementIteratif = NBITER_RAFFINEMENT; +} + +return; +} + + + diff --git a/src/ext/ext changelog.txt b/src/ext/ext changelog.txt new file mode 100644 index 0000000000..d8244dcee0 --- /dev/null +++ b/src/ext/ext changelog.txt @@ -0,0 +1,35 @@ +Starting ANTARES version 6.0.0: +=============================== + +* libcurl-7.51.0 +* openssl-1.0.2j +* wxwidgets-3.0.2 +* yuni-1.1.1 + +openssl build options +x64: +"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" +cd ${ANTARES}\src\ext\openssl +perl Configure VC-WIN64A --prefix=vc-release-x86_64 no-shared +ms\do_win64a +nmake -f ms\nt.mak +nmake -f ms\nt.mak install + +x86: +"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat" +cd ${ANTARES}\src\ext\openssl +perl Configure VC-WIN32 no-asm --prefix=vc-release-x86 no-shared +ms\do_ms +nmake -f ms\nt.mak +nmake -f ms\nt.mak install + +libcurl build options +x86: +"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\vcvars32.bat" +cd ${ANTARES}\src\ext\libcurl\winbuild +nmake /f Makefile.vc mode=static VC=14 WITH_SSL=static WITH_DEVEL=../../openssl/vc-release-x86 ENABLE_SSPI=no ENABLE_IDN=no ENABLE_WINSSL=no GEN_PDB=no DEBUG=no MACHINE=x86 + +x64: +"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat" +cd ${ANTARES}\src\ext\libcurl\winbuild +nmake /f Makefile.vc mode=static VC=14 WITH_SSL=static WITH_DEVEL=../../openssl/vc-release-x86_64 ENABLE_SSPI=no ENABLE_IDN=no ENABLE_WINSSL=no GEN_PDB=no DEBUG=no MACHINE=x64 diff --git a/src/ext/libcurl b/src/ext/libcurl new file mode 160000 index 0000000000..3c561c657c --- /dev/null +++ b/src/ext/libcurl @@ -0,0 +1 @@ +Subproject commit 3c561c657c2f0e553b19115a506592a8bbd744bc diff --git a/src/ext/openssl b/src/ext/openssl new file mode 160000 index 0000000000..e216bf9d7c --- /dev/null +++ b/src/ext/openssl @@ -0,0 +1 @@ +Subproject commit e216bf9d7ca761718f34e8b3094fcb32c7a143e4 diff --git a/src/ext/wxwidgets b/src/ext/wxwidgets new file mode 160000 index 0000000000..37aa8123b5 --- /dev/null +++ b/src/ext/wxwidgets @@ -0,0 +1 @@ +Subproject commit 37aa8123b5fa79702a6c77a5fd3f05d811d688b6 diff --git a/src/ext/yuni/AUTHORS.txt b/src/ext/yuni/AUTHORS.txt new file mode 100644 index 0000000000..f0857a2a63 --- /dev/null +++ b/src/ext/yuni/AUTHORS.txt @@ -0,0 +1,6 @@ +Damien GERARD +Bruno BORRI +AurĂ©lien GUILLAUME + +Contributors: +Roland BROCHARD diff --git a/src/ext/yuni/bin/__license-header.txt b/src/ext/yuni/bin/__license-header.txt new file mode 100644 index 0000000000..95aa3a6879 --- /dev/null +++ b/src/ext/yuni/bin/__license-header.txt @@ -0,0 +1,933 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + libyuni/__license-header.txt at v1.1.0 · libyuni/libyuni + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Skip to content +
+ + + + + + + + + + + + +
+ +
+ +
+
+ + + +
+
+
+ + + + + + + + + + +
+
+ +
    +
  • +
    + +
    + + + +
    +
    +
    + + Notifications +
    + + + +
    +
    +
    +
    +
  • + +
  • + +
    +
    + + + +
    +
    + + + +
    + +
  • + +
  • +
    + +
    + +
  • +
+ +

+ + /libyuni + +

+ +
+ + + + +
+ +
+
+ + + Permalink + + + + + +
+ +
+ + +
+ +
+
+ + Switch branches/tags +
+ +
+
+ +
+
+ +
+
+ + + + + +
+
+
+ +
+ + Find file + + + Copy path + +
+ +
+ + + +
+ Fetching contributors… +
+ +
+ + Cannot retrieve contributors at this time +
+
+ + +
+
+
+ +
+ Raw + Blame + History +
+ + + + + +
+ +
+ 11 lines (10 sloc) + + 401 Bytes +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
/*
** This file is part of libyuni, a cross-platform C++ framework (http://libyuni.org).
**
** This Source Code Form is subject to the terms of the Mozilla Public License
** v.2.0. If a copy of the MPL was not distributed with this file, You can
** obtain one at http://mozilla.org/MPL/2.0/.
**
** github: https://github.com/libyuni/libyuni/
** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror)
*/
+ + + +
+ +
+ + + + + +
+ +
+ +
+
+ +
+ + + + + + +
+ + + You can’t perform that action at this time. +
+ + + + + + + + + +
+ + You signed in with another tab or window. Reload to refresh your session. + You signed out in another tab or window. Reload to refresh your session. +
+ + + + +
+ Press h to open a hovercard with more details. +
+ + + + + diff --git a/src/ext/yuni/bin/clean.sh b/src/ext/yuni/bin/clean.sh new file mode 100755 index 0000000000..56df69980a --- /dev/null +++ b/src/ext/yuni/bin/clean.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +root=`dirname "${0}"` + +find "${root}/../src" '(' \ + -name 'cmake_install.cmake' \ + -or -name 'CMakeCache.txt' \ + -or -name 'CMakeFiles' \ + -or -name 'Makefile' \ + -or -name '*.xcodeproj' \ + -or -name 'CMakeScripts' \ + -or -name '*.o' \ + -or -name '.*.sw*' \ + ')' -exec echo ' * Removing `' '{}' '`' \; -exec rm -rf '{}' \; + +# yuni-config +rm -f "${root}/../src/tools/yuni-config/yuni-config" diff --git a/src/ext/yuni/bin/unzip.exe b/src/ext/yuni/bin/unzip.exe new file mode 100755 index 0000000000..b10387734a Binary files /dev/null and b/src/ext/yuni/bin/unzip.exe differ diff --git a/src/ext/yuni/bin/yuni-devpack-make.sh b/src/ext/yuni/bin/yuni-devpack-make.sh new file mode 100755 index 0000000000..b2069d8902 --- /dev/null +++ b/src/ext/yuni/bin/yuni-devpack-make.sh @@ -0,0 +1,413 @@ +#! /bin/sh + +# -- Default settings -- +pkgName="" +pkgVersion="" +pkgRevision="r1" +pkgOS="" +pkgArch="`uname -m`" +pkgCompiler="" +pkgSource="" +pkgCompiler="g++" +pkgTarget="" + +zip="" +zipFromUser=0 +find="" +mktemp="" + +targetFolder=`dirname "$0"` + + + +# +# \brief Print the absolute path of a given path +# +# \param $1 A relative or absolute path +# \return (echo) The absolute path +# +rel2abs() +{ + # make sure file is specified + if [ -z "$1" ] + then + echo "$1" + return 1 + fi + # already absolute case + if [ "${1:0:1}" = "/" ] || [ "$PWD" = "/" ] + then + ABS="" + else + ABS="$PWD" + fi + # loop thru path + IFS="/" + for DIR in $1 + do + if [ -n "$DIR" ] + then + if [ "$DIR" = ".." ] + then + ABS="${ABS%/*}" + elif [ "$DIR" != "." ] + then + ABS="$ABS/$DIR" + fi + fi + done + IFS=":" + echo "$ABS" + return 0 +} + + + +# +# \brief Try to find all needed programs +# +checkEnv() +{ + if [ "x${find}" = "x" -o ! -x "${find}" ]; then + find=`which find` + if [ "x${find}" = "x" -o ! -x "${find}" ]; then + echo "The program 'find' is missing or could not be found. Aborting now." + exit 3 + fi + fi + if [ "x${mktemp}" = "x" -o ! -x "${mktemp}" ]; then + mktemp=`which mktemp` + if [ "x${mktemp}" = "x" -o ! -x "${mktemp}" ]; then + echo "The program 'mktemp' is missing or could not be found. Aborting now." + exit 3 + fi + fi + if [ "x${zip}" = "x" -o ! -x "${zip}" ]; then + zip=`which zip` + if [ "x${zip}" = "x" -o ! -x "${zip}" ]; then + echo "The program 'zip' is missing or could not be found. Aborting now." + exit 3 + fi + fi +} + + + + +# +# \brief Generate a summary of all settings +# +printPkgSettings() +{ + if [ ! "x${pkgName}" = "x" ]; then + echo " * Package: '${pkgName}'" + fi + if [ ! "x${pkgVersion}" = "x" ]; then + echo " * Version: '${pkgVersion}'" + fi + if [ ! "x${pkgRevision}" = "x" ]; then + echo " * Revision: '${pkgRevision}'" + fi + if [ ! "x${pkgOS}" = "x" ]; then + echo " * OS: '${pkgOS}'" + fi + if [ ! "x${pkgArch}" = "x" ]; then + echo " * Arch: '${pkgArch}'" + fi + if [ ! "x${pkgCompiler}" = "x" ]; then + echo " * Compiler: '${pkgCompiler}'" + fi + if [ ! "x${pkgSource}" = "x" ]; then + echo " * Source: '${pkgSource}'" + fi + if [ ! "x${pkgTarget}" = "x" ]; then + echo " * Source: '${pkgTarget}'" + fi + if [ "${zipFromUser}" -eq 1 ]; then + echo " * zip: '${zip}' (user)" + else + echo " * zip: '${zip}' (auto)" + fi +} + + + +# +# \brief Check if a folder exists +# +# If the folder does not exist, the script will abort (exit 5) +# +checkSingleFolder() +{ + if [ ! -d "${1}" ]; then + echo "[ERROR] Invalid DevPack structure: The folder '${1}' is missing" + exit 5 + fi +} + +# +# \brief Check if a file exists +# +# If the file does not exist, the script will abort (exit 5) +# +checkSingleFile() +{ + if [ ! -f "${1}" ]; then + echo "[ERROR] Invalid DevPack structure: The file '${1}' is missing" + exit 5 + fi +} + + +# +# \brief Check the consistency of a dev pack folder +# \param $1 The folder +# +checkDevPackFolderConsistency() +{ + checkSingleFolder "${1}/${pkgVersion}/${pkgRevision}/${pkgArch}/cmake" + cmakelist="CMakeLists-${pkgName}-${pkgOS}-${pkgCompiler}-${pkgTarget}.cmake" + checkSingleFile "${1}/${pkgVersion}/${pkgRevision}/${pkgArch}/cmake/${cmakelist}" + checkSingleFolder "${1}/${pkgVersion}/${pkgRevision}/${pkgArch}/${pkgCompiler}" + #checkSingleFolder "${1}/${pkgVersion}/${pkgRevision}/${pkgArch}/${pkgCompiler}/include" + #checkSingleFolder "${1}/${pkgVersion}/${pkgRevision}/${pkgArch}/${pkgCompiler}/lib" +} + + + + + +# +# \brief Generate the Help +# +help() +{ + echo "Yuni - Package maker for external dependencies" + echo "Usage: `basename "$0"` [] " + echo "Options:" + echo " -n : Name of the package (ex: '-n irrlicht', '-n lua')" + echo " -v : Version of the package (ex: '-v1.4.1')" + echo " -r : Revision for the package (ex: '-r2')" + echo " -o : Operating system (ex: '-o macos', '-o linux', '-o windows)" + echo " -a : Architecture (ex: '-a 386', '-a ppc', '-a ub')" + echo " -f : Target folder for the package" + echo " -c : Compiler (ex: '-c vs9', '-c mingw', '-c g++', '-c g++4.2')" + echo " -t : Target (ex: '-t release', '-t debug')" + echo " -z : The absolute path to the program 'zip' to use to compress (archive) files (ex: '-z/usr/bin/zip')" + echo " -h : This help" + echo + echo "Example:" + echo " ./makepackage.sh -n lua -v5.1.4 -r3 ~/somewhere/on/my/disks/my-devpacks/lua" + echo + echo "Note: The source directory should be like this :" + echo " + " + echo " |- " + echo " \- " + echo " \- " + echo " |- cmake (.cmake)" + echo " |- (g++, vs9...)" + echo " |- include (.h)" + echo " \- lib" + echo " |- debug/ (.a,.so,.dll,.lib)" + echo " \- release/ (.a,.so,.dll,.lib)" + echo + exit 0 # Exits now +} + + + + +# +# \brief Operating System Auto Detection +# +operatingSystemAutoDetection() +{ + unamedata=`uname -a` + pkgOS="" + if [ ! "`echo "${unamedata}" | grep -i Darwin`" = "" ]; then + pkgOS="macos" ; return + fi + if [ ! "`echo "${unamedata}" | grep -i Linux`" = "" ]; then + pkgOS="linux" ; return + fi + if [ ! "`echo "${unamedata}" | grep -i SunOS`" = "" ]; then + pkgOS="sun" ; return + fi + if [ ! "`echo "${unamedata}" | grep -i HP-UX`" = "" ]; then + pkgOS="hpux" ; return + fi + if [ ! "`echo "${unamedata}" | grep -i FreeBSD`" = "" ]; then + pkgOS="freebsd" ; return + fi + if [ ! "`echo "${unamedata}" | grep -i DargonFly`" = "" ]; then + pkgOS="dragonfly" ; return + fi + if [ ! "`echo "${unamedata}" | grep -i Cygwin`" = "" ]; then + pkgOS="cygwin" ; return + fi +} + +# Try to detect the OS +operatingSystemAutoDetection + + + + + +# Parse all command line arguments +# +# All options +args=`getopt n:v:r:o:c:a:s:z:f:t:h $*` +# Help +if [ $? != 0 ]; then + help +fi +# All other options +set -- $args +for i +do + case "$i" + in + -h) help; shift;; + -n) pkgName="$2"; shift; shift;; + -v) pkgVersion="$2"; shift; shift;; + -r) pkgRevision="r$2"; shift; shift;; + -o) pkgOS="$2"; shift; shift;; + -a) pkgArch="$2"; shift; shift;; + -c) pkgCompiler="$2"; shift; shift;; + -t) pkgTarget="$2"; shift; shift;; + -f) targetFolder="$2"; shift; shift;; + -z) zip="$2"; zipFromUser=1; shift; shift;; + --) shift; break;; + esac +done + +# The unmatched command line argument is devpack source folder +pkgSource="$*" + +# Get the absolute path for the target folder +targetFolder=`rel2abs "${targetFolder}"` + + + +# Check the env (all needed programs) +checkEnv + + + +# +# --- Start the packaging --- +# +echo "Yuni - Package maker for external dependencies" +printPkgSettings + + + + + +# Check the consistency of all settings +good='1' +if [ "x${pkgName}" = "x" ]; then + echo "[ERROR] The name of the package is missing (ex: '-n irrlicht', '-n lua')" + good='0' +fi +if [ "x${pkgVersion}" = "x" ]; then + echo "[ERROR] The version is missing (ex: '-v1.4.1')" + good='0' +fi +if [ "x${pkgRevision}" = "x" ]; then + echo "[ERROR] The revision is missing (ex: '-r2')" + good='0' +fi +if [ "x${pkgOS}" = "x" ]; then + echo "[ERROR] The operating system is missing (ex: '-o macos', '-o linux', '-o windows')" + good='0' +fi +if [ "x${pkgArch}" = "x" ]; then + echo "[ERROR] The architecture is missing (ex: '-a i386', '-a ppc', '-a ub')" + good='0' +fi +if [ "x${pkgCompiler}" = "x" ]; then + echo "[ERROR] The compiler is missing (ex: '-c vs9', '-c mingw', '-c g++', '-c g++4.2')" + good='0' +fi +if [ "x${pkgTarget}" = "x" ]; then + echo "[ERROR] The target is missing (ex: '-t release', '-t debug')" + good='0' +fi + + +if [ "x${pkgSource}" = "x" ]; then + echo "[ERROR] The source directory is missing" + good='0' +fi + + +if [ "${good}" -eq 0 ]; then + echo "An error has occured. To have more informations please use type ''`basename "$0"` -h''" + echo "Aborting." + exit 1 +fi + + +# The target DevPack - compressed file +target="${targetFolder}/${pkgName}-${pkgVersion}-${pkgRevision}-${pkgOS}-${pkgArch}-${pkgCompiler}-${pkgTarget}.zip" +echo " * Archive : ${target}" +if [ -f "${target}" ]; then + echo "The archive file already exists. Aborting." + exit 1 +fi + + +# Check the source folder consistency +checkDevPackFolderConsistency "${pkgSource}" + + + +# The `yndevpack-*` file +devpackfile="yndevpack-${pkgName}-${pkgVersion}-${pkgRevision}-${pkgOS}-${pkgArch}-${pkgCompiler}-${pkgTarget}" +devpack="${pkgSource}/${devpackfile}" +if [ ! -f "${devpack}" ]; then + shouldDeleteDevPackIndex=1 +else + shouldDeleteDevPackIndex=0 +fi +echo 1 > "${devpack}" + +# The tmpfile is the list of files to include +tmpfile=`"${mktemp}" -t yunipackagemaker.XXXXXX` || exit 4 + + +# && "${find}" . '(' -path ''*/${pkgVersion}/r${pkgRevision}/${pkgArch}/${pkgCompiler}/*'' -and ! -path '*/.*' -and ! -name '*.o' -and ! -name '#*' ')' > "${tmpfile}" \ + +# What files to include +cmakelist="CMakeLists-${pkgName}-${pkgOS}-${pkgCompiler}-${pkgTarget}.cmake" +cd "${pkgSource}" \ + && echo "Searching files to include into the package..." \ + && "${find}" . '(' -regex "\./${pkgVersion}/${pkgRevision}/${pkgArch}/${pkgCompiler}/.*" -and -not -name '.*' -and -not -iname '*.o' -and -not -name '#*' ')' > "${tmpfile}" \ + && echo "./${pkgVersion}/${pkgRevision}/${pkgArch}/cmake/${cmakelist}" >> "${tmpfile}" \ + && echo "./${devpackfile}" >> "${tmpfile}" \ + && echo "Creating the archive... Please wait..." \ + && "${zip}" -n .Z:.zip:.png:.gif:.snd:.mp3:.jpg:.rar:.bz2:.gz -Xyr "${target}" . -i@"${tmpfile}" +result="$?" +if [ "${result}" -eq 0 ]; then + echo "The package is ready: '${target}'" +else + echo "[ERROR] An error has occured. Aborting." +fi + + + +# Removing the tmp files +rm -f "${tmpfile}" +if [ -f "${tmpfile}" ]; then + echo "[WARNING] The temporary file should be removed: '${tmpfile}'" +fi +if [ "${shouldDeleteDevPackIndex}" -eq 1 ]; then + rm -f "${devpack}" +fi + + +# Done. +echo "Done." + diff --git a/src/ext/yuni/bin/yuni-extract-headers.sh b/src/ext/yuni/bin/yuni-extract-headers.sh new file mode 100755 index 0000000000..32a6615002 --- /dev/null +++ b/src/ext/yuni/bin/yuni-extract-headers.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +# This script is designed to extract all headers from the sources and to copy them +# into a given folder +# +# Those headers could be distributed within an archive for example +# + +if [ "x${1}" = "x" ]; then + echo "Target folder: argument required" + exit 1 +fi + + +root=`dirname "${0}"` +source="${root}/../src/yuni" +target="${1}" + + +echo "Extracting the Yuni Headers..." +echo " . From '${source}'" +echo " . To '${target}'" +echo " . Searching..." + +# Find all files +list=`cd "${source}" && find . '(' \ + '(' -name '*.h' -or -name '*.hxx' ')' \ + -and ! -path "./private*" \ + -and -type f ')' -print -depth | sort ` + +IFS=" +" + +count=0 +for i in ${list}; do + count=`expr "${count}" '+' 1` +done + +echo " ${count} headers found" + + +echo " . Copying..." +if [ -e "${target}" ]; then + rm -rf "${target}" +fi + +count=0 +lastFolder='' + +for i in ${list}; do + count=`expr "${count}" '+' 1` + sourceFile="${source}/${i}" + targetFile="${target}/${i}" + folder=`dirname "${targetFile}"` + + if [ ! "x${folder}" = "x${lastFolder}" ]; then + # The folder has changed + lastFolder="${folder}" + mkdir -p "${folder}" + fi + + cp -f "${sourceFile}" "${targetFile}" +done + diff --git a/src/ext/yuni/license.md b/src/ext/yuni/license.md new file mode 100644 index 0000000000..37f4f2a5db --- /dev/null +++ b/src/ext/yuni/license.md @@ -0,0 +1,1318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + libyuni/license.md at v1.1.0 · libyuni/libyuni + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Skip to content +
+ + + + + + + + + + + + +
+ +
+ +
+
+ + + +
+
+
+ + + + + + + + + + +
+
+ +
    +
  • +
    + +
    + + + +
    +
    +
    + + Notifications +
    + + + +
    +
    +
    +
    +
  • + +
  • + +
    +
    + + + +
    +
    + + + +
    + +
  • + +
  • +
    + +
    + +
  • +
+ +

+ + /libyuni + +

+ +
+ + + + +
+ +
+
+ + + Permalink + + + + + +
+ +
+ + +
+ +
+
+ + Switch branches/tags +
+ +
+
+ +
+
+ +
+
+ + + + + +
+
+
+ +
+ + Find file + + + Copy path + +
+ +
+ +
+
+ +

+ libyuni/libyuni is licensed under the +

+

Mozilla Public License 2.0

+

Permissions of this weak copyleft license are conditioned on making available source code of licensed files and modifications of those files under the same license (or in certain cases, one of the GNU licenses). Copyright and license notices must be preserved. Contributors provide an express grant of patent rights. However, a larger work using the licensed work may be distributed under different terms and without source code for files added in the larger work.

+
+ +
+ + + +
+ +

+ This is not legal advice. + Learn more about repository licenses. +

+
+ + + +
+ + + d8f102a + + Jan 28, 2016 + + + +
+ + +
+ + +
+ + + +
+
+
+ +
+ Raw + Blame + History +
+ + + + + +
+ +
+ 370 lines (283 sloc) + + 15.2 KB +
+
+ + +
+

Mozilla Public License Version 2.0

+
    +
  1. Definitions
  2. +
+
+

1.1. "Contributor" +means each individual or legal entity that creates, contributes to +the creation of, or owns Covered Software.

+

1.2. "Contributor Version" +means the combination of the Contributions of others (if any) used +by a Contributor and that particular Contributor's Contribution.

+

1.3. "Contribution" +means Covered Software of a particular Contributor.

+

1.4. "Covered Software" +means Source Code Form to which the initial Contributor has attached +the notice in Exhibit A, the Executable Form of such Source Code +Form, and Modifications of such Source Code Form, in each case +including portions thereof.

+

1.5. "Incompatible With Secondary Licenses" +means

+
(a) that the initial Contributor has attached the notice described
+    in Exhibit B to the Covered Software; or
+
+(b) that the Covered Software was made available under the terms of
+    version 1.1 or earlier of the License, but not also under the
+    terms of a Secondary License.
+
+

1.6. "Executable Form" +means any form of the work other than Source Code Form.

+

1.7. "Larger Work" +means a work that combines Covered Software with other material, in +a separate file or files, that is not Covered Software.

+

1.8. "License" +means this document.

+

1.9. "Licensable" +means having the right to grant, to the maximum extent possible, +whether at the time of the initial grant or subsequently, any and +all of the rights conveyed by this License.

+

1.10. "Modifications" +means any of the following:

+
(a) any file in Source Code Form that results from an addition to,
+    deletion from, or modification of the contents of Covered
+    Software; or
+
+(b) any new file in Source Code Form that contains any Covered
+    Software.
+
+

1.11. "Patent Claims" of a Contributor +means any patent claim(s), including without limitation, method, +process, and apparatus claims, in any patent Licensable by such +Contributor that would be infringed, but for the grant of the +License, by the making, using, selling, offering for sale, having +made, import, or transfer of either its Contributions or its +Contributor Version.

+

1.12. "Secondary License" +means either the GNU General Public License, Version 2.0, the GNU +Lesser General Public License, Version 2.1, the GNU Affero General +Public License, Version 3.0, or any later versions of those +licenses.

+

1.13. "Source Code Form" +means the form of the work preferred for making modifications.

+

1.14. "You" (or "Your") +means an individual or a legal entity exercising rights under this +License. For legal entities, "You" includes any entity that +controls, is controlled by, or is under common control with You. For +purposes of this definition, "control" means (a) the power, direct +or indirect, to cause the direction or management of such entity, +whether by contract or otherwise, or (b) ownership of more than +fifty percent (50%) of the outstanding shares or beneficial +ownership of such entity.

+
    +
  1. License Grants and Conditions
  2. +
+
+

2.1. Grants

+

Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license:

+

(a) under intellectual property rights (other than patent or trademark) +Licensable by such Contributor to use, reproduce, make available, +modify, display, perform, distribute, and otherwise exploit its +Contributions, either on an unmodified basis, with Modifications, or +as part of a Larger Work; and

+

(b) under Patent Claims of such Contributor to make, use, sell, offer +for sale, have made, import, and otherwise transfer either its +Contributions or its Contributor Version.

+

2.2. Effective Date

+

The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution.

+

2.3. Limitations on Grant Scope

+

The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor:

+

(a) for any code that a Contributor has removed from Covered Software; +or

+

(b) for infringements caused by: (i) Your and any other third party's +modifications of Covered Software, or (ii) the combination of its +Contributions with other software (except as part of its Contributor +Version); or

+

(c) under Patent Claims infringed by Covered Software in the absence of +its Contributions.

+

This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4).

+

2.4. Subsequent Licenses

+

No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3).

+

2.5. Representation

+

Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License.

+

2.6. Fair Use

+

This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents.

+

2.7. Conditions

+

Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1.

+
    +
  1. Responsibilities
  2. +
+
+

3.1. Distribution of Source Form

+

All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form.

+

3.2. Distribution of Executable Form

+

If You distribute Covered Software in Executable Form then:

+

(a) such Covered Software must also be made available in Source Code +Form, as described in Section 3.1, and You must inform recipients of +the Executable Form how they can obtain a copy of such Source Code +Form by reasonable means in a timely manner, at a charge no more +than the cost of distribution to the recipient; and

+

(b) You may distribute such Executable Form under the terms of this +License, or sublicense it under different terms, provided that the +license for the Executable Form does not attempt to limit or alter +the recipients' rights in the Source Code Form under this License.

+

3.3. Distribution of a Larger Work

+

You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s).

+

3.4. Notices

+

You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies.

+

3.5. Application of Additional Terms

+

You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction.

+
    +
  1. Inability to Comply Due to Statute or Regulation
  2. +
+
+

If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it.

+
    +
  1. Termination
  2. +
+
+

5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice.

+

5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate.

+

5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination.

+
    +
  1. Disclaimer of Warranty
  2. +
+
+
+

Covered Software is provided under this License on an "as is" +basis, without warranty of any kind, either expressed, implied, or +statutory, including, without limitation, warranties that the +Covered Software is free of defects, merchantable, fit for a +particular purpose or non-infringing. The entire risk as to the +quality and performance of the Covered Software is with You. +Should any Covered Software prove defective in any respect, You +(not any Contributor) assume the cost of any necessary servicing, +repair, or correction. This disclaimer of warranty constitutes an +essential part of this License. No use of any Covered Software is +authorized under this License except under this disclaimer.

+
+
    +
  1. Limitation of Liability
  2. +
+
+
+

Under no circumstances and under no legal theory, whether tort +(including negligence), contract, or otherwise, shall any +Contributor, or anyone who distributes Covered Software as +permitted above, be liable to You for any direct, indirect, +special, incidental, or consequential damages of any character +including, without limitation, damages for lost profits, loss of +goodwill, work stoppage, computer failure or malfunction, or any +and all other commercial damages or losses, even if such party +shall have been informed of the possibility of such damages. This +limitation of liability shall not apply to liability for death or +personal injury resulting from such party's negligence to the +extent applicable law prohibits such limitation. Some +jurisdictions do not allow the exclusion or limitation of +incidental or consequential damages, so this exclusion and +limitation may not apply to You.

+
+
    +
  1. Litigation
  2. +
+
+

Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims.

+
    +
  1. Miscellaneous
  2. +
+
+

This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor.

+
    +
  1. Versions of the License
  2. +
+
+

10.1. New Versions

+

Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number.

+

10.2. Effect of New Versions

+

You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward.

+

10.3. Modified Versions

+

If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License).

+

10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses

+

If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached.

+

Exhibit A - Source Code Form License Notice

+

This Source Code Form is subject to the terms of the Mozilla Public +License, v. 2.0. If a copy of the MPL was not distributed with this +file, You can obtain one at http://mozilla.org/MPL/2.0/.

+

If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice.

+

You may add additional accurate notices of copyright ownership.

+

Exhibit B - "Incompatible With Secondary Licenses" Notice

+

This Source Code Form is "Incompatible With Secondary Licenses", as +defined by the Mozilla Public License, v. 2.0.

+
+
+ +
+ + + + + +
+ +
+ +
+
+ +
+ + + + + + +
+ + + You can’t perform that action at this time. +
+ + + + + + + + + +
+ + You signed in with another tab or window. Reload to refresh your session. + You signed out in another tab or window. Reload to refresh your session. +
+ + + + +
+ Press h to open a hovercard with more details. +
+ + + + + diff --git a/src/ext/yuni/packages/cmake/FindYuni.cmake b/src/ext/yuni/packages/cmake/FindYuni.cmake new file mode 100644 index 0000000000..3f40dffb52 --- /dev/null +++ b/src/ext/yuni/packages/cmake/FindYuni.cmake @@ -0,0 +1,156 @@ +# +# Locate the Yuni Framework +# +# This module reads the following variables : +# +# - Yuni_YUNICONFIG_PATH : Path to the program 'yuni-config' (optional if you're building +# in the source tree) +# +# This module defines : +# - Yuni_FOUND : If the libraries has been found +# - Yuni_CXXFLAGS : The flags to use for compiling a source file +# - Yuni_LIBS : The flags to use to link against the libyuni libraries +# - Yuni_INFOS : A string about the selected version of yuni (`Not found` by default) +# - Yuni_YUNICONFIG_PATH : Path to the program 'yuni-config' (empty if not found) +# +# Usage : +# \code +# find_package(Yuni COMPONENTS core gfx3d lua) +# if(NOT Yuni_FOUND) +# message(ERROR "The yuni framework could not been found.") +# endif() +# \endcode +# + + +# +# External variables +# +set(Yuni_CXXFLAGS "") +set(Yuni_LIBS "") +set(Yuni_INFOS "Not found") +set(Yuni_FOUND FALSE) +# Yuni_YUNICONFIG_PATH is also an input variable. + +# +# Internal variables +# +set(__Yuni_Message "Looking for the Yuni Framework") +set(__Yuni_ConfigNotFound FALSE) + +# +# Where is yuni-config ? +# +# - It might be specified. + +if(Yuni_YUNICONFIG_PATH AND EXISTS "${Yuni_YUNICONFIG_PATH}") + # Nothing to do, the binary is there, we'll blindly use it. + set(__Yuni_Config "${Yuni_YUNICONFIG_PATH}") +elseif(Yuni_YUNICONFIG_PATH AND NOT EXISTS "${Yuni_YUNICONFIG_PATH}") + # If the specified yuni-config cannot be found, we should not try harder. + message(STATUS "${__Yuni_Message} - The specified yuni-config (`${Yuni_YUNICONFIG_PATH}`) could not be found.") + set(__Yuni_ConfigNotFound TRUE) +else() + # Try to find it in _reasonable_ places. + set(__Yuni_CurrentFolder "${CMAKE_CURRENT_LIST_FILE}") + string(REPLACE "\\FindYuni.cmake" "" __Yuni_CurrentFolder "${__Yuni_CurrentFolder}") + string(REPLACE "/FindYuni.cmake" "" __Yuni_CurrentFolder "${__Yuni_CurrentFolder}") + + SET(__Yuni_ProgramSearchPath + # Search in the source tree (if we have a trunk-like tree). + "${__Yuni_CurrentFolder}/../../src/build/release/bin/" + "${__Yuni_CurrentFolder}/../../src/build/debug/bin/" + "$ENV{YUNI_PATH}") + + find_program(__Yuni_Config NAMES yuni-config yuni-config.exe PATHS ${__Yuni_ProgramSearchPath}) + + if("${__Yuni_Config}" STREQUAL "__Yuni_Config-NOTFOUND") + message(STATUS "${__Yuni_Message} - failed ('yuni-config' not found)") + set(__Yuni_ConfigNotFound TRUE) + endif() +endif() + + +# FIXME: we should check if yuni-config has any versions configured here, to avoid problems. +# FIXME: we also should give a choice of options to pass to yuni-config (like a secondary version, or so). + +if(NOT __Yuni_ConfigNotFound) + + # Store the config path. + set(Yuni_YUNICONFIG_PATH "${__Yuni_Config}") + + # + # Compiler + # + set(__Yuni_Compiler "gcc") + if(MINGW) + set(__Yuni_Compiler "mingw") + endif() + if(MSVC) + set(__Yuni_Compiler "msvc") + endif() + if(WATCOM) + set(__Yuni_Compiler "watcom") + endif() + if(BORLAND) + set(__Yuni_Compiler "borland") + endif() + if(MSYS) + set(__Yuni_Compiler "mingw") + endif(MSYS) + + # + # Building the command line options for the list of components + # + set(__Yuni_ModsMods "") + foreach(COMPONENT ${Yuni_FIND_COMPONENTS}) + string(TOLOWER ${COMPONENT} COMPONENT) + set(__Yuni_ModsOpts "${__Yuni_ModsOpts} ${COMPONENT}") + endforeach() + + # Converting eventual slashes in yuni-config path on Windows + if(WIN32 OR WIN64) + if(NOT MSYS AND NOT CYGWIN) + # On Windows (not MSys), a path with slashes is invalid. + # "C:/path/..." needs to be changed into "C:\path\..." + string(REPLACE "/" "\\" __Yuni_Config "${__Yuni_Config}") + endif() + endif() + + # Check if the required modules, and their dependencies are compiled in. + execute_process(COMMAND "${__Yuni_Config}" -c "${__Yuni_Compiler}" + -m "${__Yuni_ModsOpts}" --module-deps + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE __Yuni_ModsDeps + RESULT_VARIABLE __Yuni_Config_DepsResult) + if(NOT "${__Yuni_Config_DepsResult}" EQUAL 0 OR "${__Yuni_ModsDeps}" STREQUAL "") + message(STATUS "${__Yuni_Message} - Requires: ${Yuni_FIND_COMPONENTS}") + message(STATUS "${__Yuni_Message} - failed - the required modules could not be found") + set(__Yuni_ConfigNotFound TRUE) + endif() + + # If we encountered no problems, get the framework info, and fill + # the detection variables. + if(NOT __Yuni_ConfigNotFound) + + # Infos + execute_process(COMMAND "${__Yuni_Config}" -c "${__Yuni_Compiler}" + -m "${__Yuni_ModsOpts}" -l + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE Yuni_INFOS) + + # CXX + execute_process(COMMAND "${__Yuni_Config}" -c "${__Yuni_Compiler}" + -m "${__Yuni_ModsOpts}" --cxxflags + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE Yuni_CXXFLAGS) + + # LIBS + execute_process(COMMAND "${__Yuni_Config}" -c "${__Yuni_Compiler}" + -m "${__Yuni_ModsOpts}" --libs + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE Yuni_LIBS) + + # Framework found + set(Yuni_FOUND true) + + endif() + +endif() + diff --git a/src/ext/yuni/packages/sources/build.sh b/src/ext/yuni/packages/sources/build.sh new file mode 100755 index 0000000000..d1b2051770 --- /dev/null +++ b/src/ext/yuni/packages/sources/build.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +root=`dirname "${0}"` + +headerBuilder="${root}/../../bin/yuni-extract-headers.sh" + +if [ ! -f "${headerBuilder}" ]; then + echo "The script to extract all headers from sources is missing" + exit 1 +fi + +revision=`svnversion | cut -d'M' -f1 | cut -d' ' -f1` + + +tmpFolder="/tmp/org.libyuni.packages.sources" + +file_headers_targz="${tmpFolder}/yuni-headers-r${revision}.tar.gz" +file_headers_zip="${tmpFolder}/yuni-headers-r${revision}.zip" + + +if [ -d "${tmpFolder}" ]; then + rm -rf "${tmpFolder}" +fi + +"${headerBuilder}" "${tmpFolder}/yuni" + + +echo "Archives" + +echo " . Compressing '${file_headers_targz}'" +tar zcsf "${file_headers_targz}" "${tmpFolder}/yuni" 2>/dev/null +echo " . Compressing '${file_headers_zip}'" +`cd "${tmpFolder}" && zip -q -r "${file_headers_zip}" .` + + +echo "Moving archives..." +mv -f "${file_headers_targz}" "${root}" +mv -f "${file_headers_zip}" "${root}" + +echo "Cleaning" +rm -rf "${tmpFolder}" diff --git a/src/ext/yuni/src/CMakeLists.txt b/src/ext/yuni/src/CMakeLists.txt new file mode 100644 index 0000000000..7a873bb8d5 --- /dev/null +++ b/src/ext/yuni/src/CMakeLists.txt @@ -0,0 +1,217 @@ + +# Minimum CMake version check +cmake_minimum_required(VERSION 2.8) +include("cmake/message.cmake") + +project(yuni) +YMESSAGE("") +YMESSAGE_BOLD("The Yuni Framework") + + +# Package informations +set(YUNI_URL_WEBSITE "http://www.libyuni.org") +set(YUNI_MAILING_LIST "dev@libyuni.org") +# Version +set(YUNI_VERSION_HI 1) +set(YUNI_VERSION_LO 1) +set(YUNI_VERSION_REV 0) +set(YUNI_VERSION "${YUNI_VERSION_HI}.${YUNI_VERSION_LO}") +set(YUNI_TARGET "debug") # Target : debug/release - see Target.cmake +set(YUNI_URL_DEVPACK_REPOSITORY "http://devpacks.libyuni.org/") +set(YUNI_URL_DEVPACK_SOURCE "http://devpacks.libyuni.org/downloads") + + + + + + + + +# +# ----------------------------------------------------------------------------- +# + +# CMake special variables +set(VS_KEYWORD "YuniVS${YUNI_VERSION}") +set(VERSION "${YUNI_VERSION}") +set(VS_SCC_PROJECTNAME "Yuni Framework") +set(PROJECT_LABEL "Yuni Framework") + +if (WIN32 AND NOT WIN64) + # We have to determine the platform architecture + if (MINGW OR MSYS OR CYGWIN) + execute_process(COMMAND "${CMAKE_CXX_COMPILER}" "--version" + OUTPUT_VARIABLE compiler_version ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE) + string(FIND "${compiler_version}" "64" platform_64) + if ("${platform_64}" GREATER 0) + set(WIN64 true) + endif() + else() + string(FIND "${CMAKE_GENERATOR}" "64" platform_64) + if ("${platform_64}" GREATER 0) + set(WIN64 true) + endif() + endif() +endif() + + +# +# CMake policies +# +# Preprocessor definition values are now escaped automatically +if (POLICY CMP0005) + CMake_Policy(SET CMP0005 NEW) +endif() +if (POLICY CMP0011) + CMake_Policy(SET CMP0011 NEW) +endif() + + +set(YUNI_INSTALL_CXX_FLAGS "") +set(YUNI_INSTALL_CXX_DEFINES "") + +include(CheckCSourceCompiles) +include(CheckCXXSourceCompiles) +include(CheckIncludeFiles) +include(CheckIncludeFileCXX) +include(CheckCCompilerFlag) +include(CheckCXXCompilerFlag) + + +# ICC Detection +# CMake does not handle ICC at all, mainly because ICC behaves like Visual Studio and +# it seems there is no reliable way to make the distinction +if (WIN32 OR WIN64) + if (NOT MSVC AND NOT MINGW AND NOT CYGWIN) + # Should behaves like Visual Studio, like ICC + set(MSVC 1) + endif() +endif() + + +# Target +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/target.cmake") +# Getting the latest revision number +YMESSAGE_BOLD("Version : v${YUNI_VERSION_HI}.${YUNI_VERSION_LO}-${YUNI_TARGET} (Rev: ${YUNI_VERSION_REV})") +YMESSAGE("") +set(YUNI_VERSION_STRING "${YUNI_VERSION_HI}.${YUNI_VERSION_LO}.${YUNI_VERSION_REV}-${CMAKE_BUILD_TYPE}") +# Informations about the system +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/system-information.cmake") + + +# +# The target directory for static libs +# Various output directories +# +set(YUNI_VERSIONED_INST_PATH "yuni/${YUNI_VERSION}") +set(YUNI_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/build/${YUNI_TARGET}/") +set(YUNI_SOURCE_TREE "${CMAKE_CURRENT_SOURCE_DIR}/yuni/") + +set(YUNI_SKIP_YUNI_CONFIG false) + +YMESSAGE_BOLD("Folders") +YMESSAGE(" Source: ${CMAKE_CURRENT_SOURCE_DIR}") +YMESSAGE(" Build into: ${CMAKE_CURRENT_BINARY_DIR}") + + +# Custom settings +if ("${PROFILE}" STREQUAL "") + + if (NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/ProfileBuild.cmake") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/ProfileBuild.template.cmake + ${CMAKE_CURRENT_BINARY_DIR}/ProfileBuild.cmake) + YMESSAGE("") + YMESSAGE("A default profile has been created (`/ProfileBuild.cmake`)") + YMESSAGE("Please edit this file to override the default settings") + YMESSAGE("") + endif() + + set(YUNI_PROFILE_PATH "${CMAKE_CURRENT_BINARY_DIR}/ProfileBuild.cmake") + +else() + + if (NOT EXISTS "${PROFILE}") + YERROR("Could not find the specified profile file: (`${PROFILE}`)") + endif() + + set(YUNI_PROFILE_PATH "${PROFILE}") + +endif() + +include("${YUNI_PROFILE_PATH}") +YMESSAGE(" Using profile: ${YUNI_PROFILE_NAME}") +YMESSAGE(" found in: ${YUNI_PROFILE_PATH}") + +# (Re)Check the target +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/target.cmake") + +# DevPacks utilities +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/devpack.cmake") +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/devpack-standard-imports.cmake") + +# Modules +include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules.cmake") + + + +# Sub Directories +add_subdirectory(yuni) + +# tools (especially for yuni-config) +add_subdirectory(tools) + + + +# +# Compiling yuni-config if required +# +if (YUNI_AUTO_COMPILE_YUNI_CONFIG) + YMESSAGE("[yuni-config] Bootstraping") + if (YUNI_TESTS) + YMESSAGE("The bootstrapping is required to compile the testsuite") + endif() + # -- + YMESSAGE("Configuring yuni-config...") + YMESSAGE("(in ${CMAKE_CURRENT_SOURCE_DIR}/tools/yuni-config)") + # Create the yuni-config bootstrap directory. + execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory + "${CMAKE_CURRENT_BINARY_DIR}/tools/yuni-config-bootstrap" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + # Configure yuni-config like us. + execute_process(COMMAND "${CMAKE_COMMAND}" + ${CMAKE_CURRENT_SOURCE_DIR}/tools/yuni-config + "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" + "-DYUNI_OUTPUT_DIRECTORY=${YUNI_OUTPUT_DIRECTORY}" + "-DYUNI_BOOTSTRAP_YUNI_CONFIG=1" + -G "${CMAKE_GENERATOR}" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tools/yuni-config-bootstrap") + # Compile it. + YMESSAGE("Compiling yuni-config...") + execute_process(COMMAND "${CMAKE_COMMAND}" --build + "${CMAKE_CURRENT_BINARY_DIR}/tools/yuni-config-bootstrap" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/tools/yuni-config-bootstrap") +endif() + + +if (YUNI_BENCHMARKS) + add_subdirectory(benchmarks) +endif() + + +if (YUNI_ERROR_HAS_OCCURED) + message(STATUS "") + message(STATUS "") + if (UNIX) + message(SEND_ERROR "An error has occured. Aborting. ") + else() + message(SEND_ERROR "An error has occured. Aborting.") + endif() +endif() + + + + +# Empty message, for beauty :) +YMESSAGE("") # done + diff --git a/src/ext/yuni/src/cmake/DetectInstructionsSets.cmake b/src/ext/yuni/src/cmake/DetectInstructionsSets.cmake new file mode 100644 index 0000000000..06c86f54e1 --- /dev/null +++ b/src/ext/yuni/src/cmake/DetectInstructionsSets.cmake @@ -0,0 +1,97 @@ + + + +# +# --- Applying the Configuation --- +# + +set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "") + +# +# MMX +# +if("${YUNI_PROFILE_MMX}" STREQUAL "yes") + if(CMAKE_COMPILER_IS_GNUCXX) + set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS} -mmmx") + else() + endif() +endif() + +# +# 3D NOW +# +if("${YUNI_PROFILE_3DNOW}" STREQUAL "yes") + if(CMAKE_COMPILER_IS_GNUCXX) + set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS} -m3dnow") + else() + endif() +endif() + + + +# +# SSE +# +if("${YUNI_PROFILE_SSE}" STREQUAL "yes") + if(CMAKE_COMPILER_IS_GNUCXX) + set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS} -msse -mfpmath=sse") + else() + set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS} -msse -mfpmath=sse") + endif() + + # SSE2 + if("${YUNI_PROFILE_SSE2}" STREQUAL "yes") + if(CMAKE_COMPILER_IS_GNUCXX) + set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS} -msse2") + else() + if(MSVC) + set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS} /arch:SSE2") + endif() + endif() + + # SSE3 + if("${YUNI_PROFILE_SSE3}" STREQUAL "yes") + if(CMAKE_COMPILER_IS_GNUCXX) + set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS} -msse3") + else() + endif() + + # SSE4 + if("${YUNI_PROFILE_SSE4}" STREQUAL "yes") + if(CMAKE_COMPILER_IS_GNUCXX) + set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS} -msse4") + else() + endif() + endif() + + # SSE4a + if("${YUNI_PROFILE_SSE4a}" STREQUAL "yes") + if(CMAKE_COMPILER_IS_GNUCXX) + set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS} -msse4a") + else() + endif() + endif() + + # SSE 4.1 + if("${YUNI_PROFILE_SSE4_1}" STREQUAL "yes") + if(CMAKE_COMPILER_IS_GNUCXX) + set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS} -msse4.1") + else() + endif() + endif() + + # SSE 4.2 + if("${YUNI_PROFILE_SSE4_2}" STREQUAL "yes") + if(CMAKE_COMPILER_IS_GNUCXX) + set(YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS "${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS} -msse4.2") + else() + endif() + endif() + + endif() + + endif() + +endif() + + diff --git a/src/ext/yuni/src/cmake/ProfileBuild.template.cmake b/src/ext/yuni/src/cmake/ProfileBuild.template.cmake new file mode 100644 index 0000000000..c7681b7076 --- /dev/null +++ b/src/ext/yuni/src/cmake/ProfileBuild.template.cmake @@ -0,0 +1,189 @@ + +############################################################################### +# Profile +# Everything related to this particular profile +############################################################################### + +# Profile name +# FIXME: Document usage. +set(YUNI_PROFILE_NAME "Default") + + + + +############################################################################### +# Environment +# Compilers, program search paths, everything about your system. +############################################################################### + +# YUNI_MACPORTS_PREFIX +# Mac-specific: MacPorts path. When you specify "macports" in a package search, +# this prefix is used. +# +# Default: Prefix of the first «port» program found in PATH. +# Should be /opt/local in the most common case. +# +#set(YUNI_MACPORTS_PREFIX "/my/twisted/macports/prefix") +set(YUNI_MACPORTS_PREFIX "/opt/local/") + + + +############################################################################### +# Target +# What is produced, and everything related to it. +############################################################################### + +# YUNI_TARGET +# Specifies the compilation profile. Accepted values are: +# - debug: No optimization, debug info, very slow. +# - release: O3 optimization level, no debug, production code. +# +# Default: debug +# +#set(YUNI_TARGET "debug") + + +# MODULES +# Specifies which Yuni components should be build. +# Uncomment the following line to override the module list +# Example : `messaging,audio,-uuid` +# Note : `cmake -DMODULES=help` to have a list of all available modules +#set(MODULES "messaging,audio") + + + +############################################################################### +# External packages +# +# A module often requires one or more external packages (`lua` for example). +# Most of the time the system has its own package management utility, which +# will provide all needed and up-to-date packages (`lua`, `libxml`...). +# It is not always the case (Windows for example), so some pre-built packages +# (DevPacks) are available on http://devpacks.libyuni.org and can be +# automatically downloaded. +# +# Several modes can be given in the preferred order to find and use the +# appropriate package. If nothing suits your needs, it is possible to use the +# `custom` mode and to set the prefix path where the package can be found. +# This is useful if you have special needs or wish to integrate Yuni in an +# software that already uses the package. +# +# Generic modes : +# +# auto : Automatically choose a mode depending on platform +# +# disabled: Do as if the particular package could not be found. +# Implemented only for certain packages providing optional support. +# +# system : Try to use the standard way to find the package provided by the system +# Standard paths, System Frameworks (OS X) +# +# custom : Try to find the package from a custom prefix path +# The variable `YUNI_DvP__PREFIX` must be set. +# Other variables may need to be set, on a per-package +# basis +# +# macport : Try to find the package from a macport installation (Mac OS X) +# (http://www.macports.org) +# +# devpack : Download and use the pre-build package from `devpacks.libyuni.org` +# This is the recommended way on Windows, and when you want to have +# a known-working build. +# +# NOTE: Each package is not required to support every mode. Available modes are speci +# +# Example : +# Use `lua` compiled by hand, installed in `/opt/lua` (/opt/lua/include and `/opt/lua/lib`) : +# Set(YUNI_DvP_LUA_MODE custom) +# Set(YUNI_DvP_LUA_PREFIX "/opt/lua") +# +############################################################################### + + +## Audio + +# ZLIB [FIXME: NOT IMPLEMENTED] +# Provides: GZip compression support +# Modes: system, custom +# Required for Audio module. + +# OpenAL +# Provides: Audio abstraction layer. +# Modes: system, devpack, custom +# Required for Audio module. +set(YUNI_DvP_OPENAL_MODE auto) + + +## Scripts + +# Lua (+script,+lua) +# Provides: Lua scripting support +# Modes: devpack, system, macports, custom +# Optional. +set(YUNI_DvP_LUA_MODE auto) + + + +############################################################################### +# Platform-specific options +############################################################################### + +# For building universal binaries on OS X +# Value by default : i686;x86_64 +#set(YUNI_MACOX_UNIVERSAL_BINARIES "ppc;ppc64;i386;x86_64") + + +############################################################################### +# Miscellaneous build options +# Options that concern small features, tweaks or optimisations +############################################################################### + +# Auto-Compile yuni-config from CMake +# Enable this option to automatically compile yuni-config from CMake +# FIXME: Describe when this could be useful. +#set(YUNI_AUTO_COMPILE_YUNI_CONFIG false) + + +# Special instructions sets +# The following options enable or disable certain CPU optimisations. +# If you have to run on platforms that do not support certain options, +# we recommend to disable them. +# Options: +# auto : Auto detect if these sets can be used (based on build host) +# no : Completely disable it +# yes : Try to use it anyways (it may not even compile, though) +# +set(YUNI_PROFILE_MMX auto) # MMX +set(YUNI_PROFILE_3DNOW auto) # 3DNow! +set(YUNI_PROFILE_SSE auto) # SSE +set(YUNI_PROFILE_SSE2 auto) # SSE2 (depends on SSE) +set(YUNI_PROFILE_SSE3 auto) # SSE3 (depends on SSE2) +set(YUNI_PROFILE_SSE4 auto) # SSE4 (depends on SSE3) +set(YUNI_PROFILE_SSE4a auto) # SSE4a (depends on SSE3) +set(YUNI_PROFILE_SSE4_1 auto) # SSE 4.1 (depends on SSE3) +set(YUNI_PROFILE_SSE4_2 auto) # SSE 4.2 (depends on SSE3) + + +# yuni-config +# Enable this option to skip the build of yuni-config +set(YUNI_SKIP_YUNI_CONFIG false) + +# Custom C/C++ Flags +# +# Advanced users only : it may not a good idea to use your own CFlags +# for compiling the Yuni library. Do not file any bug reports before re-testing +# with standard build-flags. + +# Uncomment the following line to ADD some C++ compiler flags +#set(YUNI_CXX_FLAGS_OVERRIDE_ADD_DEBUG "-Wextra") +#set(YUNI_CXX_FLAGS_OVERRIDE_ADD_RELEASE "-Wextra") +#set(YUNI_CXX_FLAGS_OVERRIDE_ADD_RELWITHDEBINFO "-Wextra") + +# Uncomment the following line to OVERRIDE the C++ compiler flags +# This is not recommended. +#set(YUNI_CXX_FLAGS_OVERRIDE_DEBUG "-g -ggdb -Wall -Wextra") +#set(YUNI_CXX_FLAGS_OVERRIDE_RELEASE "-g -ggdb -Wall -Wextra") +#set(YUNI_CXX_FLAGS_OVERRIDE_RELWITHDEBINFO "-g -ggdb -Wall -Wextra") + + +# That's all, folks ! ######################################################### diff --git a/src/ext/yuni/src/cmake/YuniConfig.cmake b/src/ext/yuni/src/cmake/YuniConfig.cmake new file mode 100644 index 0000000000..fc66540fc7 --- /dev/null +++ b/src/ext/yuni/src/cmake/YuniConfig.cmake @@ -0,0 +1,136 @@ + + +# +# This variable must only be enabled when compiling +# the yuni library. +# Otherwise, some files could be created in the wrong place +# +if(LIBYUNI_CONFIG_ENABLED) + if(MSVC) + set(YUNI_LIBYUNI_CONFIG_COMPILER "msvc") + else() + if(MINGW) + set(YUNI_LIBYUNI_CONFIG_COMPILER "mingw") + else() + set(YUNI_LIBYUNI_CONFIG_COMPILER "gcc") + endif() + endif() + + # Configure the config-file for the in-tree yuni-config + set(YUNI_LIBYUNI_CONFIG_INTREE_INIFILE + "${CMAKE_CURRENT_BINARY_DIR}/yuni.config.${YUNI_LIBYUNI_CONFIG_COMPILER}") + file(WRITE "${YUNI_LIBYUNI_CONFIG_INTREE_INIFILE}" "[settings]\n") + + # Configure the config-file for the installed Yuni profile + set(YUNI_LIBYUNI_CONFIG_TARGET_INIFILE + "${CMAKE_CURRENT_BINARY_DIR}/yuni.config.${YUNI_LIBYUNI_CONFIG_COMPILER}.target") + file(WRITE "${YUNI_LIBYUNI_CONFIG_TARGET_INIFILE}" "[settings]\n") +endif() + + +macro(LIBYUNI_CONFIG_CFLAG mode module pth) + if(LIBYUNI_CONFIG_ENABLED) + if("${mode}" STREQUAL "target" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_TARGET_INIFILE}" "cxxflag:${module} = ${pth}\n") + endif() + if("${mode}" STREQUAL "intree" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_INTREE_INIFILE}" "cxxflag:${module} = ${pth}\n") + endif() + endif() +endmacro() + + +macro(LIBYUNI_CONFIG_LIB mode module pth) + if(LIBYUNI_CONFIG_ENABLED) + foreach(I ${pth}) + if("${mode}" STREQUAL "target" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_TARGET_INIFILE}" "lib:${module} = ${I}\n") + endif() + if("${mode}" STREQUAL "intree" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_INTREE_INIFILE}" "lib:${module} = ${I}\n") + endif() + endforeach() + endif() +endmacro() + + +macro(LIBYUNI_CONFIG_LIB_RAW_COMMAND mode module pth) + if(LIBYUNI_CONFIG_ENABLED) + foreach(I ${pth}) + if("${mode}" STREQUAL "target" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_TARGET_INIFILE}" "lib,rawcommand:${module} = ${I}\n") + endif() + if("${mode}" STREQUAL "intree" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_INTREE_INIFILE}" "lib,rawcommand:${module} = ${I}\n") + endif() + endforeach() + endif() +endmacro() + + +macro(LIBYUNI_CONFIG_FRAMEWORK mode module pth) + if(LIBYUNI_CONFIG_ENABLED) + foreach(I ${pth}) + if("${mode}" STREQUAL "target" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_TARGET_INIFILE}" "framework:${module} = ${I}\n") + endif() + if("${mode}" STREQUAL "intree" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_INTREE_INIFILE}" "framework:${module} = ${I}\n") + endif() + endforeach() + endif() +endmacro() + + + +macro(LIBYUNI_CONFIG_DEFINITION mode module pth) + if(LIBYUNI_CONFIG_ENABLED) + foreach(I ${pth}) + if("${mode}" STREQUAL "target" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_TARGET_INIFILE}" "define:${module} = ${I}\n") + endif() + if("${mode}" STREQUAL "intree" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_INTREE_INIFILE}" "define:${module} = ${I}\n") + endif() + endforeach() + endif() +endmacro() + + +macro(LIBYUNI_CONFIG_DEPENDENCY module pth) + if(LIBYUNI_CONFIG_ENABLED) + file(APPEND "${YUNI_LIBYUNI_CONFIG_TARGET_INIFILE}" "dependency:${module} = ${pth}\n") + file(APPEND "${YUNI_LIBYUNI_CONFIG_INTREE_INIFILE}" "dependency:${module} = ${pth}\n") + endif() +endmacro() + + + + +macro(LIBYUNI_CONFIG_INCLUDE_PATH mode module pth) + if(LIBYUNI_CONFIG_ENABLED) + foreach(I ${pth}) + if("${mode}" STREQUAL "target" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_TARGET_INIFILE}" "path.include:${module} = ${I}\n") + endif() + if("${mode}" STREQUAL "intree" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_INTREE_INIFILE}" "path.include:${module} = ${I}\n") + endif() + endforeach() + endif() +endmacro() + + +macro(LIBYUNI_CONFIG_LIB_PATH mode module pth) + if(LIBYUNI_CONFIG_ENABLED) + foreach(I ${pth}) + if("${mode}" STREQUAL "target" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_TARGET_INIFILE}" "path.lib:${module} = ${I}\n") + endif() + if("${mode}" STREQUAL "intree" OR "${mode}" STREQUAL "both") + file(APPEND "${YUNI_LIBYUNI_CONFIG_INTREE_INIFILE}" "path.lib:${module} = ${I}\n") + endif() + endforeach() + endif() +endmacro() + diff --git a/src/ext/yuni/src/cmake/common-settings.cmake b/src/ext/yuni/src/cmake/common-settings.cmake new file mode 100644 index 0000000000..d4871369f4 --- /dev/null +++ b/src/ext/yuni/src/cmake/common-settings.cmake @@ -0,0 +1,329 @@ + +# +# CMake Stuff +# +#set(CMAKE_VERBOSE_MAKEFILE ON) +# Policy +if(NOT CMAKE_MINOR_VERSION EQUAL 4 OR NOT CMAKE_MAJOR_VERSION EQUAL 2 ) + cmake_policy(SET CMP0004 OLD) + cmake_policy(SET CMP0003 NEW) +endif() +include(CheckIncludeFile) +include(CheckCXXCompilerFlag) + +set_property(GLOBAL PROPERTY USE_FOLDERS true) + + +if ("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set(YUNI_) +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_DEBUG}") +endif() + + +# +# Macro for automatically detect compiler flag +# +macro(compile_flag flag varname) + check_cxx_compiler_flag("${flag}" "YUNI_HAS_CXX_FLAG_${varname}") + if ("${YUNI_HAS_CXX_FLAG_${varname}}") + foreach (arg ${ARGN}) + set("CMAKE_CXX_FLAGS_${arg}" "${CMAKE_CXX_FLAGS_${arg}} ${flag}") + endforeach() + endif() + check_c_compiler_flag("${flag}" "YUNI_HAS_C_FLAG_${varname}") + if ("${YUNI_HAS_C_FLAG_${varname}}") + foreach (arg ${ARGN}) + set("CMAKE_C_FLAGS_${arg}" "${CMAKE_C_FLAGS_${arg}} ${flag}") + endforeach() + endif() +endmacro() + + +# +# Clang Detection +# +check_cxx_source_compiles(" + #ifndef __clang__ + will never compile ! + #endif + int main() {return 0;}" YUNI_COMPILER_IS_CLANG) +if ("${YUNI_COMPILER_IS_CLANG}") + set(CLANG 1) +endif() + + +# +# Getting the folder where this file is located +# +set(CurrentFolder "${CMAKE_CURRENT_LIST_FILE}") +string(REPLACE "\\common-settings.cmake" "" CurrentFolder "${CurrentFolder}") +string(REPLACE "/common-settings.cmake" "" CurrentFolder "${CurrentFolder}") +# Current Folder : ${CurrentFolder} + +# +# Detect Special Instructions Set (SSE, MMX...) +# +include("${CurrentFolder}/DetectInstructionsSets.cmake") + + +# Common options to all GCC-based compilers +set(YUNI_COMMON_CC_OPTIONS "") +set(YUNI_COMMON_CC_OPTIONS "${YUNI_COMMON_CC_OPTIONS} -D_REENTRANT -DXUSE_MTSAFE_API") +set(YUNI_COMMON_CC_OPTIONS "${YUNI_COMMON_CC_OPTIONS} -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64") +set(YUNI_COMMON_CXX_OPTIONS "") + +set(COMMON_MSVC_FLAGS "/W3 /MP4 /Zi") +set(COMMON_MSVC_FLAGS "${COMMON_MSVC_FLAGS} /DREENTRANT /D_LARGEFILE_SOURCE /D_LARGEFILE64_SOURCE /D_FILE_OFFSET_BITS=64") +set(COMMON_MSVC_FLAGS "${COMMON_MSVC_FLAGS} /DUNICODE /D_UNICODE") + + + +# Common options for GCC on Unixes (mingw excluded) +# fPIC seems a good choice in most cases +set(YUNI_COMMON_CC_OPTIONS_UNIX "${YUNI_COMMON_CC_OPTIONS} -fPIC") + +include(CheckCXXCompilerFlag) +if(NOT MSVC) + check_cxx_compiler_flag("-std=gnu++14" YUNI_HAS_GNU14_SUPPORT) + check_cxx_compiler_flag("-std=gnu++11" YUNI_HAS_GNU11_SUPPORT) + check_cxx_compiler_flag("-std=c++14" YUNI_HAS_CPP14_SUPPORT) + check_cxx_compiler_flag("-std=c++11" YUNI_HAS_CPP11_SUPPORT) + check_cxx_compiler_flag("-std=c++0x" YUNI_HAS_GCC_CPP0X_SUPPORT) + check_cxx_compiler_flag("-stdlib=libc++" YUNI_HAS_LIB_CPP11_SUPPORT) # clang, Apple gcc... + + if (NOT APPLE) + if (YUNI_HAS_GNU14_SUPPORT) + set(YUNI_COMMON_CXX_OPTIONS "${YUNI_COMMON_CXX_OPTIONS} -std=gnu++14") + set(YUNI_CPP_STD "-std=gnu++14" CACHE STRING "c++std" FORCE) + else() + if (YUNI_HAS_GNU11_SUPPORT) + set(YUNI_COMMON_CXX_OPTIONS "${YUNI_COMMON_CXX_OPTIONS} -std=gnu++11") + set(YUNI_CPP_STD "-std=gnu++11" CACHE STRING "c++std" FORCE) + else() + if (YUNI_HAS_GCC_CPP0X_SUPPORT) + set(YUNI_COMMON_CXX_OPTIONS "${YUNI_COMMON_CXX_OPTIONS} -std=c++0x") + set(YUNI_CPP_STD "-std=c++0x" CACHE STRING "c++std" FORCE) + endif() + endif() + endif() + else() + if (YUNI_HAS_CPP14_SUPPORT) + set(YUNI_COMMON_CXX_OPTIONS "${YUNI_COMMON_CXX_OPTIONS} -std=c++14") + set(YUNI_CPP_STD "-std=c++14" CACHE STRING "c++std" FORCE) + else() + if (YUNI_HAS_CPP11_SUPPORT) + set(YUNI_COMMON_CXX_OPTIONS "${YUNI_COMMON_CXX_OPTIONS} -std=c++11") + set(YUNI_CPP_STD "-std=c++11" CACHE STRING "c++std" FORCE) + else() + if (YUNI_HAS_GCC_CPP0X_SUPPORT) + set(YUNI_COMMON_CXX_OPTIONS "${YUNI_COMMON_CXX_OPTIONS} -std=c++0x") + set(YUNI_CPP_STD "-std=c++0x" CACHE STRING "c++std" FORCE) + endif() + endif() + endif() + endif() + + + if (YUNI_HAS_LIB_CPP11_SUPPORT AND (NOT CLANG OR APPLE)) + # clang seems to not like the option -stdlib, but required on MacOS... + set(YUNI_COMMON_CXX_OPTIONS "${YUNI_COMMON_CXX_OPTIONS} -stdlib=libc++") + endif() + + + # transform some warnings into errors to avoid common mistakes + check_cxx_compiler_flag("-Werror=switch" YUNI_HAS_W2E_SWITCH) + + if (YUNI_HAS_W2E_SWITCH) + set(YUNI_COMMON_CXX_OPTIONS "${YUNI_COMMON_CXX_OPTIONS} -Werror=switch") + endif() +endif() + +if (APPLE AND CLANG) + # http://lists.cs.uiuc.edu/pipermail/cfe-dev/2011-January/012999.html + # Temporary workaround for compiling with Clang on OS X + set(YUNI_COMMON_CC_OPTIONS_UNIX "${YUNI_COMMON_CC_OPTIONS_UNIX} -U__STRICT_ANSI__") +endif() + + + + +# Unicode on Windows +if(WIN32 OR WIN64) + add_definitions("-DUNICODE") + add_definitions("-D_UNICODE") + add_definitions("-D__UNICODE") +endif() + +# Thread safety +add_definitions("-D_REENTRANT -DXUSE_MTSAFE_API") + + + + +if(NOT WIN32) + set(CMAKE_CXX_FLAGS_RELEASE "${YUNI_COMMON_CC_OPTIONS_UNIX} ${YUNI_COMMON_CXX_OPTIONS}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${YUNI_COMMON_CC_OPTIONS_UNIX} ${YUNI_COMMON_CXX_OPTIONS}") + set(CMAKE_CXX_FLAGS_DEBUG "${YUNI_COMMON_CC_OPTIONS_UNIX} ${YUNI_COMMON_CXX_OPTIONS}") + + set(CMAKE_C_FLAGS_RELEASE "${YUNI_COMMON_CC_OPTIONS_UNIX}") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${YUNI_COMMON_CC_OPTIONS_UNIX}") + set(CMAKE_C_FLAGS_DEBUG "${YUNI_COMMON_CC_OPTIONS_UNIX}") +endif() + +if(MINGW) + set(CMAKE_CXX_FLAGS_RELEASE "${YUNI_COMMON_CC_OPTIONS} ${YUNI_COMMON_CXX_OPTIONS}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${YUNI_COMMON_CC_OPTIONS} ${YUNI_COMMON_CXX_OPTIONS}") + set(CMAKE_CXX_FLAGS_DEBUG "${YUNI_COMMON_CC_OPTIONS} ${YUNI_COMMON_CXX_OPTIONS}") + + set(CMAKE_C_FLAGS_RELEASE "${YUNI_COMMON_CC_OPTIONS}") + set(CMAKE_C_FLAGS_RELWITHDEBINFO "${YUNI_COMMON_CC_OPTIONS}") + set(CMAKE_C_FLAGS_DEBUG "${YUNI_COMMON_CC_OPTIONS}") +endif() + +if(MSVC) + set(CMAKE_C_FLAGS_DEBUG "${COMMON_MSVC_FLAGS} /MDd /GR /Ot /Od /EHsc /RTC1") + set(CMAKE_CXX_FLAGS_DEBUG "${COMMON_MSVC_FLAGS} /MDd /GR /Ot /Od /EHsc /RTC1 /fp:except") + + set(MSVC_RELEASE_FLAGS) + + # O2x: optimization + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /O2") + # Prefer speed instead of size + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /Ot") + # Omit frame pointer + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /Oy") + # Any suitable inlining + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /Ob2") + # Fiber-safe optimizations + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /GT") + # whole program / requires "Link time code generation" + #set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /GL") + # No buffer security check + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /GS-") + # SSE2 + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /arch:SSE2") + # Intrinsic functions + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /Oi") + # Multithreaded DLL + set(MSVC_RELEASE_FLAGS "${MSVC_RELEASE_FLAGS} /MD") + + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MSVC_RELEASE_FLAGS}") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${MSVC_RELEASE_FLAGS}") +endif() + +if (NOT MSVC) + # Optimisation + compile_flag("-O3" O3 RELEASE) + compile_flag("-fomit-frame-pointer" FOMIT_FRAME_POINTER RELEASE RELWITHDEBINFO) + compile_flag("-fstrict-aliasing" STRICT_ALIASING RELEASE RELWITHDEBINFO) + compile_flag("-msse" MSSE RELEASE RELWITHDEBINFO) + compile_flag("-msse2" MSSE2 RELEASE RELWITHDEBINFO) + compile_flag("-fvisibility=hidden" VISIBILITY_HIDDEN RELEASE DEBUG RELWITHDEBINFO) + #compile_flag("-mfpmath=sse" FPMATH_MSSE RELEASE RELWITHDEBINFO) + if (NOT "${CLANG}") + compile_flag("-fdiagnostics-color=auto" DIAG_COLORS RELEASE DEBUG RELWITHDEBINFO) + endif() + + # link + #compile_flag("-flto" FLTO RELEASE RELWITHDEBINFO) + + # debugging symbols + compile_flag("-g" DEBUG_G DEBUG RELWITHDEBINFO) + compile_flag("-g3" DEBUG_G3 DEBUG RELWITHDEBINFO) + compile_flag("-gfull" DEBUG_GFULL DEBUG RELWITHDEBINFO) + compile_flag("-ggdb" DEBUG_GDB DEBUG RELWITHDEBINFO) + compile_flag("-ggdb3" DEBUG_GDB3 DEBUG RELWITHDEBINFO) + + # extra debugging tools + #compile_flag("-fsanitize=undefined" DEBUG_SANITIZE_UNDEF DEBUG RELWITHDEBINFO) + #compile_flag("-fsanitize=address" DEBUG_SANITIZE_ADDR DEBUG RELWITHDEBINFO) + + # warnings + compile_flag("-W" W RELEASE DEBUG RELWITHDEBINFO) + compile_flag("-Wall" W_ALL RELEASE DEBUG RELWITHDEBINFO) + compile_flag("-Wextra" W_EXTRA RELEASE DEBUG RELWITHDEBINFO) + compile_flag("-Wunused-parameter" W_UNUSED_PARAMETER RELEASE DEBUG RELWITHDEBINFO) + compile_flag("-Wconversion" W_CONVERSION RELEASE DEBUG RELWITHDEBINFO) + compile_flag("-Woverloaded-virtual" W_OVERLOADED_VIRTUAL RELEASE DEBUG RELWITHDEBINFO) + compile_flag("-Wundef" W_UNDEF RELEASE DEBUG RELWITHDEBINFO) + compile_flag("-Wfloat-equal" W_FLOAT_EQUAL RELEASE DEBUG RELWITHDEBINFO) + compile_flag("-Wmissing-noreturn" W_MISSING_NORETURN RELEASE DEBUG RELWITHDEBINFO) + compile_flag("-Wcast-align" W_CAST_ALIGN RELEASE DEBUG RELWITHDEBINFO) + compile_flag("-Wuninitialized" W_UNINITIALIZED RELEASE DEBUG RELWITHDEBINFO) + compile_flag("-Wdocumentation" W_DOCUMENTATION RELEASE DEBUG RELWITHDEBINFO) + #compile_flag("-Wold-style-cast" W_OLD_STYLE_CAST RELEASE DEBUG RELWITHDEBINFO) +endif() + + +if (MINGW) + # mthreads is required on windows with mingw + compile_flag("-mthreads" MTHREADS RELEASE DEBUG RELWITHDEBINFO) +endif() + + + + +# NDEBUG +if(MSVC) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /DNDEBUG") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /DNDEBUG") +else() + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG") +endif() + +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS}") +set(CMAKE_CXX_FLAGS_RELWITHDEBUG "${CMAKE_CXX_FLAGS_RELWITHDEBUG} ${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS}") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${YUNI_PROFILE_CXX_FLAGS_INSTRUCTIONS_SETS}") + +# Override +if (NOT "${YUNI_CXX_FLAGS_OVERRIDE}" STREQUAL "") + set(CMAKE_CXX_FLAGS_RELEASE "${YUNI_CXX_FLAGS_OVERRIDE}") + set(CMAKE_CXX_FLAGS_RELWITHDEBUG "${YUNI_CXX_FLAGS_OVERRIDE}") + set(CMAKE_CXX_FLAGS_RELWITHDEBUGINFO "${YUNI_CXX_FLAGS_OVERRIDE}") + set(CMAKE_CXX_FLAGS_DEBUG "${YUNI_CXX_FLAGS_OVERRIDE}") +endif() + +if(NOT "${YUNI_CXX_FLAGS_OVERRIDE_ADD_DEBUG}" STREQUAL "") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${YUNI_CXX_FLAGS_OVERRIDE_ADD_DEBUG}") +endif() +if(NOT "${YUNI_CXX_FLAGS_OVERRIDE_ADD_RELEASE}" STREQUAL "") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${YUNI_CXX_FLAGS_OVERRIDE_ADD_RELEASE}") +endif() +if(NOT "${YUNI_CXX_FLAGS_OVERRIDE_ADD_RELWITHDEBINFO}" STREQUAL "") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${YUNI_CXX_FLAGS_OVERRIDE_ADD_RELWITHDEBINFO}") +endif() + +if ("${CMAKE_BUILD_TYPE}" STREQUAL "release" OR "${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELEASE}") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_DEBUG}") +endif() + + + +# +# Extra - Mac OS X Bundles +# +if(APPLE) + set(MACOSX_BUNDLE_COPYRIGHT "Yuni Framework - 2012") + + # The compiler flag -arch must be checked. The compiler might not have apple extensions + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("arch" YUNI_GCC_HAS_ARCH_FLAG) + + if (YUNI_GCC_HAS_ARCH_FLAG) + if(YUNI_MACOX_UNIVERSAL_BINARIES) + YMESSAGE("Enabled universal binaries (custom : ${YUNI_MACOX_UNIVERSAL_BINARIES})") + set(CMAKE_OSX_ARCHITECTURES "${YUNI_MACOX_UNIVERSAL_BINARIES}") # ppc;i386;ppc64;x86_64 + else() + YMESSAGE("Enabled universal binaries (i386, x86_64)") + set(CMAKE_OSX_ARCHITECTURES "i686;x86_64") # ppc;i386;ppc64;x86_64 + endif() + else() + YWARNING("Universal binaries disabled. The compiler does not seem to support multiple platform architectures in a single binary)") + endif() +endif() + + diff --git a/src/ext/yuni/src/cmake/devpack-standard-imports.cmake b/src/ext/yuni/src/cmake/devpack-standard-imports.cmake new file mode 100644 index 0000000000..fce4ecd54f --- /dev/null +++ b/src/ext/yuni/src/cmake/devpack-standard-imports.cmake @@ -0,0 +1,142 @@ + + +# +# FFMpeg +# +macro(DEVPACK_IMPORT_FFMPEG) + if(WIN64) + DEVPACK_IMPORT("ffmpeg" "git09cd228" "1" "windows" "x86_64" "all" "all" "all") + else() + if (WIN32) + DEVPACK_IMPORT("ffmpeg" "git09cd228" "1" "windows" "i386" "all" "all" "all") + else() + include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FindFFMPEG.cmake") + set(YUNI_EXT_FFMPEG_INCLUDE "${FFMPEG_INCLUDE_DIR}") + set(YUNI_EXT_FFMPEG_LIB "${FFMPEG_LIBRARIES}") + endif() + endif() + list(APPEND YUNI_STATIC_AUDIO "${YUNI_EXT_FFMPEG_LIB}") + list(APPEND YUNI_INCLUDE "${YUNI_EXT_FFMPEG_INCLUDE}") +endmacro() + + + +# +# OpenAL +# +macro(DEVPACK_IMPORT_OPENAL) + set(OPENAL_INCLUDE_DIR) + set(OPENAL_LIBRARY) + if(WIN32 OR WIN64) + if (WIN64) + DEVPACK_IMPORT("openal" "1.14" "1" "windows" "x86_64" "all" "all") + else() + DEVPACK_IMPORT("openal" "1.14" "1" "windows" "i386" "all" "all") + endif() + set(OPENAL_INCLUDE_DIR "${YUNI_EXT_OPENAL_INCLUDE}") + set(OPENAL_LIBRARY "${YUNI_EXT_OPENAL_LIB}") + else() + YERROR("No OpenAL devpack for Unices !") + endif() + list(APPEND YUNI_STATIC_AUDIO "${OPENAL_LIBRARY}") + list(APPEND YUNI_INCLUDE "${OPENAL_INCLUDE_DIR}") +endmacro() + + +# +# FreeType +# +macro(DEVPACK_IMPORT_FREETYPE) + set(FREETYPE_INCLUDE_DIR) + set(FREETYPE_LIBRARY) + if (WIN32 OR WIN64) + if (WIN64) + DEVPACK_IMPORT("freetype" "2.4.12" "1" "windows" "x86_64" "all" "all") + else() + YERROR("No freetype devpack for Windows 32-bit !") + endif() + set(FREETYPE_INCLUDE_DIR) + set(FREETYPE_LIBRARY) + else() + #if (NOT APPLE) + execute_process(COMMAND freetype-config --cflags + RESULT_VARIABLE config_error OUTPUT_VARIABLE freetype_cflags + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT config_error) + set(FREETYPE_FOUND TRUE) + string(REPLACE " " ";" freetype_cflags "${freetype_cflags}") + foreach(it ${freetype_cflags}) + if(it) + string(REPLACE "-I" "" stripped "${it}") + list(APPEND FREETYPE_INCLUDE_DIR ${stripped}) + endif() + endforeach() + execute_process(COMMAND freetype-config --libs + RESULT_VARIABLE config_error OUTPUT_VARIABLE freetype_libs + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(FREETYPE_LIBRARY ${freetype_libs}) + set(YUNI_EXT_FREETYPE_INCLUDE ${FREETYPE_INCLUDE_DIR}) + set(YUNI_EXT_FREETYPE_LIB_RAW_COMMAND ${FREETYPE_LIBRARY}) + endif() + #endif() + endif() + list(APPEND YUNI_STATIC_UI "${FREETYPE_LIBRARY}") + list(APPEND YUNI_INCLUDE "${FREETYPE_INCLUDE_DIR}") +endmacro() + + +# +# Cairo - Pango +# +macro(DEVPACK_IMPORT_CAIROPANGO) + if(WIN32 OR WIN64) + if (WIN64) + DEVPACK_IMPORT("cairopango" "1.10.2+1.29.4+2.28.8" "1" "windows" "x86_64" "all" "all") + else() + DEVPACK_IMPORT("cairopango" "1.10.2+1.29.4+2.28.8" "1" "windows" "i386" "all" "all") + endif() + string(REPLACE " " ";" includes "${YUNI_EXT_CAIROPANGO_INCLUDE}") + foreach (it ${includes}) + include_directories("${it}") + endforeach() + set(CAIRO_FOUND TRUE) + set(PANGO_FOUND TRUE) + else() + # Cairo + execute_process(COMMAND pkg-config cairo --cflags + RESULT_VARIABLE config_error OUTPUT_VARIABLE cairo_cflags + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT config_error) + set(CAIRO_FOUND TRUE) + string(REPLACE " " ";" cairo_cflags "${cairo_cflags}") + foreach(it ${cairo_cflags}) + if(it) + string(REPLACE "-I" "" stripped "${it}") + include_directories(${stripped}) + endif() + endforeach() +# list(APPEND YUNI_INCLUDE "${cairo_cflags}") + execute_process(COMMAND pkg-config cairo --libs RESULT_VARIABLE config_error OUTPUT_VARIABLE cairo_libs OUTPUT_STRIP_TRAILING_WHITESPACE) + set(YUNI_EXT_CAIROPANGO_LIB ${cairo_libs}) + + # Pango + execute_process(COMMAND pkg-config pango --cflags-only-I RESULT_VARIABLE config_error OUTPUT_VARIABLE pango_cflags OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT config_error) + set(PANGO_FOUND TRUE) + string(REPLACE " " ";" pango_cflags "${pango_cflags}") + foreach (it ${pango_cflags}) + if(it) + string(REPLACE "-I" "" stripped ${it}) + include_directories(${stripped}) + endif() + endforeach() + execute_process(COMMAND pkg-config pango --libs RESULT_VARIABLE config_error OUTPUT_VARIABLE pango_libs OUTPUT_STRIP_TRAILING_WHITESPACE) + list(APPEND YUNI_EXT_CAIROPANGO_LIB ${pango_libs}) + endif () + endif () +# DEVPACK_IMPORT("cairopango" "1.8.10+1.28.0+2.24.0" "1" "all" "all" "${DEVPACK_COMPILER}" "all") + list (APPEND YUNI_STATIC_GFX3D ${YUNI_EXT_CAIROPANGO_LIB}) + endif() +endmacro() + + diff --git a/src/ext/yuni/src/cmake/devpack.cmake b/src/ext/yuni/src/cmake/devpack.cmake new file mode 100644 index 0000000000..98320507b5 --- /dev/null +++ b/src/ext/yuni/src/cmake/devpack.cmake @@ -0,0 +1,279 @@ + +# +# DevPacks Settings +# +set(DevPackSourceFolder "${CMAKE_CURRENT_SOURCE_DIR}/../devpacks") +set(DevPackReceiptsFolder "${CMAKE_CURRENT_SOURCE_DIR}/../devpacks/receipts") +set(DevPackRepositoryURL "http://devpacks.libyuni.org/") +set(DevPackSourceURL "http://devpacks.libyuni.org/downloads") +set(DevPackPrefix "yndevpack") + + + + + + +# Where is unzip ? +set(DevPackSourceZIP) +if (WIN32 AND NOT CMAKE_CROSSCOMPILING) + Find_Program(DevPackSourceZIP NAMES "unzip.exe" PATHS "${CMAKE_CURRENT_SOURCE_DIR}/../bin") +else() + Find_Program(DevPackSourceZIP NAMES "unzip") +endif() +String(COMPARE EQUAL "${DevPackSourceZIP}" "DevPackSourceZIP-NOTFOUND" DevPackUnzipHasNotBeenFound) +if (DevPackUnzipHasNotBeenFound) + Message(FATAL_ERROR "The program 'unzip' has not been found. It is required to ") +endif() +if (WIN32) + YMESSAGE("unzip: ${DevPackSourceZIP}") +endif() + + + + +set(DEVPACK_OS ) # macos, windows, linux, sun +set(DEVPACK_ARCH ) # i386, ppc +set(DEVPACK_COMPILER "unknown" ) # g++, msvc, mingw + + + +if (CMAKE_COMPILER_IS_GNUCXX) + set(DEVPACK_COMPILER "g++") +endif() +# Trying to find out the operating system +if (WIN32) + set(DEVPACK_OS "windows") + set(DEVPACK_ARCH "i386") + if (MINGW) + set(DEVPACK_COMPILER "mingw") + else() + set(DEVPACK_COMPILER "msvc") + if (MSVC70) + set(DEVPACK_COMPILER "vs7") + endif() + if (MSVC80) + set(DEVPACK_COMPILER "vs8") + endif() + if (MSVC90) + set(DEVPACK_COMPILER "vs9") + endif() + endif() +else() + execute_process(COMMAND "uname" "-p" OUTPUT_VARIABLE UNAME_P OUTPUT_STRIP_TRAILING_WHITESPACE) + string(TOLOWER "${UNAME_P}" UNAME_P) + string(COMPARE EQUAL "${UNAME_P}" "i386" IsI386) + string(COMPARE EQUAL "${UNAME_P}" "powerpc" IsPPC) + if (IsI386) + set(DEVPACK_ARCH "i386") + endif() + if (IsPPC) + set(DEVPACK_ARCH "ppc") + endif() +endif() + +if (NOT DEVPACK_OS) + String(TOLOWER "${CMAKE_SYSTEM_NAME}" DevPackSystemName) + String(COMPARE EQUAL "${DevPackSystemName}" "linux" IsLinux) + if (IsLinux) + set(DEVPACK_OS "linux") + endif() + String(COMPARE EQUAL "${DevPackSystemName}" "windows" IsWindows) + if (IsWindows) + set(DEVPACK_OS "windows") + endif() + String(COMPARE EQUAL "${DevPackSystemName}" "freebsd" IsFreeBSD) + if (IsFreeBSD) + set(DEVPACK_OS "freebsd") + endif() + String(COMPARE EQUAL "${DevPackSystemName}" "darwin" IsDarwin) + if (IsDarwin) + set(DEVPACK_OS "macos") + endif() +endif() +if (NOT DEVPACK_ARCH) + set(DEVPACK_ARCH "i386") +endif() + + + + +macro(DEVPACK_LIST_CONTAINS var value) + set(${var}) + foreach(value2 ${ARGN}) + if ("${value}" STREQUAL "${value2}") + set(${var} TRUE) + endif() + endforeach() +endmacro() + + +# +# Check if a DevPack is installed +# +macro(DEVPACK_IS_INSTALLED var dpname dpversion dprelease dpos dparch dpcompiler dptarget) + + # Specific to the given pack + set(DevPackFolder "${DevPackSourceFolder}/${dpname}") + set(DevPackShortFilename "${dpname}-${dpversion}-r${dprelease}-${dpos}-${dparch}-${dpcompiler}-${dptarget}") + # File for informations about the pack + set(DevPackFileInfo "${DevPackFolder}/${DevPackPrefix}-${DevPackShortFilename}") + # Title for this pack + set(DevPackTitle "DevPack: ${dpname} (${dpversion}-r${dprelease}, ${dpos}, ${dparch}, ${dpcompiler}, ${dptarget})") + # Is this pack already available + set(var FALSE) + set(DevPackReady) + + # Trying to find the appropriate file + File(GLOB FilesFound RELATIVE "${DevPackFolder}" "${DevPackFolder}/${DevPackPrefix}-*") + DEVPACK_LIST_CONTAINS(Contains "${DevPackPrefix}-${DevPackShortFilename}" ${FilesFound}) + if (Contains) + file(STRINGS "${DevPackFileInfo}" DevPackInfo) + list(FIND "${DevPackInfo}" "1" DevPackReady) + DEVPACK_LIST_CONTAINS(DevPackReady "1" ${DevPackInfo}) + if (NOT DevPackReady) + DEVPACK_LIST_CONTAINS(DevPackReady "ok" ${DevPackInfo}) + endif() + endif() + + if (DevPackReady) + set(${var} TRUE) + endif() + +endmacro() + + + + +# +# Check if a DevPack is already avialable in the `receipts` folder +# +macro(DEVPACK_IS_IN_RECEIPTS var dpname dpversion dprelease dpos dparch dpcompiler dptarget) + + # Specific to the given pack + set(DevPackFolder "${DevPackSourceFolder}/${dpname}") + set(DevPackShortFilename "${dpname}-${dpversion}-r${dprelease}-${dpos}-${dparch}-${dpcompiler}-${dptarget}") + # Is this pack already available + set(var FALSE) + set(DevPackReady) + + # Trying to find the appropriate file + file(GLOB FilesFound RELATIVE "${DevPackReceiptsFolder}" "${DevPackReceiptsFolder}/${DevPackShortFilename}.zip") + DEVPACK_LIST_CONTAINS(Contains "${DevPackShortFilename}.zip" ${FilesFound}) + if (Contains) + set(${var} TRUE) + endif() + +endmacro() + + + + + + +# +# Import settings from a DevPack +# +macro(DEVPACK_IMPORT dpname dpversion dprelease dpos dparch dpcompiler dptarget) + + # Specific to the given pack + set(DevPackFolder "${DevPackSourceFolder}/${dpname}") + set(DevPackShortFilename "${dpname}-${dpversion}-r${dprelease}-${dpos}-${dparch}-${dpcompiler}-${dptarget}") + # File for informations about the pack + set(DevPackFileInfo "${DevPackFolder}/${DevPackPrefix}-${DevPackShortFilename}") + set(DevPackURL "${DevPackSourceURL}/${DevPackShortFilename}.zip") + + # Title for this pack + set(DevPackTitle "DevPack: ${dpname} (${dpversion}-r${dprelease}, ${dpos}, ${dparch}, ${dpcompiler}, ${dptarget})") + # Is this pack already available + set(DevPackReady FALSE) + + DEVPACK_IS_INSTALLED(DevPackReady "${dpname}" "${dpversion}" "${dprelease}" "${dpos}" "${dparch}" + "${dpcompiler}" "${dptarget}") + + if (NOT DevPackReady) + + YMESSAGE(" ${DevPackTitle}: Missing") + file(MAKE_DIRECTORY "${DevPackReceiptsFolder}") + file(MAKE_DIRECTORY "${DevPackFolder}") + set(DevPackReceiptReady false) + set(DevPackHasBeenDownloaded false) + + DEVPACK_IS_IN_RECEIPTS(DevPackReceiptReady "${dpname}" "${dpversion}" "${dprelease}" "${dpos}" "${dparch}" + "${dpcompiler}" "${dptarget}") + if (NOT DevPackReceiptReady) + YMESSAGE(" . Downloading ${DevPackURL}") + set(DevPackHasBeenDownloaded true) + # Download the Pack + + file(DOWNLOAD "http://www.gdfslsdflsdffsdfoogle.com" "${DevPackReceiptsFolder}/${DevPackShortFilename}.zip" + STATUS DevPackDwnlStatus) + message(STATUS "${DevPackDwnlStatus}") + if (NOT "${DevPackDwnlStatus}") + message(STATUS "OK") + else() + message(STATUS "FAILED") + endif() + + file(DOWNLOAD "${DevPackURL}" "${DevPackReceiptsFolder}/${DevPackShortFilename}.zip" + STATUS DevPackDwnlStatus) + message(STATUS "${DevPackDwnlStatus}") + if ("${DevPackDwnlStatus}") + DEVPACK_IS_IN_RECEIPTS(DevPackReceiptReady "${dpname}" "${dpversion}" "${dprelease}" "${dpos}" + "${dparch}" "${dpcompiler}" "${dptarget}") + else() + set(DevPackReceiptReady false) + endif() + if (NOT DevPackReceiptReady) + YMESSAGE(" . !! The download has failed") + file(REMOVE "${DevPackReceiptsFolder}/${DevPackShortFilename}.zip") + endif() + endif() + + if (DevPackReceiptReady) + # Execute `unzip` + YMESSAGE(" . Extracting the receipt file") + execute_process(COMMAND "${DevPackSourceZIP}" + -u "${DevPackReceiptsFolder}/${DevPackShortFilename}.zip" + -d "${DevPackFolder}" + WORKING_DIRECTORY "${DevPackFolder}" OUTPUT_QUIET) + endif() + + DEVPACK_IS_INSTALLED(DevPackReady "${dpname}" "${dpversion}" "${dprelease}" "${dpos}" "${dparch}" + "${dpcompiler}" "${dptarget}") + + else() + YMESSAGE(" ${DevPackTitle}") + endif() + + if (NOT DevPackReady) + YMESSAGE("") + YMESSAGE("[!!] The installation of the DevPack `${dpname}` has failed.") + YMESSAGE(" You can download the DevPack from this url :") + YMESSAGE(" `${DevPackURL}`") + YMESSAGE(" And put it into the `receipts` folder :") + YMESSAGE(" `${DevPackReceiptsFolder}`") + YMESSAGE("") + YMESSAGE("[!!] If the devpack is already available in the receipts folder and you still have") + YMESSAGE(" issues, please manually remove it and try again.") + YMESSAGE(" Please visit `${DevPackRepositoryURL}` for all devpacks.") + YMESSAGE("") + message(FATAL_ERROR "Aborting now.") + else() + set(YUNI_CURRENT_DEVPACK_SOURCE_DIR "${DevPackFolder}/${dpversion}/r${dprelease}/${dparch}/${dpcompiler}") + include("${DevPackFolder}/${dpversion}/r${dprelease}/${dparch}/cmake/CMakeLists-${dpname}-${dpos}-${dpcompiler}-${dptarget}.cmake") + endif() + +endmacro() + + + + + + +macro(DEVPACK_SMART_IMPORT dpname dpversion dprelease dptarget) + # Import + DEVPACK_IMPORT("${dpname}" "${dpversion}" "${dprelease}" "${DEVPACK_OS}" + "${DEVPACK_ARCH}" "${DEVPACK_COMPILER}" "${dptarget}") +endmacro() + + diff --git a/src/ext/yuni/src/cmake/message.cmake b/src/ext/yuni/src/cmake/message.cmake new file mode 100644 index 0000000000..25e48bc670 --- /dev/null +++ b/src/ext/yuni/src/cmake/message.cmake @@ -0,0 +1,67 @@ + +set(YUNI_ERROR_HAS_OCCURED false) + + +macro(YMESSAGE msg) + if(UNIX) + message(STATUS "{yuni} ${msg}") + else() + message(STATUS "{yuni} ${msg}") + endif() + +endmacro() + + +macro(YMESSAGE_BOLD msg) + if(UNIX) + message(STATUS "{yuni} ${msg}") + else() + message(STATUS "{yuni} ${msg}") + endif() +endmacro() + + +macro(YMESSAGE_TITLE msg1 msg2) + if(UNIX) + message(STATUS "{yuni} ${msg1}${msg2}") + else() + message(STATUS "{yuni} ${msg1}${msg2}") + endif() +endmacro() + + +macro(YMESSAGE_MODULE msg) + YMESSAGE_TITLE("[module] " "${msg}") +endmacro() + + +macro(YWARNING msg) + if(UNIX) + message(STATUS "{yuni} [warning] ${msg}") + else() + message(STATUS "{yuni} [WARNING] ${msg}") + endif() +endmacro() + + +macro(YERROR msg) + if(UNIX) + message(STATUS "{yuni} [error] ${msg}") + else() + message(STATUS "{yuni} [ERROR] ${msg}") + endif() + set(YUNI_ERROR_HAS_OCCURED true) +endmacro() + + +macro(YFATAL msg) + if(UNIX) + message(FATAL_ERROR "{yuni} [error] ${msg}") + else() + message(FATAL_ERROR "{yuni} [ERROR] ${msg}") + endif() + + set(YUNI_ERROR_HAS_OCCURED true) +endmacro() + + diff --git a/src/ext/yuni/src/cmake/modules.cmake b/src/ext/yuni/src/cmake/modules.cmake new file mode 100644 index 0000000000..b55102ce56 --- /dev/null +++ b/src/ext/yuni/src/cmake/modules.cmake @@ -0,0 +1,599 @@ + +# +# --- Modules - Default settings --- +# +if (WIN32 OR WIN64) + # NSIS does not support semicolons..... + set(YUNICOMPONENT_CORE "yuni_core") + set(YUNICOMPONENT_ALGORITHMS "yuni_algorithms") + set(YUNICOMPONENT_MEDIA_CORE "yuni_media_core") + set(YUNICOMPONENT_DEVICE_DISPLAY "yuni_device_display") + set(YUNICOMPONENT_UUID "yuni_uuid") + set(YUNICOMPONENT_MARSHAL "yuni_marshal") + set(YUNICOMPONENT_NET "yuni_net") + set(YUNICOMPONENT_MESSAGING "yuni_messaging") + set(YUNICOMPONENT_DBI "yuni_dbi") + set(YUNICOMPONENT_PARSER "yuni_parser") +else() + set(YUNICOMPONENT_CORE "yuni-core") + set(YUNICOMPONENT_ALGORITHMS "yuni-algorithms") + set(YUNICOMPONENT_MEDIA_CORE "yuni-media-core") + set(YUNICOMPONENT_DEVICE_DISPLAY "yuni-device-display") + set(YUNICOMPONENT_UUID "yuni-uuid") + set(YUNICOMPONENT_MARSHAL "yuni-marshal") + set(YUNICOMPONENT_NET "yuni-net") + set(YUNICOMPONENT_MESSAGING "yuni-messaging") + set(YUNICOMPONENT_DBI "yuni-dbi") + set(YUNICOMPONENT_PARSER "yuni-parser") +endif() + + + + +# Core +set(YUNI_MODULE_CORE true) # Must be True + +# benchmarks +set(YUNI_BENCHMARKS false) + +# VFS +#set(YUNI_MODULE_VFS false) +# set(YUNI_MODULE_VFS_FILE true) + +# VM +set(YUNI_MODULE_VM false) + +# Marshal +set(YUNI_MARSHAL false) + +# Devices +set(YUNI_MODULE_DEVICES false) + set(YUNI_MODULE_DEVICE_DISPLAY true) + set(YUNI_MODULE_DEVICE_KEYBOARD true) + set(YUNI_MODULE_DEVICE_MOUSE true) + +set(YUNI_MODULE_DBI false) + set(YUNI_MODULE_DBI_SQLITE false) + +# Media +set(YUNI_MODULE_MEDIA false) + +# Network +set(YUNI_MODULE_NET false) + +# Messaging +set(YUNI_MODULE_MESSAGING false) + +# LDO +set(YUNI_MODULE_LDO false) + +# Graphics +set(YUNI_MODULE_GRAPHICS false) +set(YUNI_MODULE_OPENGL false) + +# UI (User Interface) +set(YUNI_MODULE_UI false) + +# Algorithms +set(YUNI_MODULE_ALGORITHMS false) + +# UUID +set(YUNI_MODULE_EXTRA_UUID false) + +# Doc +set(YUNI_MODULE_DOCUMENTATION false) + +# Parser Generator +set(YUNI_MODULE_PARSER false) + +# Tests +set(YUNI_TESTS false) + + + + + + +# The list of all available modules +# There is no need for `core`, which is implicit +set(YUNI_MODULE_LIST + algorithms + vm + marshal + vfs + vfs-local + media + devices + display + keyboard + mouse + graphics + opengl + ui + dbi + dbi-sqlite + net + netserver + netclient + ldo + # extra + uuid + docs + parser + benchmarks +) + + + + +# +# --- Command lines options --- +# +if (MODULES) + set(KeywordError false) + string(REPLACE "," ";" MODULES "${MODULES}") + string(REPLACE " " ";" MODULES "${MODULES}") + string(REPLACE "+" "" MODULES "${MODULES}") + + foreach(it ${MODULES}) + set(KeywordIsKnown false) + + # core + if ("${it}" STREQUAL "core") + set(YUNI_MODULE_CORE true) + set(KeywordIsKnown true) + endif() + # -core + if ("${it}" STREQUAL "-core") + set(KeywordIsKnown true) + YMESSAGE("[!!] Module: Impossible to disable the core module") + set(KeywordError true) + endif() + + # all + if ("${it}" STREQUAL "all") + set(YUNI_MODULE_CORE true) + #set(YUNI_MODULE_VFS true) + set(YUNI_MODULE_DEVICES true) + set(YUNI_MODULE_VM true) + set(YUNI_MODULE_MEDIA true) + set(YUNI_MODULE_NET true) + set(YUNI_MODULE_MESSAGING true) + set(YUNI_MODULE_GRAPHICS true) + set(YUNI_MODULE_OPENGL true) + set(YUNI_MODULE_UI true) + set(YUNI_MODULE_ALGORITHMS true) + set(YUNI_MODULE_EXTRA_UUID true) + set(YUNI_MODULE_LDO true) + set(YUNI_MODULE_DOCUMENTATION true) + set(YUNI_MODULE_MARSHAL true) + set(YUNI_MODULE_DBI true) + set(YUNI_MODULE_PARSER true) + set(YUNI_TESTS true) + set(YUNI_BENCHMARKS true) + set(KeywordIsKnown true) + endif() + + # vfs + #if ("${it}" STREQUAL "vfs") + # set(YUNI_MODULE_VFS true) + # set(KeywordIsKnown true) + #endif() + # -vfs + #if ("${it}" STREQUAL "-vfs") + # set(YUNI_MODULE_VFS false) + # set(KeywordIsKnown true) + #endif() + + # vfs-local + #if ("${it}" STREQUAL "vfs-local") + # set(YUNI_MODULE_VFS true) + # set(YUNI_MODULE_VFS_LOCAL true) + # set(KeywordIsKnown true) + #endif() + # -vfs + #if ("${it}" STREQUAL "-vfs-local") + # set(YUNI_MODULE_VFS_LOCAL false) + # set(KeywordIsKnown true) + #endif() + + # benchmarks + if ("${it}" STREQUAL "benchmarks") + set(YUNI_BENCHMARKS true) + set(KeywordIsKnown true) + endif() + # -benchmarks + if ("${it}" STREQUAL "-benchmarks") + set(YUNI_BENCHMARKS false) + set(KeywordIsKnown true) + endif() + + # vm + if ("${it}" STREQUAL "vm") + set(YUNI_MODULE_VM true) + set(KeywordIsKnown true) + endif() + # -vm + if ("${it}" STREQUAL "-vm") + set(YUNI_MODULE_VM false) + set(KeywordIsKnown true) + endif() + + # dbi + if ("${it}" STREQUAL "dbi") + set(YUNI_MODULE_DBI true) + set(KeywordIsKnown true) + endif() + # -dbi + if ("${it}" STREQUAL "-dbi") + set(YUNI_MODULE_DBI false) + set(KeywordIsKnown true) + endif() + + # dbi-sqlite + if ("${it}" STREQUAL "dbi-sqlite") + set(YUNI_MODULE_DBI_SQLITE true) + set(KeywordIsKnown true) + endif() + # -dbi-sqlite + if ("${it}" STREQUAL "-dbi-sqlite") + set(YUNI_MODULE_DBI_SQLITE false) + set(KeywordIsKnown true) + endif() + + # marshal + if ("${it}" STREQUAL "marshal") + set(YUNI_MODULE_MARSHAL true) + set(KeywordIsKnown true) + endif() + # -marshal + if ("${it}" STREQUAL "-marshal") + set(YUNI_MODULE_MARSHAL false) + set(KeywordIsKnown true) + endif() + + # messaging + if ("${it}" STREQUAL "messaging") + set(YUNI_MODULE_MESSAGING true) + set(KeywordIsKnown true) + endif() + # -messaging + if ("${it}" STREQUAL "-messaging") + set(YUNI_MODULE_MESSAGING false) + set(KeywordIsKnown true) + endif() + + # ldo + if ("${it}" STREQUAL "ldo") + set(YUNI_MODULE_LDO true) + set(KeywordIsKnown true) + endif() + # -ldo + if ("${it}" STREQUAL "-ldo") + set(YUNI_MODULE_LDO false) + set(KeywordIsKnown true) + endif() + + # algorithms + if ("${it}" STREQUAL "algorithms") + set(YUNI_MODULE_ALGORITHMS true) + set(KeywordIsKnown true) + endif() + # -algorithms + if ("${it}" STREQUAL "-algorithms") + set(YUNI_MODULE_ALGORITHMS false) + set(KeywordIsKnown true) + endif() + + + # display + if ("${it}" STREQUAL "display") + set(YUNI_MODULE_DEVICE_DISPLAY true) + set(KeywordIsKnown true) + endif() + # -display + if ("${it}" STREQUAL "-display") + set(YUNI_MODULE_DEVICE_DISPLAY false) + set(KeywordIsKnown true) + endif() + + # keyboard + if ("${it}" STREQUAL "keyboard") + set(YUNI_MODULE_DEVICE_KEYBOARD true) + set(KeywordIsKnown true) + endif() + # -keyboard + if ("${it}" STREQUAL "-keyboard") + set(YUNI_MODULE_DEVICE_KEYBOARD false) + set(KeywordIsKnown true) + endif() + + # mouse + if ("${it}" STREQUAL "mouse") + set(YUNI_MODULE_DEVICE_MOUSE true) + set(KeywordIsKnown true) + endif() + # -mouse + if ("${it}" STREQUAL "-mouse") + set(YUNI_MODULE_DEVICE_MOUSE false) + set(KeywordIsKnown true) + endif() + + # devices + if ("${it}" STREQUAL "devices") + set(YUNI_MODULE_DEVICES true) + set(KeywordIsKnown true) + endif() + # -devices + if ("${it}" STREQUAL "-devices") + set(YUNI_MODULE_DEVICES false) + set(KeywordIsKnown true) + endif() + + + # net + if ("${it}" STREQUAL "net") + set(YUNI_MODULE_NET true) + set(KeywordIsKnown true) + endif() + # -net + if ("${it}" STREQUAL "-net") + set(YUNI_MODULE_NET false) + set(KeywordIsKnown true) + endif() + + # media + if ("${it}" STREQUAL "media") + set(KeywordIsKnown true) + set(YUNI_MODULE_MEDIA true) + endif() + # -media + if ("${it}" STREQUAL "-media") + set(KeywordIsKnown true) + set(YUNI_MODULE_MEDIA false) + endif() + + + # Tests + if ("${it}" STREQUAL "tests") + set(KeywordIsKnown true) + set(YUNI_TESTS true) + endif() + # -tests + if ("${it}" STREQUAL "-tests") + set(KeywordIsKnown true) + set(YUNI_TESTS false) + endif() + + # graphics (Graphic renderers) + if ("${it}" STREQUAL "graphics") + set(KeywordIsKnown true) + set(YUNI_MODULE_GRAPHICS true) + endif() + # -graphics + if ("${it}" STREQUAL "-graphics") + set(KeywordIsKnown true) + set(YUNI_MODULE_GRAPHICS false) + endif() + + # OpenGL renderer + if ("${it}" STREQUAL "opengl") + set(KeywordIsKnown true) + set(YUNI_MODULE_OPENGL true) + endif() + # -opengl + if ("${it}" STREQUAL "-opengl") + set(KeywordIsKnown true) + set(YUNI_MODULE_OPENGL false) + endif() + + # ui (User Interface) + if ("${it}" STREQUAL "ui") + set(KeywordIsKnown true) + set(YUNI_MODULE_UI true) + endif() + # -ui + if ("${it}" STREQUAL "-ui") + set(KeywordIsKnown true) + set(YUNI_MODULE_UI false) + endif() + + # uuid + if ("${it}" STREQUAL "uuid") + set(KeywordIsKnown true) + set(YUNI_MODULE_EXTRA_UUID true) + endif() + # -uuid + if ("${it}" STREQUAL "-uuid") + set(KeywordIsKnown true) + set(YUNI_MODULE_EXTRA_UUID false) + endif() + + # parser + if ("${it}" STREQUAL "parser") + set(KeywordIsKnown true) + set(YUNI_MODULE_PARSER true) + endif() + # -parser + if ("${it}" STREQUAL "-parser") + set(KeywordIsKnown true) + set(YUNI_MODULE_PARSER false) + endif() + + # docs + if ("${it}" STREQUAL "docs" OR "${it}" STREQUAL "doc") + set(KeywordIsKnown true) + set(YUNI_MODULE_DOCUMENTATION true) + endif() + # -docs + if ("${it}" STREQUAL "-doc" OR "${it}" STREQUAL "-docs") + set(KeywordIsKnown true) + set(YUNI_MODULE_DOCUMENTATION false) + endif() + + if (NOT KeywordIsKnown) + YMESSAGE("[!!] Unknown module from command line: `${it}` (ignored)") + set(KeywordError true) + endif() + + endforeach() + + if (KeywordError) + YMESSAGE("") + YMESSAGE("Errors on modules. Here is the list of all available modules :") + YMESSAGE("(+ : Enable the module, - disable the module)") + YMESSAGE(" Main and virtual modules") + YMESSAGE(" +core : The core module (needed)") + YMESSAGE(" -/+tests : Atomic Tests for the yuni framework") + YMESSAGE(" +all : Enable all main modules (ui,tests,...)") + YMESSAGE(" -/+docs : Documentation Tools") + #YMESSAGE(" The VFS module") + #YMESSAGE(" -/+vfs : The Virtual filesystem") + #YMESSAGE(" -/+vfs-local : Support for the local filesystems") + YMESSAGE(" The device modules") + YMESSAGE(" -/+devices : All devices (display,keyboard,mouse...)") + YMESSAGE(" -/+display : The Display device") + YMESSAGE(" -/+keyboard : The Keyboard device") + YMESSAGE(" -/+mouse : The Mouse device") + YMESSAGE(" The media modules") + YMESSAGE(" -/+media : The Media module (default: disabled)") + YMESSAGE(" The graphics modules") + YMESSAGE(" -/+opengl : The OpenGL renderer module (default: disabled)") + YMESSAGE(" The ui modules") + YMESSAGE(" -/+ui : The ui module (default: disabled)") + YMESSAGE(" The virtual machine module") + YMESSAGE(" -/+vm : The Virtual machine") + YMESSAGE(" The network modules") + YMESSAGE(" -/+net : The network core module (default: disabled)") + YMESSAGE(" -/+messaging : The messaging module (default: disabled)") + YMESSAGE(" The DBI modules") + YMESSAGE(" -/+dbi : The Database Indepedent module (default: disabled)") + YMESSAGE(" The extra modules") + YMESSAGE(" -/+uuid : UUID (default: disabled)") + YMESSAGE(" -/+marshal : The Marshal module (for Object serialization, default: disabled)") + YMESSAGE(" -/+algorithms : Standard algorithms") + YMESSAGE(" -/+parser : Parser Generator") + YMESSAGE(" -/+benchmarks : Benchmarks") + YMESSAGE("") + message(FATAL_ERROR "Errors on module names") + endif() +endif() + + +# +# Dependencies +# +if (YUNI_MODULE_OPENGL) + set(YUNI_MODULE_GRAPHICS true) +endif() +if (YUNI_MODULE_UI) + set(YUNI_MODULE_DEVICES true) + set(YUNI_MODULE_DEVICE_DISPLAY true) +endif() +if (YUNI_MODULE_LDO) + set(YUNI_MODULE_NET true) +endif() +if (YUNI_MODULE_MESSAGING) + set(YUNI_MODULE_NET true) + set(YUNI_MODULE_MARSHAL true) +endif() +if (YUNI_MODULE_DBI_SQLITE) + set(YUNI_MODULE_DBI true) +endif() +if (YUNI_MODULE_DBI) + set(YUNI_MODULE_DBI_SQLITE true) +endif() + + + + + + +# +# List of all available modules +# + +set(YUNI_MODULE_AVAILABLE "core") + +if (YUNI_MODULE_ALGORITHMS) + list(APPEND YUNI_MODULE_AVAILABLE algorithms) +endif() + +if (YUNI_MODULE_DBI) + list(APPEND YUNI_MODULE_AVAILABLE dbi) + if (YUNI_MODULE_DBI_SQLITE) + list(APPEND YUNI_MODULE_AVAILABLE dbi-sqlite) + endif() +endif() + +if (YUNI_MODULE_DEVICES) + list(APPEND YUNI_MODULE_AVAILABLE devices) + if (YUNI_MODULE_DEVICE_DISPLAY) + list(APPEND YUNI_MODULE_AVAILABLE display) + endif() + if (YUNI_MODULE_DEVICE_MOUSE) + list(APPEND YUNI_MODULE_AVAILABLE mouse) + endif() + if (YUNI_MODULE_DEVICE_KEYBOARD) + list(APPEND YUNI_MODULE_AVAILABLE keyboard) + endif() +endif() + +if (YUNI_MODULE_VFS) + list(APPEND YUNI_MODULE_AVAILABLE vfs) + if (YUNI_MODULE_VFS_FILE) + list(APPEND YUNI_MODULE_AVAILABLE vfs-local) + endif() +endif() + +if (YUNI_MODULE_VM) + list(APPEND YUNI_MODULE_AVAILABLE vm) +endif() + +if (YUNI_MODULE_MARSHAL) + list(APPEND YUNI_MODULE_AVAILABLE marshal) +endif() + +if (YUNI_MODULE_NET) + list(APPEND YUNI_MODULE_AVAILABLE net) +endif() + +if (YUNI_MODULE_MESSAGING) + list(APPEND YUNI_MODULE_AVAILABLE messaging) +endif() + +if (YUNI_MODULE_LDO) + list(APPEND YUNI_MODULE_AVAILABLE ldo) +endif() + +if (YUNI_MODULE_MEDIA) + list(APPEND YUNI_MODULE_AVAILABLE media) +endif() + +if (YUNI_MODULE_GRAPHICS) + list(APPEND YUNI_MODULE_AVAILABLE graphics) + if (YUNI_MODULE_OPENGL) + list(APPEND YUNI_MODULE_AVAILABLE opengl) + endif() +endif() + +if (YUNI_MODULE_UI) + list(APPEND YUNI_MODULE_AVAILABLE ui) +endif() + +if (YUNI_MODULE_DOCUMENTATION) + list(APPEND YUNI_MODULE_AVAILABLE docs) +endif() + +if (YUNI_MODULE_EXTRA_UUID) + list(APPEND YUNI_MODULE_AVAILABLE uuid) +endif() + +if (YUNI_MODULE_PARSER) + list(APPEND YUNI_MODULE_AVAILABLE parser) +endif() + +if (YUNI_BENCHMARKS) + list(APPEND YUNI_MODULE_AVAILABLE benchmarks) +endif() + diff --git a/src/ext/yuni/src/cmake/system-information.cmake b/src/ext/yuni/src/cmake/system-information.cmake new file mode 100644 index 0000000000..5f1c4ddef2 --- /dev/null +++ b/src/ext/yuni/src/cmake/system-information.cmake @@ -0,0 +1,65 @@ + +# +# CMake Generator / Compiler +# +YMESSAGE_TITLE("Generator : " "${CMAKE_GENERATOR}") +if(MSVC) + if (WIN64) + YMESSAGE("Compiler: Visual Studio (64bits)") + else() + YMESSAGE("Compiler: Visual Studio (32bits)") + endif() +endif() + +if(MINGW) + if (WIN64) + YMESSAGE("Compiler: MinGW (64bits)") + else() + YMESSAGE("Compiler: MinGW (32bits)") + endif() +endif() + +if(XCODE) + YMESSAGE("Compiler: XCode") +endif() +if(CMAKE_COMPILER_IS_GNUCXX) + if(NOT GNUCXX_VERSION) + # -dumpversion might be used + execute_process(COMMAND ${CMAKE_CXX_COMPILER} "--version" OUTPUT_VARIABLE GNUCXX_VERSION_N ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX REPLACE "Copyright.*" "" GNUCXX_VERSION_N "${GNUCXX_VERSION_N}") + string(STRIP "${GNUCXX_VERSION_N}" GNUCXX_VERSION_N) + set(GNUCXX_VERSION "${GNUCXX_VERSION_N}" CACHE INTERNAL "Version of the Gnu Gxx compiler") + endif() + YMESSAGE("g++ Variant : ${GNUCXX_VERSION}") +endif() + + + + +# +# Information about the current operating system +# +if(APPLE) + execute_process(COMMAND sw_vers -productName OUTPUT_VARIABLE SW_PN OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND sw_vers -productVersion OUTPUT_VARIABLE SW_PV OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND sw_vers -buildVersion OUTPUT_VARIABLE SW_BV OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND sysctl -n hw.packages OUTPUT_VARIABLE HI_CPU_COUNT OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND sysctl -n machdep.cpu.core_count OUTPUT_VARIABLE HI_CPU_CORE_COUNT + OUTPUT_STRIP_TRAILING_WHITESPACE) + # SSE + execute_process(COMMAND sysctl -n hw.optional.sse OUTPUT_VARIABLE CPU_SSE1 OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND sysctl -n hw.optional.sse2 OUTPUT_VARIABLE CPU_SSE2 OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND sysctl -n hw.optional.sse3 OUTPUT_VARIABLE CPU_SSE3 OUTPUT_STRIP_TRAILING_WHITESPACE) + # 64Bits ? + execute_process(COMMAND sysctl -n hw.cpu64bit_capable OUTPUT_VARIABLE HI_CPU_i64 + OUTPUT_STRIP_TRAILING_WHITESPACE) + # Display + YMESSAGE("System: ${SW_PN} ${SW_PV} ${SW_BV} - ${CMAKE_SYSTEM} (${CMAKE_SYSTEM_PROCESSOR})") + YMESSAGE(" ${HI_CPU_COUNT} CPUs (${HI_CPU_CORE_COUNT}-Core), SSE1:${CPU_SSE1}, SSE2:${CPU_SSE2}, " + "SSE3:${CPU_SSE3}, x86_64:${HI_CPU_i64}") +else() + YMESSAGE("System: ${CMAKE_SYSTEM} (${CMAKE_SYSTEM_PROCESSOR})") +endif() + + + diff --git a/src/ext/yuni/src/cmake/target.cmake b/src/ext/yuni/src/cmake/target.cmake new file mode 100644 index 0000000000..b0e23cfff0 --- /dev/null +++ b/src/ext/yuni/src/cmake/target.cmake @@ -0,0 +1,48 @@ + +set(YUNI_TARGET_DEBUG true) +set(YUNI_TARGET_RELEASE true) + +# Detecting 64-bit Windows +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + if(WIN32) + set(WIN64 true) + endif() +endif() + +string(COMPARE EQUAL "${CMAKE_BUILD_TYPE}" "" NO_BUILD_TYPE) +if(NO_BUILD_TYPE) + string(COMPARE EQUAL "${TARGET}" "" NO_BUILD_TYPE) + if(NO_BUILD_TYPE) + string(COMPARE EQUAL "${YUNI_TARGET}" "" NO_BUILD_TYPE) + if(NO_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "debug") + else() + set(CMAKE_BUILD_TYPE "${YUNI_TARGET}") + endif() + else() + set(CMAKE_BUILD_TYPE "${TARGET}") + endif() +endif() + +string(COMPARE EQUAL "${CMAKE_BUILD_TYPE}" "debug" BUILD_TYPE_IS_DEBUG) +string(COMPARE EQUAL "${CMAKE_BUILD_TYPE}" "release" BUILD_TYPE_IS_RELEASE) +if(NOT BUILD_TYPE_IS_DEBUG AND NOT BUILD_TYPE_IS_RELEASE) + set(CMAKE_BUILD_TYPE "debug") +endif() + + +string(COMPARE EQUAL "${CMAKE_BUILD_TYPE}" "debug" BUILD_TYPE_IS_DEBUG) +string(COMPARE EQUAL "${CMAKE_BUILD_TYPE}" "release" BUILD_TYPE_IS_RELEASE) +if(BUILD_TYPE_IS_DEBUG) + set(YUNI_TARGET_DEBUG true) + set(YUNI_TARGET_RELEASE false) +endif() +if(BUILD_TYPE_IS_RELEASE) + set(YUNI_TARGET_DEBUG false) + set(YUNI_TARGET_RELEASE true) +endif() + +# Reset +set(YUNI_TARGET "${CMAKE_BUILD_TYPE}") +set(TARGET "${CMAKE_BUILD_TYPE}") + diff --git a/src/ext/yuni/src/tools/CMakeLists.txt b/src/ext/yuni/src/tools/CMakeLists.txt new file mode 100644 index 0000000000..626318d9ea --- /dev/null +++ b/src/ext/yuni/src/tools/CMakeLists.txt @@ -0,0 +1,13 @@ +if (NOT YUNI_AUTO_COMPILE_YUNI_CONFIG) + if (NOT YUNI_SKIP_YUNI_CONFIG) + add_subdirectory(yuni-config) + endif() +endif(NOT YUNI_AUTO_COMPILE_YUNI_CONFIG) + +if (YUNI_MODULE_PARSER) + add_subdirectory(parser-generator) +endif() + +if (YUNI_MODULE_DOCUMENTATION) + #add_subdirectory(yuni-docmake) +endif() diff --git a/src/ext/yuni/src/tools/generators/commons.rb b/src/ext/yuni/src/tools/generators/commons.rb new file mode 100644 index 0000000000..95c9e1493f --- /dev/null +++ b/src/ext/yuni/src/tools/generators/commons.rb @@ -0,0 +1,123 @@ + +require 'erb' + + + +class Generator + + # + # \brief Constructor + # + def initialize + # Max Arguments + @maxArgumentCount = 16 + end + + def thisHeaderHasBeenGenerated(name) + "/*! +** \\internal This file is automatically generated by '#{name}'. +** Please make any modifications you wish to this script instead of +** this file, as they will otherwise be lost at the next generation. +*/" + end + + # getter + def argumentCount + @maxArgumentCount + end + # setter + def argumentCount= (value) + @maxArgumentCount = value + end + + def templateParameterList(count, prefix = ', ', name = 'A') + ret = '' + if count > 0 + ret += prefix + end + (0..count - 1).each do |i| + if i != 0 + ret += ', ' + end + ret += "class #{name}#{i}" + end + ret + end + + def list(count, name = 'A', prefix = '', suffix = '', separator = ', ', nmprefix = '', nmsuffix = '') + ret = '' + if count > 0 + ret += prefix + end + (0..count - 1).each do |i| + if i != 0 + ret += separator + end + ret += "#{nmprefix}#{name}#{i}#{nmsuffix}" + end + if count > 0 + ret += suffix + end + ret + end + + def variableList(count, name = 'A', varname = 'a', prefix = '') + ret = '' + if count > 0 + ret += prefix + end + (0..count - 1).each do |i| + if i != 0 + ret += ', ' + end + ret += "#{name}#{i} #{varname}#{i}" + end + ret + end + + def xArgumentsToStr(count) + if count == 0 + return "0 argument" + else + return (count == 1) ? "1 argument" : "#{count} arguments" + end + end + + def templateParameterListDoxygen(count) + ret = '' + (0..count-1).each do |i| + ret += "\t** \\tparam A#{i} The type of the " + # todo use `when` + ret += case i + when 0 then "first" + when 1 then "second" + when 2 then "third" + else "#{i+1}th" + end + ret += " argument" + if i != count - 1 + ret += "\n" + end + end + ret + end + + def include(fname) + erb = ERB.new(IO.read(File.dirname(__FILE__) + '/../../' + fname), nil, nil, 'erbout') + erb.filename = fname + generator = self + i = 0 + return erb.result(binding()) + end + + def include(fname,i) + erb = ERB.new(IO.read(File.dirname(__FILE__) + '/../../' + fname), nil, nil, 'erbout') + erb.filename = fname + generator = self + return erb.result(binding()) + end + + +end + + diff --git a/src/ext/yuni/src/tools/generators/regenerate-computed-headers.rb b/src/ext/yuni/src/tools/generators/regenerate-computed-headers.rb new file mode 100644 index 0000000000..43f2058ca0 --- /dev/null +++ b/src/ext/yuni/src/tools/generators/regenerate-computed-headers.rb @@ -0,0 +1,37 @@ + +require 'pathname' + + +class File + def self.find(dir, filename="*.*", subdirs=true) + Dir[ subdirs ? File.join(dir.split(/\\/), "**", filename) : File.join(dir.split(/\\/), filename) ] + end +end + + +puts "Regenerating computed headers" +puts "Warning: A stupid detection of PHP scripts is preset. Please remove it as soon as possible." +count = 0 +rootPath = Pathname.new(File.dirname(__FILE__) + "/../../").realpath.to_s +puts "Started from #{rootPath}" +File.find(rootPath, "*.generator.hpp").each do |f| + + # Try to detect PHP scripts. Really ugly but it will be removed anyway + data = IO.read(f) + isPHP = data.index('") + if (isPHP) + puts " . #{s} (php)" + else + puts " . #{s}" + end + if (!isPHP) + output = `erb "#{f}"` + File.open(headerFile, 'w') {|f| f.write(output) } + count += 1 + end +end +puts "Processed #{count} files." +puts "Done." diff --git a/src/ext/yuni/src/tools/testsuite/myopen4.rb b/src/ext/yuni/src/tools/testsuite/myopen4.rb new file mode 100644 index 0000000000..64f3d64d6a --- /dev/null +++ b/src/ext/yuni/src/tools/testsuite/myopen4.rb @@ -0,0 +1,100 @@ +#require 'rubygems' +require 'platform' +#require_gem 'Platform', '>= 0.4.0' + +case Platform::OS + +# win32/popen4 yields stdin, stdout, stderr and pid, respectively +when :win32 + + require 'win32/open3' + + # POpen4 provides the Rubyist a single API across platforms for executing a + # command in a child process with handles on stdout, stderr, and stdin streams + # as well as access to the process ID and exit status. + # + # Consider the following example (borrowed from Open4): + # + # require 'rubygems' + # require 'popen4' + # + # status = + # POpen4::popen4("cmd") do |stdout, stderr, stdin, pid| + # stdin.puts "echo hello world!" + # stdin.puts "echo ERROR! 1>&2" + # stdin.puts "exit" + # stdin.close + # + # puts "pid : #{ pid }" + # puts "stdout : #{ stdout.read.strip }" + # puts "stderr : #{ stderr.read.strip }" + # end + # + # puts "status : #{ status.inspect }" + # puts "exitstatus : #{ status.exitstatus }" + # + module POpen4 + # Starts a new process and hands IO objects representing the subprocess + # stdout, stderr, stdin streams and the pid (respectively) to the block + # supplied. If the command could not be started, return nil. + # + # The mode argument may be set to t[ext] or b[inary] and is used only on + # Windows platforms. + # + # The stdin stream and/or pid may be omitted from the block parameter list + # if they are not required. + def self.popen4(command, mode = "t") # :yields: stdout, stderr, stdin, pid + + err_output = nil + status = Open4.popen4(command, mode) do |stdin,stdout,stderr,pid| + yield stdout, stderr, stdin, pid + + # On windows we will always get an exit status of 3 unless + # we read to the end of the streams so we do this on all platforms + # so that our behavior is always the same. + stdout.read unless stdout.eof? + + # On windows executing a non existent command does not raise an error + # (as in unix) so on unix we return nil instead of a status object and + # on windows we try to determine if we couldn't start the command and + # return nil instead of the Process::Status object. + stderr.rewind + err_output = stderr.read + end + + #if status.exitstatus == 1 && + # err_output.match(/is not recognized as an internal or external command/) + # return nil + #end + + return status + end # def + end # module + + +else # unix popen4 yields pid, stdin, stdout and stderr, respectively + # :enddoc: + require 'open4' + module POpen4 + def self.popen4(command, mode = "t") + begin + return status = Open4.popen4(command) do |pid,stdin,stdout,stderr| + yield stdout, stderr, stdin, pid + # On windows we will always get an exit status of 3 unless + # we read to the end of the streams so we do this on all platforms + # so that our behavior is always the same. + stdout.read unless stdout.eof? + stderr.read unless stderr.eof? + end + rescue Errno::ENOENT => e + # On windows executing a non existent command does not raise an error + # (as in unix) so on unix we return nil instead of a status object and + # on windows we try to determine if we couldn't start the command and + # return nil instead of the Process::Status object. + return nil + end + end #def + end #module + +end + diff --git a/src/ext/yuni/src/tools/testsuite/open4.rb b/src/ext/yuni/src/tools/testsuite/open4.rb new file mode 100644 index 0000000000..3027b47c7c --- /dev/null +++ b/src/ext/yuni/src/tools/testsuite/open4.rb @@ -0,0 +1,401 @@ +# vim: ts=2:sw=2:sts=2:et:fdm=marker +require 'fcntl' +require 'timeout' +require 'thread' + +module Open4 +#--{{{ + VERSION = '1.0.1' + def self.version() VERSION end + + class Error < ::StandardError; end + + def popen4(*cmd, &b) +#--{{{ + pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe + + verbose = $VERBOSE + begin + $VERBOSE = nil + ps.first.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) + ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) + + cid = fork { + pw.last.close + STDIN.reopen pw.first + pw.first.close + + pr.first.close + STDOUT.reopen pr.last + pr.last.close + + pe.first.close + STDERR.reopen pe.last + pe.last.close + + STDOUT.sync = STDERR.sync = true + + begin + exec(*cmd) + raise 'forty-two' + rescue Exception => e + Marshal.dump(e, ps.last) + ps.last.flush + end + ps.last.close unless (ps.last.closed?) + exit! + } + ensure + $VERBOSE = verbose + end + + [pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close} + + begin + e = Marshal.load ps.first + raise(Exception === e ? e : "unknown failure!") + rescue EOFError # If we get an EOF error, then the exec was successful + 42 + ensure + ps.first.close + end + + pw.last.sync = true + + pi = [pw.last, pr.first, pe.first] + + if b + begin + b[cid, *pi] + Process.waitpid2(cid).last + ensure + pi.each{|fd| fd.close unless fd.closed?} + end + else + [cid, pw.last, pr.first, pe.first] + end +#--}}} + end + alias open4 popen4 + module_function :popen4 + module_function :open4 + + class SpawnError < Error +#--{{{ + attr 'cmd' + attr 'status' + attr 'signals' + def exitstatus + @status.exitstatus + end + def initialize cmd, status + @cmd, @status = cmd, status + @signals = {} + if status.signaled? + @signals['termsig'] = status.termsig + @signals['stopsig'] = status.stopsig + end + sigs = @signals.map{|k,v| "#{ k }:#{ v.inspect }"}.join(' ') + super "cmd <#{ cmd }> failed with status <#{ exitstatus.inspect }> signals <#{ sigs }>" + end +#--}}} + end + + class ThreadEnsemble +#--{{{ + attr 'threads' + + def initialize cid + @cid, @threads, @argv, @done, @running = cid, [], [], Queue.new, false + @killed = false + end + + def add_thread *a, &b + @running ? raise : (@argv << [a, b]) + end + +# +# take down process more nicely +# + def killall + c = Thread.critical + return nil if @killed + Thread.critical = true + (@threads - [Thread.current]).each{|t| t.kill rescue nil} + @killed = true + ensure + Thread.critical = c + end + + def run + @running = true + + begin + @argv.each do |a, b| + @threads << Thread.new(*a) do |*a| + begin + b[*a] + ensure + killall rescue nil if $! + @done.push Thread.current + end + end + end + rescue + killall + raise + ensure + all_done + end + + @threads.map{|t| t.value} + end + + def all_done + @threads.size.times{ @done.pop } + end +#--}}} + end + + def to timeout = nil +#--{{{ + Timeout.timeout(timeout){ yield } +#--}}} + end + module_function :to + + def new_thread *a, &b +#--{{{ + cur = Thread.current + Thread.new(*a) do |*a| + begin + b[*a] + rescue Exception => e + cur.raise e + end + end +#--}}} + end + module_function :new_thread + + def getopts opts = {} +#--{{{ + lambda do |*args| + keys, default, ignored = args + catch('opt') do + [keys].flatten.each do |key| + [key, key.to_s, key.to_s.intern].each do |key| + throw 'opt', opts[key] if opts.has_key?(key) + end + end + default + end + end +#--}}} + end + module_function :getopts + + def relay src, dst = nil, t = nil +#--{{{ + send_dst = + if dst.respond_to?(:call) + lambda{|buf| dst.call(buf)} + else + lambda{|buf| dst << buf} + end + + unless src.nil? + if src.respond_to? :gets + while buf = to(t){ src.gets } + send_dst[buf] + end + + elsif src.respond_to? :each + q = Queue.new + th = nil + + timer_set = lambda do |t| + th = new_thread{ to(t){ q.pop } } + end + + timer_cancel = lambda do |t| + th.kill if th rescue nil + end + + timer_set[t] + begin + src.each do |buf| + timer_cancel[t] + send_dst[buf] + timer_set[t] + end + ensure + timer_cancel[t] + end + + elsif src.respond_to? :read + buf = to(t){ src.read } + send_dst[buf] + + else + buf = to(t){ src.to_s } + send_dst[buf] + end + end +#--}}} + end + module_function :relay + + def spawn arg, *argv +#--{{{ + argv.unshift(arg) + opts = ((argv.size > 1 and Hash === argv.last) ? argv.pop : {}) + argv.flatten! + cmd = argv.join(' ') + + + getopt = getopts opts + + ignore_exit_failure = getopt[ 'ignore_exit_failure', getopt['quiet', false] ] + ignore_exec_failure = getopt[ 'ignore_exec_failure', !getopt['raise', true] ] + exitstatus = getopt[ %w( exitstatus exit_status status ) ] + stdin = getopt[ %w( stdin in i 0 ) << 0 ] + stdout = getopt[ %w( stdout out o 1 ) << 1 ] + stderr = getopt[ %w( stderr err e 2 ) << 2 ] + pid = getopt[ 'pid' ] + timeout = getopt[ %w( timeout spawn_timeout ) ] + stdin_timeout = getopt[ %w( stdin_timeout ) ] + stdout_timeout = getopt[ %w( stdout_timeout io_timeout ) ] + stderr_timeout = getopt[ %w( stderr_timeout ) ] + status = getopt[ %w( status ) ] + cwd = getopt[ %w( cwd dir ) ] + + exitstatus = + case exitstatus + when TrueClass, FalseClass + ignore_exit_failure = true if exitstatus + [0] + else + [*(exitstatus || 0)].map{|i| Integer i} + end + + stdin ||= '' if stdin_timeout + stdout ||= '' if stdout_timeout + stderr ||= '' if stderr_timeout + + started = false + + status = + begin + chdir(cwd) do + Timeout::timeout(timeout) do + popen4(*argv) do |c, i, o, e| + started = true + + %w( replace pid= << push update ).each do |msg| + break(pid.send(msg, c)) if pid.respond_to? msg + end + + te = ThreadEnsemble.new c + + te.add_thread(i, stdin) do |i, stdin| + relay stdin, i, stdin_timeout + i.close rescue nil + end + + te.add_thread(o, stdout) do |o, stdout| + relay o, stdout, stdout_timeout + end + + te.add_thread(e, stderr) do |o, stderr| + relay e, stderr, stderr_timeout + end + + te.run + end + end + end + rescue + raise unless(not started and ignore_exec_failure) + end + + raise SpawnError.new(cmd, status) unless + (ignore_exit_failure or (status.nil? and ignore_exec_failure) or exitstatus.include?(status.exitstatus)) + + status +#--}}} + end + module_function :spawn + + def chdir cwd, &block + return(block.call Dir.pwd) unless cwd + Dir.chdir cwd, &block + end + module_function :chdir + + def background arg, *argv +#--{{{ + require 'thread' + q = Queue.new + opts = { 'pid' => q, :pid => q } + case argv.last + when Hash + argv.last.update opts + else + argv.push opts + end + thread = Thread.new(arg, argv){|arg, argv| spawn arg, *argv} + sc = class << thread; self; end + sc.module_eval { + define_method(:pid){ @pid ||= q.pop } + define_method(:spawn_status){ @spawn_status ||= value } + define_method(:exitstatus){ @exitstatus ||= spawn_status.exitstatus } + } + thread +#--}}} + end + alias bg background + module_function :background + module_function :bg + + def maim pid, opts = {} +#--{{{ + getopt = getopts opts + sigs = getopt[ 'signals', %w(SIGTERM SIGQUIT SIGKILL) ] + suspend = getopt[ 'suspend', 4 ] + pid = Integer pid + existed = false + sigs.each do |sig| + begin + Process.kill sig, pid + existed = true + rescue Errno::ESRCH + return(existed ? nil : true) + end + return true unless alive? pid + sleep suspend + return true unless alive? pid + end + return(not alive?(pid)) +#--}}} + end + module_function :maim + + def alive pid +#--{{{ + pid = Integer pid + begin + Process.kill 0, pid + true + rescue Errno::ESRCH + false + end +#--}}} + end + alias alive? alive + module_function :alive + module_function :'alive?' +#--}}} +end + +def open4(*cmd, &b) cmd.size == 0 ? Open4 : Open4::popen4(*cmd, &b) end diff --git a/src/ext/yuni/src/tools/testsuite/platform.rb b/src/ext/yuni/src/tools/testsuite/platform.rb new file mode 100644 index 0000000000..6fa86048b8 --- /dev/null +++ b/src/ext/yuni/src/tools/testsuite/platform.rb @@ -0,0 +1,82 @@ +# +# platform.rb: naive platform detection for Ruby +# author: Matt Mower +# + +# == Platform +# +# Platform is a simple module which parses the Ruby constant +# RUBY_PLATFORM and works out the OS, it's implementation, +# and the architecture it's running on. +# +# The motivation for writing this was coming across a case where +# +# +if RUBY_PLATFORM =~ /win/+ +# +# didn't behave as expected (i.e. on powerpc-darwin-8.1.0) +# +# It is hoped that providing a library for parsing the platform +# means that we can cover all the cases and have something which +# works reliably 99% of the time. +# +# Please report any anomalies or new combinations to the author(s). +# +# == Use +# +# require "platform" +# +# defines +# +# Platform::OS (:unix,:win32,:vms,:os2) +# Platform::IMPL (:macosx,:linux,:mswin) +# Platform::ARCH (:powerpc,:x86,:alpha) +# +# if an unknown configuration is encountered any (or all) of +# these constant may have the value :unknown. +# +# To display the combination for your setup run +# +# ruby platform.rb +# +module Platform + + # Each platform is defined as + # [ /regex/, ::OS, ::IMPL ] + # define them from most to least specific and + # [ /.*/, :unknown, :unknown ] should always come last + # whither AIX, SOLARIS, and the other unixen? + PLATFORMS = [ + [ /darwin/i, :unix, :macosx ], + [ /linux/i, :unix, :linux ], + [ /freebsd/i, :unix, :freebsd ], + [ /netbsd/i, :unix, :netbsd ], + [ /mswin/i, :win32, :mswin ], + [ /cygwin/i, :hybrid, :cygwin ], + [ /mingw/i, :win32, :mingw ], + [ /bccwin/i, :win32, :bccwin ], + [ /wince/i, :win32, :wince ], + [ /vms/i, :vms, :vms ], + [ /os2/i, :os2, :os2 ], + [ /solaris/i, :unix, :solaris ], + [ /irix/i, :unix, :irix ], + [ /.*/, :unknown, :unknown ] + ] + (*), OS, IMPL = PLATFORMS.find { |p| RUBY_PLATFORM =~ /#{p[0]}/ } + + # What about AMD, Turion, Motorola, etc..? + ARCHS = [ + [ /i\d86/, :x86 ], + [ /ia64/, :ia64 ], + [ /powerpc/, :powerpc ], + [ /alpha/, :alpha ], + [ /sparc/i, :sparc ], + [ /mips/i, :mips ], + [ /.*/, :unknown ] + ] + (*), ARCH = ARCHS.find { |a| RUBY_PLATFORM =~ /#{a[0]}/} + +end + +if __FILE__ == $0 + puts "Platform OS=#{Platform::OS}, IMPL=#{Platform::IMPL}, ARCH=#{Platform::ARCH}" +end diff --git a/src/ext/yuni/src/tools/testsuite/testcase.rb b/src/ext/yuni/src/tools/testsuite/testcase.rb new file mode 100644 index 0000000000..d7a3a6f709 --- /dev/null +++ b/src/ext/yuni/src/tools/testsuite/testcase.rb @@ -0,0 +1,207 @@ + +require "ostruct" +require 'timeout' +require 'myopen4' + +# -2 : invalid +# -1 : timeout +# 0 : failed +# 1 : ok + + + +def loadConfigFile(path) + eval <<-END_CONFIG + options = OpenStruct.new + #{File.read(path)} + options + END_CONFIG +end + + + +def compile(options) + options.compilation = OpenStruct.new + options.compilation.message = '' + options.compilation.result = 0 + options.compilation.stdout = '' + options.compilation.stderr = '' + t = 10 * 60 + status = 0 + # Timeout for compiling + timeout(t) { + status = POpen4.popen4(options.make) do |stdout, stderr, stdin, pid| + while (s = stderr.gets) != nil + options.compilation.stderr += s + end + while (s = stdout.gets) != nil + options.compilation.stdout += s + end + end + } + if status == 0 + options.compilation.result = 1 + else + options.compilation.result = 0 + options.compilation.message += "The compilation has failed\n" + end + rescue Timeout::Error + options.compilation.message += "Compilation failed: Timeout (after " + t + " seconds)\n" + options.compilation.result = -1 +end + + + +def execute(options) + options.executable = OpenStruct.new + options.executable.message = '' + options.executable.result = 1 + options.executable.stdout = '' + options.executable.stdoutExpected = nil + options.executable.stderr = '' + options.executable.stderrExpected = nil + options.executable.command = options.program + options.executable.timeout = options.timeout + options.executable.duration = 0 + if options.executable.timeout < 3 + options.executable.timeout = 3 + else + if options.executable.timeout > 60 + options.executable.timeout = 60 + end + end + if options.compilation.result != 1 + options.executable.message += "Not executed\n" + options.executable.result = -2 + return + end + status = 0 + timeout(options.executable.timeout) { + start = Time.now.to_f + status = POpen4.popen4(options.executable.command) do |stdout, stderr, stdin, pid| + while (s = stderr.gets) != nil + options.executable.stderr += s + end + while (s = stdout.gets) != nil + options.executable.stdout += s + end + end + e = Time.now.to_f + options.executable.duration = (e - start) * 1000 # ms + } + # Output comparison + if options.compareStdoutWith != nil and not options.compareStdoutWith.empty? + filename = options.path + '/' + options.compareStdoutWith + if File.exist?(filename) + f = File.new(filename) + text = f.read + if text != options.executable.stdout + options.executable.result = 0 + options.executable.message += "The stdout is not as expected.\n" + options.executable.stdoutExpected = text + end + else + options.executable.result = 0 + options.executable.message += "The file of reference for stdout has not been found.\n" + end + end + if options.compareStderrWith != nil and not options.compareStderrWith.empty? + filename = options.path + '/' + options.compareStderrWith + if File.exist?(filename) + f = File.new(options.path + '/' + options.compareStderrWith) + text = f.read + if text != options.executable.stderr + options.executable.result = 0 + options.executable.message += "The stderr is not as expected.\n" + options.executable.stderrExpected = text + end + else + options.executable.result = 0 + options.executable.message += "The file of reference for stderr has not been found.\n" + end + end + if options.exitStatus != status + options.executable.result = 0 + options.executable.message += "The exit status is incorrect.\n" + end + + # Rescue + rescue Timeout::Error + options.executable.message += "Execution failed: Timeout (after " + options.executable.timeout.to_s + options.executable.message += " seconds).\n" + options.executable.result = -1 +end + + +def resultToStr(value) + case value + when -2: "invalid" + when -1: "timeout" + when 1: "ok" + else "failed" + end +end + + +def writeXMLTest(tag, t) + if t != nil and not t.empty? + return "\t\t<#{tag}>\n" + end + "" +end + + +def generateReport(options) + r = '' + r += "\n" + r += "\t\n" % resultToStr(options.compilation.result) + r += writeXMLTest("msg", options.compilation.message) + r += writeXMLTest("stdout", options.compilation.stdout) + r += writeXMLTest("stderr", options.compilation.stderr) + r += "\t\n" + r += "\t\n" % resultToStr(options.executable.result) + r += writeXMLTest("cmd", options.executable.command) + r += writeXMLTest("msg", options.executable.message) + r += writeXMLTest("stdout", options.executable.stdout) + r += writeXMLTest("stderr", options.executable.stderr) + r += writeXMLTest("stdoutexpected", options.executable.stdoutExpected) + r += writeXMLTest("stderrexpected", options.executable.stderrExpected) + if options.executable.duration > 0 + r += "\t\t%.0f\n" % options.executable.duration + end + r += "\t\n" + + r += "" + File.open(options.report, 'w') {|f| f.write(r) } +end + + + +def executeTestcase(filename) + o = loadConfigFile(filename) + if nil != o.identifier and "" != o.identifier + #puts "Running testcase #{o.identifier}" + # Try to compile + compile(o) + # Execute the program + execute(o) + + # Global result for the testcase + if o.executable.result == -1 + o.result = -1 + else + o.result = (o.executable.result == 1 and o.compilation.result == 1) ? 1 : 0 + end + + # Generate the report + generateReport(o) + end +end + + +begin + ARGV.each do|a| + executeTestcase(a) + end +end + diff --git a/src/ext/yuni/src/tools/testsuite/win32/open3.so b/src/ext/yuni/src/tools/testsuite/win32/open3.so new file mode 100644 index 0000000000..b9ac4edd15 Binary files /dev/null and b/src/ext/yuni/src/tools/testsuite/win32/open3.so differ diff --git a/src/ext/yuni/src/tools/yuni-config/CMakeLists.txt b/src/ext/yuni/src/tools/yuni-config/CMakeLists.txt new file mode 100644 index 0000000000..e1cccc5d25 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-config/CMakeLists.txt @@ -0,0 +1,107 @@ +IF(NOT YUNI_AUTO_COMPILE_YUNI_CONFIG) + + Project(yuni-config CXX) + CMake_minimum_required(VERSION 2.8) + + IF(POLICY CMP0005) + CMake_Policy(SET CMP0005 NEW) + endif(POLICY CMP0005) + IF(POLICY CMP0011) + CMake_Policy(SET CMP0011 NEW) + endif(POLICY CMP0011) + + Include("${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/message.cmake") + +endif(NOT YUNI_AUTO_COMPILE_YUNI_CONFIG) + +if(YUNI_AUTO_COMPILE_YUNI_CONFIG) + YMESSAGE("") + YMESSAGE_BOLD("yuni-config (self)") +else() + YMESSAGE("") + YMESSAGE_BOLD("yuni-config") +endif(YUNI_AUTO_COMPILE_YUNI_CONFIG) + + +include("${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/common-settings.cmake") +include("${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules.cmake") + + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../..") + +# Disable all code related to thread-safety +add_definitions("-DYUNI_NO_THREAD_SAFE") + +# Add definitions to help finding yuni parameters once installed (prefix + versioned path) +add_definitions("-DYUNI_VERSIONED_INST_PATH=\"${YUNI_VERSIONED_INST_PATH}\"") +add_definitions("-DYUNI_INSTALL_PREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +add_definitions("-DYUNI_SOURCE_TREE=\"${YUNI_SOURCE_TREE}\"") + + + +set(src + ../../yuni/core/string/string.h + ../../yuni/core/string/escape.h + ../../yuni/core/string/escape.hxx + ../../yuni/core/string/iterator.hxx + ../../yuni/core/string/iterator.inc.hpp + ../../yuni/core/string/operators.hxx + ../../yuni/core/string/string.cpp + ../../yuni/core/string/string.h + ../../yuni/core/string/string.hxx + ../../yuni/core/string/utf8char.h + ../../yuni/core/string/utf8char.hxx + ../../yuni/core/string/wstring.h + ../../yuni/core/string/wstring.hxx + ../../yuni/core/string/wstring.cpp + + ../../yuni/core/version/version.cpp + ../../yuni/core/getopt/option.cpp ../../yuni/core/getopt/parser.cpp + ../../yuni/core/getopt/option.cpp ../../yuni/core/getopt/parser.h + ../../yuni/core/getopt/option.cpp ../../yuni/core/getopt/parser.hxx + ../../yuni/core/getopt/option.cpp ../../yuni/core/getopt/option.h + ../../yuni/core/getopt/option.cpp ../../yuni/core/getopt/option.cpp + ../../yuni/io/constants.cpp + ../../yuni/io/file/file.cpp + ../../yuni/io/file/openmode.cpp + ../../yuni/io/file/stream.cpp + ../../yuni/io/exists.cpp + ../../yuni/io/filename-manipulation.cpp + ../../yuni/io/directory/current.cpp + ../../yuni/core/string/traits/traits.cpp + ../../yuni/thread/thread.cpp + ../../yuni/thread/mutex.cpp + + # iterator + ../../yuni/io/directory/iterator.h + ../../yuni/io/directory/iterator/iterator.h + ../../yuni/io/directory/iterator/iterator.hxx + ../../yuni/io/directory/iterator/iterator.cpp + ../../yuni/io/directory/iterator/detachedthread.h + + versions.h + versions.hxx + versions.cpp + + program.h + program.hxx + program.cpp + main.cpp) + +# Build the in-tree version of yuni-config. +add_executable(yuni-config ${src}) +set_target_properties(yuni-config PROPERTIES + COMPILE_FLAGS "-DYUNI_YUNICONFIG_IN_TREE=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\"" + RUNTIME_OUTPUT_DIRECTORY "${YUNI_OUTPUT_DIRECTORY}/bin" +) + +# If we are not bootstrapping, also build the "installable" yuni-config. +IF(NOT YUNI_BOOTSTRAP_YUNI_CONFIG) + + add_executable(yuni-config-${YUNI_VERSION} ${src}) + set_target_properties(yuni-config-${YUNI_VERSION} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${YUNI_OUTPUT_DIRECTORY}/bin") + install(TARGETS yuni-config-${YUNI_VERSION} RUNTIME DESTINATION bin) + +endif(NOT YUNI_BOOTSTRAP_YUNI_CONFIG) + diff --git a/src/ext/yuni/src/tools/yuni-config/main.cpp b/src/ext/yuni/src/tools/yuni-config/main.cpp new file mode 100644 index 0000000000..125c882d95 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-config/main.cpp @@ -0,0 +1,28 @@ +/* +** This file is part of libyuni, a cross-platform C++ framework (http://libyuni.org). +** +** This Source Code Form is subject to the terms of the Mozilla Public License +** v.2.0. If a copy of the MPL was not distributed with this file, You can +** obtain one at http://mozilla.org/MPL/2.0/. +** +** github: https://github.com/libyuni/libyuni/ +** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror) +*/ +#ifndef YUNI_NO_THREAD_SAFE +# define YUNI_NO_THREAD_SAFE // disabling thread-safety +#endif +#include +#include "program.h" + + + + +int main(int argc, char* argv[]) +{ + if (argc > 1) + { + Yuni::LibConfigProgram libconfig; + return libconfig.execute(argc, argv); + } + return 0; +} diff --git a/src/ext/yuni/src/tools/yuni-config/mark-for-yuni-sources b/src/ext/yuni/src/tools/yuni-config/mark-for-yuni-sources new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ext/yuni/src/tools/yuni-config/program.cpp b/src/ext/yuni/src/tools/yuni-config/program.cpp new file mode 100644 index 0000000000..26d763f26c --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-config/program.cpp @@ -0,0 +1,492 @@ +/* +** This file is part of libyuni, a cross-platform C++ framework (http://libyuni.org). +** +** This Source Code Form is subject to the terms of the Mozilla Public License +** v.2.0. If a copy of the MPL was not distributed with this file, You can +** obtain one at http://mozilla.org/MPL/2.0/. +** +** github: https://github.com/libyuni/libyuni/ +** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror) +*/ +#include "program.h" +#include +#include + +#define YUNI_LIBYUNI_CONFIG_SEPARATORS ", ;:\t\n" + + + +namespace Yuni +{ + + + LibConfigProgram::LibConfigProgram() : + pExitStatus(0), + pOptVersion(false), + pOptList(false), + pOptListOnlyVersions(false), + pOptNoDefaultPath(false), + pOptModuleList(false), + pOptDefaultPathList(false), + pOptCxxFlags(false), + pOptLibFlags(false), + pOptPrintCompilerByDefault(false), + pOptPrintErrors(false), + pOptPrintModulesDeps(false), + pOptDebug(false), + pOptCompiler(YUNI_LIBCONFIG_DEFAULT_COMPILER) + { + // Default module + pOptModules.push_back("core"); + } + + + int LibConfigProgram::execute(int argc, char** argv) + { + // Parse the command line + if (not parseCommandLine(argc, argv)) + return pExitStatus; + + // Find the root path + findRootPath(argv[0]); + + // Display information if asked + if (not displayInformations()) + return pExitStatus; + + // Expand name for each modules + expandModuleNames(); + + // Display information + displayInformationAboutYuniVersion(); + return pExitStatus; + } + + + bool LibConfigProgram::parseCommandLine(int argc, char** argv) + { + // The Command line parser + GetOpt::Parser opts; + + // Compiler + opts.addParagraph("\nTypical usage example :\n $ yuni-config -c gcc -m script --cxxflags\n\nCompiler settings:"); + opts.addFlag(pOptCxxFlags, ' ', "cxxflags", "Print the CXX flags (*)"); + opts.addFlag(pOptLibFlags, ' ', "libs", "Print the Libs flags (*)"); + opts.add(pOptCompiler, 'c', "compiler", "Set the target compiler (gcc,msvc,mingw,icc,...)"); + opts.addFlag(pOptPrintCompilerByDefault, ' ', "compiler-default", "Print the compiler used by default and exit"); + + // All required modules + opts.addParagraph("\nModules:"); + opts.add(pOptModules, 'm', "modules", "Add one or several requested modules (*)"); + opts.addFlag(pOptModuleList, ' ', "module-list", "Print all available modules of the selected version and exit (*)"); + opts.addFlag(pOptPrintModulesDeps, ' ', "module-deps", "Print all modules and the dependencies required and exit (*)"); + + // Prefix + opts.addParagraph("\nSearching paths:"); + opts.add(pOptPrefix, 'p', "prefix", "Add a prefix folder for searching available versions of libyuni"); + opts.addFlag(pOptNoDefaultPath, ' ', "no-default-path", "Do not use the default paths to find available versions of libyuni"); + opts.addFlag(pOptDefaultPathList, ' ', "default-path-list", "Print the default paths that would be used and exit (empty if 'no-default-path' is enabled)"); + + opts.addParagraph("\nVersions:"); + opts.addFlag(pOptList, 'l', "list", "Print the list of all versions of libyuni which have been found (with complete informations) and exit"); + opts.addFlag(pOptListOnlyVersions, ' ', "list-only-versions", "Print the list of all versions of libyuni which have been found and exit"); + + // Help + opts.addParagraph("\nHelp\n * : Option related to the selected version of libyuni"); + opts.addFlag(pOptPrintErrors, ' ', "verbose", "Print any error message"); + opts.addFlag(pOptDebug, ' ', "debug", "Print debug messages"); + opts.addFlag(pOptVersion, 'v', "version", "Print the version and exit"); + + if (!opts(argc, argv)) + { + pExitStatus = opts.errors() ? 1 /*error*/ : 0; + if (pOptPrintErrors || pOptDebug) + std::cout << "Error when parsing the command line\n"; + return false; + } + + if (pOptPrintCompilerByDefault) + { + std::cout << YUNI_LIBCONFIG_DEFAULT_COMPILER << "\n"; + return false; + } + + // Clean the prefix paths (make them absolute) + pVersionList.debug(pOptDebug); + cleanPrefixPaths(); + normalizeCompiler(); + + return true; + } + + + void LibConfigProgram::findRootPath(const char* a0) + { + # ifdef YUNI_YUNICONFIG_IN_TREE + (void) a0; + pRootPath = YUNI_YUNICONFIG_IN_TREE; + # else + + const String argv0 = a0; + if (IO::IsAbsolute(argv0)) + { + IO::ExtractFilePath(pRootPath, argv0); + } + else + { + IO::Directory::Current::Get(pRootPath); + pRootPath << IO::Separator; + String t; + IO::ExtractFilePath(t, argv0); + pRootPath += t; + pRootPath.removeTrailingSlash(); + } + # endif + + if (pOptDebug) + std::cout << "[yuni-config][debug] Root path : `" << pRootPath << '`' << std::endl; + } + + + void LibConfigProgram::cleanPrefixPaths() + { + if (!pOptPrefix.empty()) + { + // Current Directory + String pwd; + IO::Directory::Current::Get(pwd); + + String tmp; + const String::List::iterator end = pOptPrefix.end(); + for (String::List::iterator i = pOptPrefix.begin(); i != end; ++i) + { + IO::MakeAbsolute(tmp, *i, pwd); + *i = tmp; + } + } + } + + + void LibConfigProgram::initializeSystemPathList() + { + if (not pOptNoDefaultPath && pDefaultPathList.empty()) + { + # ifdef YUNI_OS_WINDOWS + pDefaultPathList.push_back("${PROGRAMFILES}\\libyuni"); + pDefaultPathList.push_back("${PROGRAMFILES}\\Dev\\libyuni"); + pDefaultPathList.push_back("C:\\Dev\\libyuni"); + # else + pDefaultPathList.push_back(String() << YUNI_INSTALL_PREFIX << "/include/" << YUNI_VERSIONED_INST_PATH); + pDefaultPathList.push_back(String() << YUNI_INSTALL_PREFIX << "/include"); + pDefaultPathList.push_back("/usr/include/yuni"); + pDefaultPathList.push_back("/usr/local/include/yuni"); + pDefaultPathList.push_back("/opt/yuni/include"); + # endif + # ifdef YUNI_OS_MAC + pDefaultPathList.push_back("/opt/local/include/yuni"); + # endif + } + } + + + void LibConfigProgram::normalizeCompiler() + { + if (pOptCompiler == "g++") + pOptCompiler = "gcc"; + if (pOptCompiler == "sun++") + pOptCompiler = "suncc"; + if (pOptCompiler == "i++") + pOptCompiler = "icc"; + + if (pOptDebug) + std::cout << "[yuni-config][debug] compiler : " << pOptCompiler << std::endl; + } + + + bool LibConfigProgram::displayInformations() + { + if (pOptVersion) + { + std::cout << YUNI_VERSION_LITE_STRING << "\n"; + return true; + } + if (pOptDefaultPathList) + { + initializeSystemPathList(); + for (String::List::const_iterator i = pDefaultPathList.begin(); i != pDefaultPathList.end(); ++i) + std::cout << *i << std::endl; + return true; + } + + pVersionList.compiler(pOptCompiler); + pVersionList.checkRootFolder(pRootPath); + pVersionList.findFromPrefixes(pOptPrefix); + if (not pOptNoDefaultPath) + { + initializeSystemPathList(); + pVersionList.findFromPrefixes(pDefaultPathList); + } + + // List + if (pOptListOnlyVersions) + { + pVersionList.print(); + return false; + } + if (pOptList) + { + pVersionList.printWithInfos(); + return false; + } + return true; + } + + + + void LibConfigProgram::expandModuleNames() + { + String item; + + // Lowercase + const String::List::iterator end = pOptModules.end(); + for (String::List::iterator i = pOptModules.begin(); i != end; ++i) + { + item = *i; + *i = item.toLower(); + } + + bool mustContinue; + do + { + mustContinue = false; + const String::List::iterator end = pOptModules.end(); + for (String::List::iterator i = pOptModules.begin(); i != end; ++i) + { + if (i->empty()) + { + // We have no interest in empty strings + pOptModules.erase(i); + mustContinue = true; + break; + } + if (String::npos != i->find_first_of(YUNI_LIBYUNI_CONFIG_SEPARATORS)) + { + // This item seems to be actually a list of several requested modules + // We will split the string to get the real list + item = *i; + pOptModules.erase(i); + item.split(pOptModules, YUNI_LIBYUNI_CONFIG_SEPARATORS, false, false, true); + mustContinue = true; + break; + } + if (i->first() == '+') + { + // The symbol `+` enables a module, but this is already a default behavior + item.assign(*i, 1, i->size() - 1); + *i = item; + continue; + } + if (i->first() == '-') + { + // The symbol `-` disables a module, so we have to remove all existing entries + mustContinue = true; + item.assign(*i, 1, i->size() - 1); + pOptModules.erase(i); + pOptModules.remove(item); + break; + } + } + } while (mustContinue); + } + + + void LibConfigProgram::displayInformationAboutYuniVersion() + { + LibConfig::VersionInfo::Settings* version = pVersionList.selected(); + if (version) + { + if (!displayInformationAboutYuniVersion(*version)) + return; + createArguments(*version); + } + else + { + pExitStatus = 1; + if (pOptPrintErrors) + std::cout << "Error: There is no available version of the yuni library\n"; + } + } + + + void LibConfigProgram::computeDependencies(LibConfig::VersionInfo::Settings& version) + { + String::List deps; + do + { + deps.clear(); + { + const String::List::const_iterator end = pOptModules.end(); + for (String::List::const_iterator i = pOptModules.begin(); i != end; ++i) + { + const String::List& modDeps = version.moduleSettings[*i].dependencies; + const String::List::const_iterator endJ = modDeps.end(); + for (String::List::const_iterator j = modDeps.begin(); j != endJ; ++j) + { + if (pOptModules.end() == std::find(pOptModules.begin(), pOptModules.end(), *j)) + deps.push_back(*j); + } + } + } + if (not deps.empty()) + { + // Merge results + const String::List::const_iterator end = deps.end(); + for (String::List::const_iterator i = deps.begin(); i != end; ++i) + { + if (pOptModules.end() == std::find(pOptModules.begin(), pOptModules.end(), *i)) + pOptModules.push_back(*i); + } + } + } + while (not deps.empty()); + } + + + void LibConfigProgram::printModulesDependencies() const + { + std::map deps; + { + const String::List::const_iterator end = pOptModules.end(); + for (String::List::const_iterator i = pOptModules.begin(); i != end; ++i) + deps[*i] = true; + } + + bool first = true; + const std::map::const_iterator end = deps.end(); + for (std::map::const_iterator i = deps.begin(); i != end; ++i) + { + if (!first) + std::cout << ' '; + std::cout << i->first; + first = false; + } + std::cout << "\n"; + } + + + + bool LibConfigProgram::checkForDependencies(LibConfig::VersionInfo::Settings& version) + { + const String::List::const_iterator end = pOptModules.end(); + for (String::List::const_iterator i = pOptModules.begin(); i != end; ++i) + { + if (not isCoreModule(*i) && version.modules.end() == std::find(version.modules.begin(), version.modules.end(), *i)) + { + pExitStatus = 3; + //if (pOptPrintErrors) + std::cerr << "Error: The module '" << *i << "' is required but not available\n"; + } + } + return (0 == pExitStatus); + } + + + bool LibConfigProgram::displayInformationAboutYuniVersion(LibConfig::VersionInfo::Settings& version) + { + // Getting the config file + String::List options; + if (not version.configFile(options, pOptPrintErrors) or not version.parserModulesOptions(options, pOptPrintErrors)) + { + pExitStatus = 1; + return false; + } + // Dependencies + computeDependencies(version); + if (pOptPrintModulesDeps) + { + printModulesDependencies(); + checkForDependencies(version); + return false; + } + if (!checkForDependencies(version)) + return false; + return true; + } + + + + + + static void PrintArgs(const LibConfig::VersionInfo::Settings::SettingsPerModule::OptionMap& args) + { + typedef LibConfig::VersionInfo::Settings::SettingsPerModule::OptionMap::const_iterator const_iterator; + + bool first = true; + const const_iterator end = args.end(); + for (const_iterator i = args.begin(); i != end; ++i) + { + if (!first) + std::cout << ' '; + first = false; + std::cout << i->first; + } + } + + + void LibConfigProgram::createArguments(LibConfig::VersionInfo::Settings& version) const + { + LibConfig::VersionInfo::Settings::SettingsPerModule::OptionMap args; + # if !defined(YUNI_OS_MSVC) && !defined(YUNI_OS_MAC) + bool hasCxxFlags = false; + # endif + + if (pOptCxxFlags) + { + const String::List::const_iterator end = pOptModules.end(); + for (String::List::const_iterator i = pOptModules.begin(); i != end; ++i) + { + LibConfig::VersionInfo::Settings::SettingsPerModule& modSettings = version.moduleSettings[*i]; + modSettings.merge(args, modSettings.cxxFlags); + modSettings.merge(args, modSettings.defines); + modSettings.merge(args, modSettings.includes); + } + if (!args.empty()) + { + # if !defined(YUNI_OS_MSVC) && !defined(YUNI_OS_MAC) + hasCxxFlags = true; + # endif + PrintArgs(args); + } + } + + if (pOptLibFlags) + { + args.clear(); + const String::List::const_iterator end = pOptModules.end(); + for (String::List::const_iterator i = pOptModules.begin(); i != end; ++i) + { + LibConfig::VersionInfo::Settings::SettingsPerModule& modSettings = version.moduleSettings[*i]; + modSettings.merge(args, modSettings.frameworks); + modSettings.merge(args, modSettings.libs); + modSettings.merge(args, modSettings.libIncludes); + } + if (!args.empty()) + { + # if !defined(YUNI_OS_MSVC) && !defined(YUNI_OS_MAC) + if (hasCxxFlags) + std::cout << ' '; + std::cout << "-Wl,--start-group "; + # endif + PrintArgs(args); + # if !defined(YUNI_OS_MSVC) && !defined(YUNI_OS_MAC) + std::cout << " -Wl,--end-group"; + # endif + } + } + std::cout << "\n"; + } + + + + +} // namespace Yuni diff --git a/src/ext/yuni/src/tools/yuni-config/program.h b/src/ext/yuni/src/tools/yuni-config/program.h new file mode 100644 index 0000000000..41b463fe17 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-config/program.h @@ -0,0 +1,114 @@ +/* +** This file is part of libyuni, a cross-platform C++ framework (http://libyuni.org). +** +** This Source Code Form is subject to the terms of the Mozilla Public License +** v.2.0. If a copy of the MPL was not distributed with this file, You can +** obtain one at http://mozilla.org/MPL/2.0/. +** +** github: https://github.com/libyuni/libyuni/ +** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror) +*/ +#pragma once +#ifndef YUNI_NO_THREAD_SAFE +# define YUNI_NO_THREAD_SAFE // disabling thread-safety +#endif +#include +#include +#include +#include "versions.h" + + + +namespace Yuni +{ + + class LibConfigProgram + { + public: + LibConfigProgram(); + + int execute(int argc, char** argv); + + bool debug() const {return pOptDebug;} + + private: + void findRootPath(const char* a0); + + bool parseCommandLine(int argc, char** argv); + + void cleanPrefixPaths(); + + void initializeSystemPathList(); + + void normalizeCompiler(); + + void expandModuleNames(); + + bool displayInformations(); + + void displayInformationAboutYuniVersion(); + + void computeDependencies(LibConfig::VersionInfo::Settings& version); + + void printModulesDependencies() const; + + bool isCoreModule(const String& name) const; + + bool checkForDependencies(LibConfig::VersionInfo::Settings& version); + + bool displayInformationAboutYuniVersion(LibConfig::VersionInfo::Settings& version); + + void createArguments(LibConfig::VersionInfo::Settings& version) const; + + + private: + //! Exit status + int pExitStatus; + //! The Root path + String pRootPath; + + //! Flag: Print the version and exit + bool pOptVersion; + //! Flag: Print all available versions of libyuni (with info) and exit + bool pOptList; + //! Flag: Print all available versions of libyuni and exit + bool pOptListOnlyVersions; + //! Flag: Do not use default paths + bool pOptNoDefaultPath; + //! Flag: Print all available modules of the selected versions + bool pOptModuleList; + //! Flag: Print all default paths and exit + bool pOptDefaultPathList; + //! Flag: Print cxx flags + bool pOptCxxFlags; + //! Flag: Print lib flags + bool pOptLibFlags; + //! Flag: Print the default compiler + bool pOptPrintCompilerByDefault; + //! Flag: Verbose + bool pOptPrintErrors; + //! Flag: Print all modules and exit + bool pOptPrintModulesDeps; + //! Flag: Debug + bool pOptDebug; + + //! List of required modules + String::List pOptModules; + //! List of given prefix + String::List pOptPrefix; + //! List of default paths + String::List pDefaultPathList; + //! The complete list of known libyuni versions + LibConfig::VersionInfo::List pVersionList; + //! The compiler to use + String pOptCompiler; + + }; // class Options + + + + + +} // namespace Yuni + +#include "program.hxx" diff --git a/src/ext/yuni/src/tools/yuni-config/program.hxx b/src/ext/yuni/src/tools/yuni-config/program.hxx new file mode 100644 index 0000000000..a57b9755f2 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-config/program.hxx @@ -0,0 +1,27 @@ +/* +** This file is part of libyuni, a cross-platform C++ framework (http://libyuni.org). +** +** This Source Code Form is subject to the terms of the Mozilla Public License +** v.2.0. If a copy of the MPL was not distributed with this file, You can +** obtain one at http://mozilla.org/MPL/2.0/. +** +** github: https://github.com/libyuni/libyuni/ +** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror) +*/ +#pragma once +#include "program.h" + + + +namespace Yuni +{ + + + inline bool LibConfigProgram::isCoreModule(const String& name) const + { + return (name == "core" or name == "gfx"); + } + + + +} // namespace Yuni diff --git a/src/ext/yuni/src/tools/yuni-config/versions.cpp b/src/ext/yuni/src/tools/yuni-config/versions.cpp new file mode 100644 index 0000000000..1af3e89009 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-config/versions.cpp @@ -0,0 +1,454 @@ +/* +** This file is part of libyuni, a cross-platform C++ framework (http://libyuni.org). +** +** This Source Code Form is subject to the terms of the Mozilla Public License +** v.2.0. If a copy of the MPL was not distributed with this file, You can +** obtain one at http://mozilla.org/MPL/2.0/. +** +** github: https://github.com/libyuni/libyuni/ +** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror) +*/ +#include "versions.h" +#include +#include +#include + + +#define SEP IO::Separator + + +namespace Yuni +{ +namespace LibConfig +{ +namespace VersionInfo +{ + + + template + static const String& QuotePath(const StringT& value) + { + static String s; + # ifndef YUNI_OS_WINDOWS + s = value; + s.replace(" ", "\\ "); + # else + s.clear(); + s << '"' << value << '"'; + # endif + return s; + } + + + + + + void List::checkRootFolder(const String& root) + { + String yuniMarker; + yuniMarker << root << SEP << "mark-for-yuni-sources"; + + if (IO::File::Exists(yuniMarker)) + { + if (pOptDebug) + std::cout << "[yuni-config][debug] found special yuni marker `" << yuniMarker << "`" << std::endl; + + # ifdef YUNI_OS_WINDOWS + loadFromPath(root + "\\..\\..\\.."); + # else + loadFromPath(root + "/../../.."); + # endif + return; + } + + # ifdef YUNI_OS_MSVC //Visual Studio + // For dealing with the paths like '{Debug,Release}/yuni-config.exe' + if (IO::File::Exists(String() << root << "\\..\\mark-for-yuni-sources")) + loadFromPath(root + "\\..\\..\\..\\.."); + # endif + } + + + void List::findFromPrefixes(const String::List& prefix) + { + if (not prefix.empty()) + { + const String::List::const_iterator end = prefix.end(); + for (String::List::const_iterator i = prefix.begin(); i != end; ++i) + loadFromPath(*i); + } + } + + + void List::loadFromPath(const String& folder) + { + String path; + IO::Canonicalize(path, folder); + if (pOptDebug) + std::cout << "[yuni-config][debug] :: reading `" << path << "`" << std::endl; + + VersionInfo::Settings info; + info.mapping = mappingStandard; + + String s; + s << path << SEP << "yuni.version"; + if (not IO::File::Exists(s)) + { + s.clear() << path << SEP << "include" << SEP << "yuni" << SEP << "yuni.version"; + if (not IO::File::Exists(s)) + { + info.mapping = mappingSVNSources; + s.clear() << path << SEP << "src" << SEP << "yuni" << SEP << "yuni.version"; + if (not IO::File::Exists(s)) + { + if (pOptDebug) + std::cout << "[yuni-config][debug] :: " << s << " not found" << std::endl; + return; + } + } + } + + IO::File::Stream file; + if (file.open(s)) + { + String key; + String value; + + Version version; + + // A buffer. The given capacity will be the maximum length for a single line + Clob buffer; + buffer.reserve(8000); + while (file.readline(buffer)) + { + buffer.extractKeyValue(key, value); + + if (key.empty() || key == "[") + continue; + if (key == "version.hi") + version.hi = value.to(); + if (key == "version.lo") + version.lo = value.to(); + if (key == "version.rev") + version.revision = value.to(); + if (key == "version.target") + info.compilationMode = value; + if (key == "modules.available") + value.split(info.modules, ";\"', \t", false); + if (key == "support.opengl") + info.supportOpenGL = value.to(); + if (key == "support.directx") + info.supportDirectX = value.to(); + if (key == "redirect") + loadFromPath(value); + if (key == "path.include") + { + if (not value.empty()) + info.includePath.push_back(value); + } + if (key == "path.lib") + { + if (not value.empty()) + info.libPath.push_back(value); + } + } + + if (not version.null() and not info.modules.empty()) + { + info.path = path; + info.compiler = pCompiler; + pList[version] = info; + + if (pOptDebug) + { + std::cout << "[yuni-config][debug] - found installation `" << path + << "` (" << version << ")" << std::endl; + } + } + else + { + std::cerr << "error: " << s << ": invalid file"; + if (version.null()) + std::cerr << " (invalid version)" << std::endl; + else if (info.modules.empty()) + std::cerr << " (no module)" << std::endl; + } + } + } + + + void List::compiler(const String& c) + { + pCompiler = c; + } + + + void List::print() + { + if (!pList.empty()) + { + const const_iterator end = pList.rend(); + for (const_iterator i = pList.rbegin(); i != end; ++i) + { + std::cout << i->first; + if (i->second.mapping == mappingSVNSources) + std::cout << " (svn-sources)"; + std::cout << "\n"; + } + } + } + + + void List::printWithInfos() + { + if (not pList.empty()) + { + const const_iterator end = pList.rend(); + for (const_iterator i = pList.rbegin(); i != end; ++i) + { + std::cout << i->first << " " << i->second.compilationMode; + if (i->second.mapping == mappingSVNSources) + std::cout << " (svn-sources)"; + std::cout << "\n"; + String path(i->second.path); + # ifdef YUNI_OS_WINDOWS + path.convertBackslashesIntoSlashes(); + # endif + std::cout << " path : " << path << "\n"; + + std::cout << " modules : [core]"; + const String::List::const_iterator mend = i->second.modules.end(); + for (String::List::const_iterator j = i->second.modules.begin(); j != mend; ++j) + std::cout << " " << *j; + std::cout << "\n"; + std::cout << " OpenGL : " << (i->second.supportOpenGL ? "Yes" : "No") << "\n"; + # ifdef YUNI_OS_WINDOWS + std::cout << " DirectX : " << (i->second.supportDirectX ? "Yes" : "No") << "\n"; + # endif + } + } + } + + + + VersionInfo::Settings* List::selected() + { + if (pList.empty()) + return nullptr; + InternalList::iterator i = pList.begin(); + return &i->second; + } + + + + bool Settings::configFile(String::List& options, bool displayError) const + { + if (compiler.empty()) + { + if (displayError) + std::cout << "Error: unknown compiler\n"; + return false; + } + String out; + out << this->path << SEP; + switch (mapping) + { + case mappingSVNSources: + out << "src" << SEP << "yuni" << SEP; + break; + case mappingStandard: + // Nothing to do + break; + } + out << "yuni.config." << this->compiler; + + if (not IO::File::Exists(out)) + { + if (displayError) + std::cout << "Error: impossible to open the config file '" << out << "'\n"; + return false; + } + + options.clear(); + IO::File::Stream file; + if (file.open(out)) + { + CString<8192> buffer; + while (file.readline(buffer)) + options.push_back(buffer); + } + else + { + if (displayError) + std::cout << "Error: Impossible to read '" << out << "'\n"; + return false; + } + return true; + } + + + + bool Settings::parserModulesOptions(String::List& options, bool displayError) + { + // Cleanup if needed + moduleSettings.clear(); + // End of the list + const String::List::const_iterator end = options.end(); + // Key + String key; + // Value + String value; + // Module name + String modName; + // Group + String group; + // normalized path + String norm; + + // The default compiler is gcc + CompilerCompliant compliant = gcc; + // Checking for Visual Studio + if (not compiler.empty() && compiler.at(0) == 'v' && compiler.at(1) == 's') + compliant = visualstudio; + + // For each entry in the ini file + for (String::List::const_iterator i = options.begin(); i != end; ++i) + { + i->extractKeyValue(key, value); + if (key.empty() || key.first() == '[') + continue; + value.trim(); + if (!value) + continue; + + // Reset + modName.clear(); + group.clear(); + + // Splitting + const String::Size p = key.find(':'); + if (p == String::npos) + continue; + group.assign(key, p); + modName.assign(key, key.size() - p - 1, p + 1); + if (not group or not modName) + continue; + + SettingsPerModule& s = moduleSettings[modName]; + + if (group == "path.include") + { + IO::Normalize(norm, value); + switch (compliant) + { + case gcc : + s.includes[String() << "-I" << QuotePath(norm)] = true; + break; + + case visualstudio : + s.includes[String() << "/I" << QuotePath(norm)] = true; + break; + } + continue; + } + + if (group == "lib,rawcommand") + { + s.libs[value] = true; + continue; + } + + if (group == "path.lib") + { + IO::Normalize(norm, value); + switch (compliant) + { + case gcc : + s.libIncludes[String() << "-L" << QuotePath(norm)] = true; + break; + case visualstudio : + s.libIncludes[String() << "/LIBPATH:" << QuotePath(norm)] = true; + break; + } + continue; + } + + if (group == "lib") + { + IO::Normalize(norm, value); + # ifdef YUNI_OS_MAC + // it may happen that cmake provides a framework for linking, which is wrong obvioulsy + CString<32,false> ext; + IO::ExtractExtension(ext, norm); + ext.toLower(); + if (ext != ".framework") + s.libs[String() << "-l" << QuotePath(norm)] = true; + else + { + // adding the parent directory + String frameworkpath; + norm += "/../"; + IO::Normalize(frameworkpath, norm); + s.libIncludes[String() << "-F" << QuotePath(frameworkpath)] = true; + } + # else + switch (compliant) + { + case gcc : s.libs[String() << "-l" << QuotePath(norm)] = true; break; + case visualstudio : s.libs[String() << QuotePath(norm)] = true; break; + } + # endif + continue; + } + + if (group == "cxxflag") + { + s.cxxFlags[value] = true; + continue; + } + + if (group == "define") + { + switch (compliant) + { + case gcc : s.defines[String() << "-D" << value] = true; break; + case visualstudio : s.defines[String() << "/D" << value] = true; break; + } + continue; + } + if (group == "dependency") + { + s.dependencies.push_back(value); + continue; + } + + if (group == "framework") + { + s.frameworks[String() << "-framework " << QuotePath(value)] = true; + continue; + } + + if (displayError) + std::cout << "Error: unknown key in the config file: '" << key << "'\n"; + return false; + } + return true; + } + + + + void Settings::SettingsPerModule::merge(OptionMap& out, const OptionMap& with) const + { + const OptionMap::const_iterator end = with.end(); + for (OptionMap::const_iterator i = with.begin(); i != end; ++i) + out[i->first] = true; + } + + + + + +} // namespace VersionInfo +} // namespace LibConfig +} // namespace Yuni + diff --git a/src/ext/yuni/src/tools/yuni-config/versions.h b/src/ext/yuni/src/tools/yuni-config/versions.h new file mode 100644 index 0000000000..5b2d218fc4 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-config/versions.h @@ -0,0 +1,163 @@ +/* +** This file is part of libyuni, a cross-platform C++ framework (http://libyuni.org). +** +** This Source Code Form is subject to the terms of the Mozilla Public License +** v.2.0. If a copy of the MPL was not distributed with this file, You can +** obtain one at http://mozilla.org/MPL/2.0/. +** +** github: https://github.com/libyuni/libyuni/ +** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror) +*/ +#pragma once +#ifndef YUNI_NO_THREAD_SAFE +# define YUNI_NO_THREAD_SAFE // disabling thread-safety +#endif +#include +#include +#include +#include + + +#ifdef YUNI_OS_WINDOWS +# if defined(YUNI_OS_MINGW) +# define YUNI_LIBCONFIG_DEFAULT_COMPILER "mingw" +# else +# define YUNI_LIBCONFIG_DEFAULT_COMPILER "msvc" +# endif +#else +# if defined(YUNI_OS_SUNOS) || defined(YUNI_OS_SOLARIS) +# define YUNI_LIBCONFIG_DEFAULT_COMPILER "suncc" +# else +# define YUNI_LIBCONFIG_DEFAULT_COMPILER "gcc" +# endif +#endif + + + +namespace Yuni +{ +namespace LibConfig +{ +namespace VersionInfo +{ + + enum CompilerCompliant + { + gcc, + visualstudio, + }; + + enum Mapping + { + mappingStandard, + mappingSVNSources, + }; + + + + struct Settings + { + public: + //! \name Constructor + //@{ + /*! + ** \brief Default Constructor + */ + Settings(); + //@} + + bool configFile(String::List& options, bool displayError) const; + + bool parserModulesOptions(String::List& options, bool displayError); + + + public: + String compiler; + Mapping mapping; + String path; + String compilationMode; + String::List modules; + bool supportOpenGL; + bool supportDirectX; + + String::List includePath; + String::List libPath; + + /*! + ** \brief Settings Per Module + */ + struct SettingsPerModule + { + public: + typedef std::map OptionMap; + + public: + void merge(OptionMap& out, const OptionMap& with) const; + + public: + //! Cxx flags for the module + OptionMap cxxFlags; + //! Includes to use for the module + OptionMap includes; + //! Frameworks needed by the module + OptionMap frameworks; + //! Libraries by the module + OptionMap libs; + //! Includes + OptionMap libIncludes; + //! Defines for the module + OptionMap defines; + //! Dependencies + String::List dependencies; + }; + std::map moduleSettings; + }; + + + + + + + class List + { + public: + typedef std::map InternalList; + typedef InternalList::reverse_iterator iterator; + typedef InternalList::const_reverse_iterator const_iterator; + + public: + List() {} + + const String& compiler() const {return pCompiler;} + void compiler(const String& c); + + void checkRootFolder(const String& root); + + void findFromPrefixes(const String::List& prefix); + + void print(); + + void printWithInfos(); + + VersionInfo::Settings* selected(); + + void debug(bool mode) {pOptDebug = mode;} + + private: + void loadFromPath(const String& folder); + + private: + String pCompiler; + InternalList pList; + bool pOptDebug; + }; + + + + + +} // namespace VersionInfo +} // namespace LibConfig +} // namespace Yuni + +#include "versions.hxx" diff --git a/src/ext/yuni/src/tools/yuni-config/versions.hxx b/src/ext/yuni/src/tools/yuni-config/versions.hxx new file mode 100644 index 0000000000..f052c09234 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-config/versions.hxx @@ -0,0 +1,32 @@ +/* +** This file is part of libyuni, a cross-platform C++ framework (http://libyuni.org). +** +** This Source Code Form is subject to the terms of the Mozilla Public License +** v.2.0. If a copy of the MPL was not distributed with this file, You can +** obtain one at http://mozilla.org/MPL/2.0/. +** +** github: https://github.com/libyuni/libyuni/ +** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror) +*/ +#pragma once +#include "versions.h" + + + +namespace Yuni +{ +namespace LibConfig +{ +namespace VersionInfo +{ + + inline Settings::Settings() + : supportOpenGL(false) + , supportDirectX(false) + {} + + + +} // namespace VersionInfo +} // namespace LibConfig +} // namespace Yuni diff --git a/src/ext/yuni/src/tools/yuni-docmake/CMakeLists.txt b/src/ext/yuni/src/tools/yuni-docmake/CMakeLists.txt new file mode 100644 index 0000000000..0a8277796d --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/CMakeLists.txt @@ -0,0 +1,131 @@ + +YMESSAGE("") +YMESSAGE_BOLD("edln-make") + +include("${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/common-settings.cmake") +include("${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules.cmake") + + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../..") +include_directories(tinyxml) + + +# Writing index-db.hxx +file(STRINGS make/index-db.sql INDEX_DB) +set(HXX_FILE "\n\n") +set(HXX_FILE "${HXX_FILE}namespace DocIndex\n") +set(HXX_FILE "${HXX_FILE}{\n") +set(HXX_FILE "${HXX_FILE}namespace // anonymous\n") +set(HXX_FILE "${HXX_FILE}{\n") +set(HXX_FILE "${HXX_FILE}\n\ttemplate\n") +set(HXX_FILE "${HXX_FILE}\tstatic void PrepareSQLScript(StringT& out)\n") +set(HXX_FILE "${HXX_FILE}\t{\n") +set(HXX_FILE "${HXX_FILE}\t\tout.clear()\n") +foreach(l ${INDEX_DB}) + string(REPLACE "\"" "\\\"" sline "${l}") + set(HXX_FILE "${HXX_FILE}\t\t\t<< \"${sline}\\n\"\n") +endforeach() +set(HXX_FILE "${HXX_FILE}\t\t\t;\n") +set(HXX_FILE "${HXX_FILE}\t}\n\n\n") +set(HXX_FILE "${HXX_FILE}} // anonymous namespace\n") +set(HXX_FILE "${HXX_FILE}} // namespace DocIndex\n\n") +file(WRITE make/index-db.hxx "${HXX_FILE}") + +# Writing webpage.hxx +file(STRINGS make/webpage.html WEBPAGE_HTML) +set(HXX_FILE "\n\n") +set(HXX_FILE "${HXX_FILE}namespace // anonymous\n") +set(HXX_FILE "${HXX_FILE}{\n") +set(HXX_FILE "${HXX_FILE}\n\ttemplate\n") +set(HXX_FILE "${HXX_FILE}\tstatic void PrepareWebPageHtml(StringT& out)\n") +set(HXX_FILE "${HXX_FILE}\t{\n") +set(HXX_FILE "${HXX_FILE}\t\tout.clear()\n") +foreach(l ${WEBPAGE_HTML}) + string(REPLACE "\"" "\\\"" sline "${l}") + set(HXX_FILE "${HXX_FILE}\t\t\t<< \"${sline}\\n\"\n") +endforeach() +set(HXX_FILE "${HXX_FILE}\t\t\t;\n") +set(HXX_FILE "${HXX_FILE}\t}\n\n\n\n") + +set(HXX_FILE "${HXX_FILE}} // anonymous namespace\n") +set(HXX_FILE "${HXX_FILE}\n\n") +file(WRITE make/webpage.hxx "${HXX_FILE}") + + + +add_library(edln-make-static-tinyxml STATIC + tinyxml/tinystr.cpp + tinyxml/tinystr.h + tinyxml/tinyxml.cpp + tinyxml/tinyxml.h + tinyxml/tinyxmlerror.cpp + tinyxml/tinyxmlparser.cpp + ) + + +add_executable(edln-make + sqlite/sqlite3.c + sqlite/sqlite3.h + sqlite/sqlite3ext.h + make/article.h + make/article.cpp + make/dictionary.h + make/dictionary.cpp + make/program.h + make/program.cpp + make/program-find-all-source-files.cpp + make/job.h + make/job.cpp + make/job-writer.h + make/job-writer.cpp + logs.h + logs.cpp + make/main.cpp + make/indexes.h + make/indexes.cpp + make/index-db.hxx +) + +target_link_libraries(edln-make + yuni-static-core + edln-make-static-tinyxml) + +if(UNIX AND NOT APPLE) + # The DL library is required on Unixes for using SQlite + target_link_libraries(edln-make dl) +endif() + + + +# --- +# --- dox2article +# --- + +# Build the in-tree version of yuni-config. +add_executable(edln-dox2article + dox2article/main.cpp + dox2article/compound.h + dox2article/compound.hxx + dox2article/compound.cpp + dox2article/options.h + dox2article/options.cpp + dox2article/read-index.h + dox2article/read-index.cpp + dox2article/job.h + dox2article/job.cpp + dox2article/job-compound-explorer.h + dox2article/job-compound-explorer.cpp + dox2article/job-compound-writer.h + dox2article/job-compound-writer.cpp + dox2article/indexes.h + dox2article/indexes.cpp + dox2article/toolbox.h + logs.h + logs.cpp +) + +target_link_libraries(edln-dox2article + yuni-static-core + edln-make-static-tinyxml) + + diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/compound.cpp b/src/ext/yuni/src/tools/yuni-docmake/dox2article/compound.cpp new file mode 100644 index 0000000000..d0b7e11d9f --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/compound.cpp @@ -0,0 +1,83 @@ + +#include "compound.h" + + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ + + Compound::Map allSymbolsByRefID; + + Compound::MapPerKind allSymbols = nullptr; + + Compound::MapPerKind allSymbolsByName = nullptr; + + + + + + + Compound::Compound() : + parent(nullptr) + {} + + + Compound::~Compound() + {} + + + void Compound::prepare() + { + name.trim("\t\n "); + htdocs.clear(); + brief.clear(); + description.clear(); + switch (kind) + { + case kdFunction: + break; + case kdTypedef: + break; + case kdClass: + htdocs << "class/" << name; + break; + case kdNamespace: + htdocs << "namespace/" << name; + break; + case kdVariable: + break; + case kdEnum: + break; + case kdFile: + break; + case kdFolder: + break; + case kdGroup: + break; + case kdFriend: + break; + case kdUnknown: + break; + case kdMax: + break; + } + + if (!htdocs && parent) + htdocs = parent->htdocs; + + htdocs.replace("::", "/"); + htdocs.toLower(); + } + + + + + +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/compound.h b/src/ext/yuni/src/tools/yuni-docmake/dox2article/compound.h new file mode 100644 index 0000000000..bbabe214a3 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/compound.h @@ -0,0 +1,169 @@ +#ifndef __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_COMPOUND_H__ +# define __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_COMPOUND_H__ + +# include +# include +# include +# include +# include + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ + + //! Any kind of compound + enum CompoundType + { + kdUnknown = 0, + kdNamespace, + kdClass, + kdTypedef, + kdEnum, + kdFunction, + kdVariable, + kdFile, + kdFolder, + kdGroup, + kdFriend, + kdMax + }; + + + class Parameter + { + public: + typedef SmartPtr Ptr; + typedef std::vector Vector; + + public: + String name; + String type; + }; + + + class Member + { + public: + typedef SmartPtr Ptr; + typedef std::vector Vector; + + public: + CompoundType kind; + String id; + String htmlID; + String name; + String brief; + String detailedDescription; + CString<16,false> visibility; + String type; + bool isStatic; + bool isConst; + bool isExplicit; + bool isInline; + Parameter::Vector parameters; + Parameter::Vector templates; + + }; // class Member + + + + class Section + { + public: + typedef SmartPtr
Ptr; + typedef std::deque Deque; + typedef std::vector Vector; + + public: + String caption; + CString<32,false> kind; + CString<16,false> visibility; + bool isStatic; + Member::Vector members; + + }; // class Section + + + + class Compound + { + public: + //! Reference ID + typedef CString<256,false> RefID; + //! The most suitable smart ptr + typedef SmartPtr Ptr; + //! Map + typedef std::map Map; + //! Deque + typedef std::deque Deque; + + //! All symbols, ordered by their type + typedef Map* MapPerKind; + + public: + template static CompoundType StringToKind(const StringT& str); + template static void AppendKindToString(StreamT& out, CompoundType kind); + + public: + Compound(); + ~Compound(); + + void prepare(); + + + public: + //! Kind of compound + CompoundType kind; + //! Reference ID + RefID refid; + //! + String name; + + String htdocs; + + //! Brief + String brief; + //! Detailed description + String description; + + Map members; + + //! The parent compound + Compound* parent; + //! All sections + Section::Vector sections; + + }; // class Compound + + + + + + + + + + + //! All symbols ordered by their reference id + extern Compound::Map allSymbolsByRefID; + + //! All symbols, ordered by their type and their reference id + extern Compound::MapPerKind allSymbols; + + //! All symbols, ordered by their type and their name + extern Compound::MapPerKind allSymbolsByName; + + + + +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + +# include "compound.hxx" + +#endif // __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_COMPOUND_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/compound.hxx b/src/ext/yuni/src/tools/yuni-docmake/dox2article/compound.hxx new file mode 100644 index 0000000000..c0877a1404 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/compound.hxx @@ -0,0 +1,71 @@ +#ifndef __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_COMPOUND_HXX__ +# define __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_COMPOUND_HXX__ + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ + + + template + CompoundType Compound::StringToKind(const StringT& str) + { + if (str == "function") + return kdFunction; + else if (str == "class") + return kdClass; + else if (str == "struct") + return kdClass; + else if (str == "variable") + return kdVariable; + else if (str == "typedef") + return kdTypedef; + else if (str == "enum") + return kdEnum; + else if (str == "file") + return kdFile; + else if (str == "namespace") + return kdNamespace; + else if (str == "dir") + return kdFolder; + else if (str == "group") + return kdGroup; + else if (str == "friend") + return kdFriend; + return kdUnknown; + } + + + + template + void Compound::AppendKindToString(StreamT& out, CompoundType kind) + { + switch (kind) + { + case kdClass: out << "class";break; + case kdNamespace: out << "namespace";break; + case kdFunction: out << "function";break; + case kdTypedef: out << "typedef";break; + case kdEnum: out << "enum";break; + case kdVariable: out << "variable";break; + case kdFile: out << "file";break; + case kdFolder: out << "folder";break; + case kdGroup: out << "group";break; + case kdFriend: out << "friend";break; + case kdUnknown:break; + case kdMax:break; + } + } + + + + + +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + +#endif // __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_COMPOUND_HXX__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/indexes.cpp b/src/ext/yuni/src/tools/yuni-docmake/dox2article/indexes.cpp new file mode 100644 index 0000000000..54c834587f --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/indexes.cpp @@ -0,0 +1,146 @@ + +#include "indexes.h" +#include +#include "../logs.h" +#include "options.h" +#include "compound.h" + + +#define SEP IO::Separator + + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ + + + void CreateIndex() + { + String filename; + filename << Options::target << SEP << "article.xml"; + IO::File::Stream file; + if (file.openRW(filename)) + { + file + << "Doxygen\n" + << "\n" + << "" + << "\n\n" + << "

API Reference

\n" + << "

Beware: THIS DOCUMENTATION IS INCOMPLETE AND WE'RE CURRENTLY WORKING ON IT

\n" + << "\n" + ; + } + } + + + + + void CreateNamespaceIndex() + { + String filename; + filename << Options::target << SEP << "namespace"; + if (!IO::Directory::Create(filename)) + return; + filename << SEP << "article.xml"; + IO::File::Stream file; + if (file.openRW(filename)) + { + file << "Namespaces\n\n"; + file << "

All namespaces

\n"; + file << "

This is a list of all namespaces in Yuni.

\n"; + file << "\n"; + file << ""; + unsigned int total = 0; + + Compound::Map::iterator end = allSymbolsByName[kdNamespace].end(); + for (Compound::Map::iterator i = allSymbolsByName[kdNamespace].begin(); i != end; ++i) + { + const Compound::Ptr compoundptr = i->second; + const Compound& compound = *compoundptr; + if (compound.name.find_first_of("<@") != String::npos) + continue; + + file << "\n"; + ++total; + } + + file << "
NameDescription
\n"; + file << "" << compound.name << "\n"; + file << "
\n"; + switch (total) + { + case 0: file << "

(no namespace)

";break; + case 1: file << "

(total: 1 namespace)

";break; + default: file << "

(total: " << total << " namespaces)

";break; + } + file << "\n"; + + logs.info() << "index: " << total << " namespaces"; + } + } + + + + + + void CreateClassIndex() + { + String filename; + filename << Options::target << SEP << "class"; + if (!IO::Directory::Create(filename)) + return; + filename << SEP << "article.xml"; + IO::File::Stream file; + if (file.openRW(filename)) + { + file << "Classes\n\n"; + file << "

All classes

\n"; + file << "

This is a list of all classes in Yuni.

\n"; + file << "\n"; + file << ""; + unsigned int total = 0; + + Compound::Map::iterator end = allSymbolsByName[kdClass].end(); + for (Compound::Map::iterator i = allSymbolsByName[kdClass].begin(); i != end; ++i) + { + const Compound::Ptr compoundptr = i->second; + const Compound& compound = *compoundptr; + if (compound.name.find_first_of("<@") != String::npos) + continue; + + file << "\n"; + ++total; + } + + file << "
NameDescription
\n"; + file << "" << compound.name << "\n"; + file << "
\n"; + switch (total) + { + case 0: file << "

(no class)

";break; + case 1: file << "

(total: 1 class)

";break; + default: file << "

(total: " << total << " classes)

";break; + } + file << "\n"; + + logs.info() << "index: " << total << " classes"; + } + } + + + + + + +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/indexes.h b/src/ext/yuni/src/tools/yuni-docmake/dox2article/indexes.h new file mode 100644 index 0000000000..ab4468ffa8 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/indexes.h @@ -0,0 +1,26 @@ +#ifndef __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_INDEXES_H__ +# define __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_INDEXES_H__ + +# include + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ + + void CreateIndex(); + + void CreateNamespaceIndex(); + + void CreateClassIndex(); + + + +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + +#endif // __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_INDEXES_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-explorer.cpp b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-explorer.cpp new file mode 100644 index 0000000000..b9eeb6e610 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-explorer.cpp @@ -0,0 +1,707 @@ + +#include "job-compound-explorer.h" +#include "../logs.h" +#include +#include "../tinyxml/tinyxml.h" +#include "options.h" +#include "toolbox.h" + +#define SEP Yuni::IO::Separator + + + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ +namespace Job +{ + + + namespace // anonymous + { + + + class XMLCompoundVisitor : public TiXmlVisitor + { + public: + //! \name Constructor + //@{ + /*! + ** \brief Constructor + */ + XMLCompoundVisitor(Compound& compound, TiXmlDocument& document); + //! Destructor + virtual ~XMLCompoundVisitor(); + //@} + + virtual bool VisitEnter(const TiXmlDocument& /*doc*/ ); + + virtual bool VisitExit(const TiXmlDocument& /*doc*/); + + virtual bool VisitEnter(const TiXmlElement& element, const TiXmlAttribute* attr); + + virtual bool VisitExit(const TiXmlElement& element); + + virtual bool Visit(const TiXmlDeclaration& /*declaration*/); + virtual bool Visit(const TiXmlText& /*text*/); + virtual bool Visit(const TiXmlComment& /*comment*/); + virtual bool Visit(const TiXmlUnknown& /*unknown*/); + + Member::Ptr currentMember(); + + void startNewParagraph(String* text); + + private: + Compound& pCompound; + //! + bool pInCompoundDef; + bool pInSectionHeader; + bool pInMemberDef; + bool pInMemberDefName; + bool pInMemberDefinition; + bool pInMemberParam; + bool pInMemberBrief; + bool pInMemberDetailedDescription; + bool pInMemberTemplates; + //! XML document + TiXmlDocument& pDocument; + //! + Section::Deque pSections; + + //! \name Paragraph + //@{ + //! + String* pCurrentParagraph; + //! Temporary string + String pS; + //! Codeline + unsigned int pParagraphCodelineCount; + //@} + + }; // class XMLCompoundVisitor + + + + + + XMLCompoundVisitor::XMLCompoundVisitor(Compound& compound, TiXmlDocument& document) : + pCompound(compound), + pInCompoundDef(false), + pInSectionHeader(false), + pInMemberDef(false), + pInMemberDefName(false), + pInMemberParam(false), + pInMemberBrief(false), + pInMemberDetailedDescription(false), + pInMemberTemplates(false), + pDocument(document), + pCurrentParagraph(nullptr) + { + } + + + XMLCompoundVisitor::~XMLCompoundVisitor() + { + } + + + Member::Ptr XMLCompoundVisitor::currentMember() + { + if (!pSections.empty()) + { + Section::Ptr section = pSections.front(); + if (!(!section) && !section->members.empty()) + return section->members[section->members.size() - 1]; + } + return nullptr; + } + + + bool XMLCompoundVisitor::VisitEnter(const TiXmlDocument& /*doc*/ ) + { + return true; + } + + + bool XMLCompoundVisitor::VisitExit(const TiXmlDocument& /*doc*/) + { + return true; + } + + + bool XMLCompoundVisitor::VisitEnter(const TiXmlElement& element, const TiXmlAttribute* /*attr*/) + { + const TIXML_STRING& strname = element.ValueTStr(); + + if (strname == "memberdef") + { + if (pSections.empty()) + return true; + + Section::Ptr section = pSections.front(); + Member* member = new Member(); + member->id = element.Attribute("id"); + IO::ExtractFileName(member->htmlID, member->id); + member->kind = Compound::StringToKind(AnyString(element.Attribute("kind"))); + if (member->kind == kdUnknown) + logs.warning() << "unknown type: " << AnyString(element.Attribute("kind")); + member->visibility = element.Attribute("prot"); + member->isStatic = AnyString(element.Attribute("static")).to(); + member->isConst = AnyString(element.Attribute("const")).to(); + member->isExplicit = AnyString(element.Attribute("explicit")).to(); + member->isInline = AnyString(element.Attribute("inline")).to(); + + section->members.push_back(member); + pInMemberDef = true; + pInMemberDefName = false; + pInMemberDefinition = false; + pInMemberParam = false; + pInMemberBrief = false; + pInMemberDetailedDescription = false; + pCurrentParagraph = nullptr; + return true; + } + if (strname == "name") + { + if (pInMemberDef) + pInMemberDefName = true; + return true; + } + if (strname == "declname") + { + if (pInMemberDef && pInMemberParam) + pInMemberDefName = true; + return true; + } + if (strname == "templateparamlist") + { + if (pInMemberDef) + pInMemberTemplates = true; + } + if (strname == "type") + { + if (pInMemberDef) + pInMemberDefinition = true; + return true; + } + if (strname == "briefdescription") + { + if (pInMemberDef) + { + Member::Ptr member = currentMember(); + startNewParagraph((!member) ? nullptr : &(member->brief)); + pInMemberBrief = true; + } + else + startNewParagraph(&(pCompound.brief)); + return true; + } + if (strname == "detaileddescription") + { + if (pInMemberDef) + { + Member::Ptr member = currentMember(); + startNewParagraph((!member) ? nullptr : &(member->detailedDescription)); + pInMemberDetailedDescription = true; + } + else + startNewParagraph(&(pCompound.description)); + return true; + } + if (strname == "parameterlist") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += "
Parameters :
    "; + return true; + } + if (strname == "parameteritem") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += "
  • "; + } + if (strname == "parameternamelist") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += ""; + } + if (strname == "programlisting") + { + if (pCurrentParagraph) + { + if (!pParagraphCodelineCount) + (*pCurrentParagraph) += ""; + } + return true; + } + if (strname == "computeroutput") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += ""; + return true; + } + if (strname == "itemizedlist") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += "
      "; + return true; + } + if (strname == "listitem") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += "
    • "; + return true; + } + if (strname == "simplesect") + { + if (pCurrentParagraph) + { + AnyString kind = element.Attribute("kind"); + if (kind == "return") + (*pCurrentParagraph) += "
      return "; + else if (kind == "warning") + (*pCurrentParagraph) += "
      warning : "; + else if (kind == "see") + (*pCurrentParagraph) += "
      see : "; + else if (kind == "note") + (*pCurrentParagraph) += "
      note : "; + else if (kind == "remark") + (*pCurrentParagraph) += "
      remark : "; + else if (kind == "attention") + (*pCurrentParagraph) += "
      attention : "; + else + { + logs.warning() << "unmanaged simplesect '" << kind; + (*pCurrentParagraph) += "
      "; + } + } + return true; + } + + if (strname == "param") + { + if (pInMemberDef && !pCurrentParagraph) + { + Member::Ptr member = currentMember(); + if (!(!member)) + { + if (pInMemberTemplates) + member->templates.push_back(new Parameter()); + else + member->parameters.push_back(new Parameter()); + pInMemberParam = true; + } + } + return true; + } + if (strname == "sectiondef") + { + const AnyString stat = element.Attribute("static"); + Section* section = new Section(); + const AnyString kind = element.Attribute("kind"); + section->kind = kind; + section->visibility = element.Attribute("prot"); + section->isStatic = AnyString(element.Attribute("static")).to(); + pSections.push_front(section); + pInSectionHeader = false; + pInMemberDef = false; + pInMemberDefName = false; + pInMemberDefinition = false; + pInMemberBrief = false; + pInMemberDetailedDescription = false; + pCurrentParagraph = nullptr; + return true; + } + if (strname == "header") + { + if (pSections.empty()) + return false; + pInSectionHeader = true; + return true; + } + if (strname == "compounddef") + { + const AnyString id = element.Attribute("id"); + if (pCompound.refid == id) + { + pInCompoundDef = true; + pInMemberDef = false; + pInMemberDefName = false; + pInMemberDefinition = false; + pInMemberBrief = false; + pInMemberDetailedDescription = false; + pCurrentParagraph = nullptr; + } + return true; + } + return true; + } + + + bool XMLCompoundVisitor::Visit(const TiXmlText& text) + { + if (pInMemberDef && pInMemberDefName) + { + if (!pSections.empty()) + { + Section::Ptr section = pSections.front(); + if (!(!section) && !section->members.empty()) + { + Member::Ptr member = section->members[section->members.size() - 1]; + const TIXML_STRING& name = text.ValueTStr(); + if (pInMemberParam) + { + if (pInMemberTemplates) + { + if (!member->templates.empty()) + { + Parameter::Ptr& param = member->templates[member->templates.size() - 1]; + if (not param->name.empty()) + param->name += ' '; + param->name.append(name.c_str(), (unsigned int)name.size()); + } + } + else + { + if (!member->parameters.empty()) + { + Parameter::Ptr& param = member->parameters[member->parameters.size() - 1]; + if (not param->name.empty()) + param->name += ' '; + param->name.append(name.c_str(), (unsigned int)name.size()); + } + } + } + else + member->name.append(name.c_str(), (unsigned int)name.size()); + } + } + return true; + } + if (pInMemberDef && pInMemberDefinition) + { + if (!pSections.empty()) + { + Section::Ptr section = pSections.front(); + if (!(!section) && !section->members.empty()) + { + Member::Ptr member = section->members[section->members.size() - 1]; + const TIXML_STRING& name = text.ValueTStr(); + + if (pInMemberParam) + { + if (pInMemberTemplates) + { + if (!member->templates.empty()) + { + Parameter::Ptr& param = member->templates[member->templates.size() - 1]; + if (not param->type.empty()) + param->type += ' '; + param->type.append(name.c_str(), (unsigned int)name.size()); + } + } + else + { + if (!member->parameters.empty()) + { + Parameter::Ptr& param = member->parameters[member->parameters.size() - 1]; + if (not param->type.empty()) + param->type += ' '; + param->type.append(name.c_str(), (unsigned int)name.size()); + } + } + } + else + { + if (not member->type.empty()) + member->type += ' '; + member->type.append(name.c_str(), (unsigned int)name.size()); + } + } + } + return true; + } + if (pInSectionHeader) + { + Section::Ptr section = pSections.front(); + if (!(!section)) + { + const TIXML_STRING& name = text.ValueTStr(); + section->caption.append(name.c_str(), (unsigned int)name.size()); + } + return true; + } + + if (pCurrentParagraph) + { + const TIXML_STRING& name = text.ValueTStr(); + if (not (*pCurrentParagraph).empty()) + (*pCurrentParagraph) += ' '; + HtmlEntities(pS, AnyString(name.c_str(), (unsigned int)name.size())); + (*pCurrentParagraph) += pS; + return true; + } + + return true; + } + + + bool XMLCompoundVisitor::Visit(const TiXmlComment&) + { + return true; + } + + + bool XMLCompoundVisitor::Visit(const TiXmlDeclaration&) + { + return true; + } + + + bool XMLCompoundVisitor::Visit(const TiXmlUnknown&) + { + return true; + } + + + + bool XMLCompoundVisitor::VisitExit(const TiXmlElement& element) + { + const TIXML_STRING& strname = element.ValueTStr(); + + if (strname == "memberdef") + { + pInMemberDef = false; + return true; + } + if (strname == "name") + { + if (pInMemberDef) + pInMemberDefName = false; + } + if (strname == "declname") + { + if (pInMemberDef && pInMemberParam) + pInMemberDefName = false; + + } + if (strname == "type") + { + if (pInMemberDef) + pInMemberDefinition = false; + } + if (strname == "briefdescription") + { + if (pCurrentParagraph) + (*pCurrentParagraph).trim(); + pInMemberBrief = false; + pCurrentParagraph = nullptr; + } + if (strname == "detaileddescription") + { + if (pCurrentParagraph) + (*pCurrentParagraph).trim(); + pInMemberDetailedDescription = false; + pCurrentParagraph = nullptr; + } + if (strname == "parameterlist") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += "
    "; + } + if (strname == "parameteritem") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += "
  • "; + } + if (strname == "parameternamelist") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += ""; + } + if (strname == "programlisting") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += "\n"; + return true; + } + if (strname == "computeroutput") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += ""; + return true; + } + if (strname == "codeline") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += '\n'; + return true; + } + if (strname == "itemizedlist") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += "
"; + return true; + } + if (strname == "para") + { + if (pCurrentParagraph && !(*pCurrentParagraph).endsWith("
")) + (*pCurrentParagraph) += "
"; + return true; + } + + if (strname == "listitem") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += ""; + return true; + } + + if (strname == "sp") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += ' '; + return true; + } + if (strname == "simplesect") + { + if (pCurrentParagraph) + (*pCurrentParagraph) += ""; + return true; + } + + if (strname == "templateparamlist") + { + if (pInMemberDef) + pInMemberTemplates = false; + return true; + } + if (strname == "param") + { + if (pInMemberDef) + pInMemberParam = false; + return true; + } + if (strname == "sectiondef") + { + pCompound.sections.push_back(pSections.front()); + pSections.pop_front(); + return true; + } + if (strname == "header") + { + pInSectionHeader = false; + return true; + } + if (strname == "compounddef") + { + pInCompoundDef = false; + return true; + } + return true; + } + + + } // anonymous namespace + + + + + + void CompoundExplorer::Dispatch() + { + typedef Compound::Map::iterator iterator; + + logs.info() << "reading class/namespace members"; + + // Namespaces + { + const iterator end = allSymbols[kdNamespace].end(); + for (iterator i = allSymbols[kdNamespace].begin(); i != end; ++i) + { + Compound::Ptr& compound = i->second; + queueService += new CompoundExplorer(compound); + } + } + // Classes + { + const iterator end = allSymbols[kdClass].end(); + for (iterator i = allSymbols[kdClass].begin(); i != end; ++i) + { + Compound::Ptr& compound = i->second; + queueService += new CompoundExplorer(compound); + } + } + + queueService.wait(); + } + + + + + CompoundExplorer::CompoundExplorer(const Compound::Ptr& compound) : + pCompound(compound) + { + } + + + CompoundExplorer::~CompoundExplorer() + { + } + + + void CompoundExplorer::onExecute() + { + if (!pCompound) + return; + + Compound& compound = *pCompound; + if (!compound.refid) + return; + + TiXmlDocument doc; + + // Parsing the XML + { + String filename; + filename << Options::doxygenXMLIndex << SEP << compound.refid << ".xml"; + + if (!doc.LoadFile(filename.c_str(), TIXML_ENCODING_UTF8)) + { + logs.error() << "impossible to read the compound index: " << filename; + return; + } + } + + // Analyze the XML document + { + XMLCompoundVisitor visitor(compound, doc); + if (!doc.Accept(&visitor)) + return; + } + } + + + void XMLCompoundVisitor::startNewParagraph(String* text) + { + if (text) + { + (*text).clear(); + pCurrentParagraph = text; + pParagraphCodelineCount = 0; + } + else + pCurrentParagraph = nullptr; + } + + + + +} // namespace Job +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-explorer.h b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-explorer.h new file mode 100644 index 0000000000..a06a837487 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-explorer.h @@ -0,0 +1,60 @@ +#ifndef __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_JOB_COMPOUND_EXPLORER_H__ +# define __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_JOB_COMPOUND_EXPLORER_H__ + +# include +# include "job.h" +# include "compound.h" + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ +namespace Job +{ + + + class CompoundExplorer : public Dox2Article::Job::IJob + { + public: + /*! + ** \brief Explorer all known symbols + */ + static void Dispatch(); + + public: + //! \name Constructor & Destructor + //@{ + /*! + ** \brief Default constructor + ** + ** \param compound The compound to analyze + */ + CompoundExplorer(const Compound::Ptr& compound); + //! Destructor + virtual ~CompoundExplorer(); + //@} + + + protected: + virtual void onExecute(); + + private: + //! Compound to analyze + Compound::Ptr pCompound; + + }; // class CompoundExplorer + + + + + + +} // namespace Job +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + +#endif // __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_JOB_COMPOUND_EXPLORER_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-writer.cpp b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-writer.cpp new file mode 100644 index 0000000000..258582e091 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-writer.cpp @@ -0,0 +1,574 @@ + +#include "job-compound-writer.h" +#include +#include +#include "../logs.h" +#include "options.h" +#include "toolbox.h" + + +#define SEP IO::Separator + + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ +namespace Job +{ + + namespace // anonymous + { + + static Atomic::Int<> GenerationNumericID; + + } // anonymous namespace + + + + void CompoundWriter::Dispatch() + { + // Write articles + { + uint count = (uint) allSymbolsByRefID.size(); + switch (count) + { + case 0: logs.info() << "No article";break; + case 1: logs.info() << "writing 1 article";break; + default: logs.info() << "writing " << count << " articles";break; + } + } + { + Compound::Map::iterator end = allSymbolsByRefID.end(); + for (Compound::Map::iterator i = allSymbolsByRefID.begin(); i != end; ++i) + { + Compound::Ptr& compound = i->second; + Edalene::Dox2Article::Job::queueService += new CompoundWriter(compound); + } + } + + queueService.wait(); + } + + + + + + CompoundWriter::CompoundWriter(Compound::Ptr& compound) : + pCompound(compound) + { + } + + + CompoundWriter::~CompoundWriter() + { + } + + + + void CompoundWriter::onExecute() + { + if (!pCompound->name || pCompound->name.contains('@')) + return; + + switch (pCompound->kind) + { + case kdFunction: break; + case kdTypedef: break; + case kdClass: buildClass();break; + case kdNamespace: buildNamespace();break; + case kdVariable: break; + case kdEnum: break; + case kdFile: break; + case kdFolder: break; + case kdGroup: break; + case kdFriend: break; + case kdUnknown: break; + case kdMax: break; + } + } + + + void CompoundWriter::buildClass() + { + if (pCompound->name.find_first_of("<@") != String::npos) + return; + + String filename; + filename << Options::target << SEP << pCompound->htdocs; + if (!IO::Directory::Create(filename)) + return; + filename << SEP << "article.xml"; + + + IO::File::Stream file; + if (file.openRW(filename)) + { + // Getting the name + const String& name = pCompound->name; + + fileOut.clear(); + + String pageTitle; + { + String tmp; + String::Size offset = name.find_last_of(":\\/"); + if (offset < name.size() && offset + 1 < name.size()) + pageTitle.append(name.c_str() + offset + 1, name.size() - (offset + 1)); + else + pageTitle << name; + PrepareTitle(tmp, pageTitle); + fileOut << "" << tmp << "\n"; + fileOut << "\n"; + fileOut << "\n"; + fileOut << "\n"; + fileOut << "\n"; + fileOut << "\n\n\n"; + + fileOut << "

"; + if (not pCompound->brief.empty()) + PrepareTitle(tmp, pCompound->brief); + else + PrepareTitle(tmp, pageTitle); + // in some cases, a final point is in the string, and it is not especially beautiful + fileOut << tmp; + fileOut << "

\n"; + } + + bool isAbstract = (pageTitle.first() == 'I'); + + OrderedSection sectionmap; + buildSectionMapping(sectionmap, isAbstract); + + if (!sectionmap.empty()) + { + // resetting temporary stream outputs + out.clear(); + for (uint i = 0; i != 2; ++i) + { + for (uint j = 0; j != (uint) kdMax; ++j) + outC[i][j].clear(); + } + + // Starting the table + out << "\n"; + + // iterating through all sections found + OrderedSection::const_iterator end = sectionmap.end(); + for (OrderedSection::const_iterator i = sectionmap.begin(); i != end; ++i) + { + // Append all sections found + Section::Vector::const_iterator send = i->second.end(); + for (Section::Vector::const_iterator j = i->second.begin(); j != send; ++j) + appendClassSection(/*section*/ *(*j), isAbstract); + } + + // End of table + out << "
\n\n\n"; + } + + // Writing the begining of the article (title...) + file << fileOut; + + // Preparing indexes from temporary buffers + fileOut.clear(); + for (uint i = 1; i < 2; --i) + { + for (uint j = 0; j != (uint) kdMax; ++j) + { + if (not outC[i][j].empty()) + appendClassIndex(fileOut, (i != 0) /*isPublic*/, (CompoundType) j, outC[i][j]); + } + } + + if (not fileOut.empty()) + fileOut << "

Detailed Description

"; + + if (not pCompound->description.empty()) + { + fileOut << "
" << pCompound->description + << "
\n"; + } + + // Writing indexes + file << fileOut; + // Writing detailed description + file << out; + } + } + + + + void CompoundWriter::buildNamespace() + { + if (pCompound->name.find_first_of("<@") != String::npos) + return; + + String filename; + filename << Options::target << SEP << pCompound->htdocs; + if (!IO::Directory::Create(filename)) + return; + filename << SEP << "article.xml"; + + IO::File::Stream file; + if (file.openRW(filename)) + { + // Getting the name + const String& name = pCompound->name; + + file << ""; + String::Size offset = name.find_last_of(":\\/"); + if (offset < name.size() && offset + 1 < name.size()) + file.write(name.c_str() + offset + 1, name.size() - (offset + 1)); + else + file << name; + file << "\n"; + file << "\n"; + file << "\n"; + file << "\n"; + file << "\n\n"; + } + } + + + + void CompoundWriter::buildSectionMapping(OrderedSection& map, bool isAbstract) + { + // just in case + map.clear(); + // Section ID + CString<48,false> id; + + uint count = (uint) pCompound->sections.size(); + for (uint i = 0; i != count; ++i) + { + const Section::Ptr& sectionptr = pCompound->sections[i]; + if (!sectionptr) // just in case + continue; + const Section& section = *sectionptr; + + if (section.kind.startsWith("public-")) + id = "0-public"; + else if (section.kind.startsWith("protected-")) + { + // Protected and private data should not be displayed when the class is not inherited + if (!isAbstract) + continue; + id = "1-protected"; + } + else if (section.kind.startsWith("private-")) + { + // Skipping all private members + continue; + } + else + id = "0-public"; + + // We will accept the fact that the first item is enough + // to determine the section order + // + // In the same time, this loop will filter empty sections + // (push_back will never be called) which may occur in some + // rare cases + uint memcount = (uint) section.members.size(); + for (uint j = 0; j != memcount; ++j) + { + const Member::Ptr& memberptr = section.members[j]; + const Member& member = *memberptr; + + // useless stuff - junk + if (member.name == "YUNI_STATIC_ASSERT") + continue; + if (member.kind == kdFriend) + continue; + + if (member.kind == kdFunction) + id += "-1-method"; + else if (member.kind == kdVariable) + id += "-2-vars"; + else + id += "-0-typedef-enum"; + + map[id].push_back(sectionptr); + break; + } + } + } + + + void CompoundWriter::prepareClassSubtitle(const Section& section) + { + subtitle = ""; + + if (not section.caption.empty()) + { + HtmlEntities(sectionName, section.caption); + subtitle << "

" << sectionName << " " << visibility << "

\n"; + } + else + { + sectionName.clear(); + subtitle << "

" << visibility << " " << visibility << "

\n"; + } + subtitle << "\n"; + } + + + + void CompoundWriter::appendClassSection(const Section& section, bool isAbstract) + { + umlSymbol = '+'; + visibility.clear(); + bool isPublic = true; + + if (section.kind.startsWith("public-")) + visibility = "Public"; + else if (section.kind.startsWith("protected-")) + { + // Protected and private data should not be displayed when the class is not inherited + if (!isAbstract) + return; + visibility = "Protected"; + umlSymbol = '#'; + isPublic = false; + } + else if (section.kind.startsWith("private-")) + { + // Skipping all private members + return; + //visibility = "Private"; + //umlSymbol = '-'; + } + else + visibility = "Public"; + + // class subtitle + prepareClassSubtitle(section); + + bool subtitleAlreadyWritten = false; + bool firstIndexMember = true; + uint memcount = (uint) section.members.size(); + for (uint j = 0; j != memcount; ++j) + { + const Member::Ptr& memberptr = section.members[j]; + const Member& member = *memberptr; + if (member.name == "YUNI_STATIC_ASSERT") + continue; + if (member.kind == kdFriend) + continue; + + if (!subtitleAlreadyWritten) + { + out << subtitle; + subtitleAlreadyWritten = true; + } + + if (firstIndexMember && (member.kind == kdFunction || member.kind == kdTypedef)) + { + firstIndexMember = false; + Clob& outIx = outC[isPublic][member.kind]; + if (outIx.empty()) + { + outIx<< ""; + outIx << "\n"; + } + + out << ""; + + id.clear() << member.name << '_' << (++GenerationNumericID) << DateTime::Now(); + id.replace('-', '_'); // prevent against int overflow + toggle.clear() << "toggleVisibility('" << id << "')"; + + HtmlEntities(name, member.name); + HtmlEntities(type, member.type); + ArrangeTypename(type); + + switch (member.kind) + { + case kdFunction: out << ""; + + out << ""; + out << ""; + out << "\n"; + + } // each member + } + + + + void CompoundWriter::appendClassFunction(const Member& member, bool isPublic) + { + Clob& outIx = outC[isPublic][kdFunction]; + if (outIx.empty()) + outIx << "

"; + } + else + outIx << "


"; + outIx << sectionName << "

";break; + case kdTypedef: out << "";break; + case kdVariable: out << "";break; + case kdEnum: out << "";break; + default: out << "";break; + } + out << "
"; + + if (not member.brief.empty()) + out << "" << member.brief << "
\n"; + out << ""; + + switch (member.kind) + { + case kdFunction: + appendClassFunction(member, isPublic); + break; + case kdTypedef: + appendClassTypedef(member, isPublic); + break; + case kdVariable: + appendClassVariable(); + break; + default: + out << "(unmanaged tag: " << (uint) member.kind << ")"; + break; + } + + out << "\n"; + + out << "
\n"; + out << "
\n
"; + + if (not member.detailedDescription.empty()) + out << member.detailedDescription; + + out << "\n
\n"; + out << "
"; + outIx << "\n"; + } + + + + void CompoundWriter::appendClassTypedef(const Member& member, bool isPublic) + { + Clob& outIx = outC[isPublic][kdTypedef]; + if (outIx.empty()) + outIx << "
"; + if (member.isStatic) + outIx << "static "; + outIx << type << ' '; + outIx << ""; + + if (!member.templates.empty()) + { + out << "
"; + out << "template<"; + for (uint p = 0; p != member.templates.size(); ++p) + { + if (p) + out << ", "; + const Parameter::Ptr& paramstr = member.templates[p]; + const Parameter& param = *paramstr; + HtmlEntities(paramType, param.type); + HtmlEntities(paramName, param.name); + ArrangeTypename(paramType); + out << paramType << ' ' << paramName; + } + out << ">
\n"; + } + + if (name.first() == '~') + { + String t = name; + t.replace("~", " ~ "); + out << " " << umlSymbol << ' ' << t << ""; + outIx << " " << t << ""; + } + else + { + out << " " << umlSymbol << ' ' << name << ""; + outIx << " " << name << ""; + } + + out << ": "; + + if (member.isStatic) + out << "static "; + + out << type << " ("; + outIx << '('; + + for (uint p = 0; p != member.parameters.size(); ++p) + { + if (p) + { + out << ", "; + outIx << ", "; + } + const Parameter::Ptr& paramstr = member.parameters[p]; + const Parameter& param = *paramstr; + HtmlEntities(paramType, param.type); + HtmlEntities(paramName, param.name); + ArrangeTypename(paramType); + out << paramType << ' ' << paramName; + outIx << paramType << ' ' << paramName; + } + + out << ')'; + outIx << ')'; + + if (member.isConst) + { + out << " const"; + outIx << " const"; + } + out << ";\n"; + outIx << "
"; + out + << "" << umlSymbol << ' ' << name << "" + << ": typedef " + << type + << ";\n"; + outIx + << "" + << "\n"; + } + + + void CompoundWriter::appendClassVariable() + { + out << "" << umlSymbol << ' ' << name << ""; + out << ": " << type; + out << ';'; + } + + + void CompoundWriter::appendClassIndex(Clob& output, bool isPublic, CompoundType compoundType, const Clob& data) + { + output << "

"; + if (isPublic) + output << "Public "; + else + output << "Protected "; + + Compound::AppendKindToString(output, compoundType); + output << "

\n"; + + output << "
"; + output << data; + output << "
typedef" << name << " : " + << type + << "
\n\n"; + } + + + + + + +} // namespace Job +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-writer.h b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-writer.h new file mode 100644 index 0000000000..e78ebb9576 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job-compound-writer.h @@ -0,0 +1,97 @@ +#ifndef __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_JOB_COMPOUND_WRITER_H__ +# define __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_JOB_COMPOUND_WRITER_H__ + +# include +# include "job.h" +# include "compound.h" +# include + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ +namespace Job +{ + + + + class CompoundWriter : public Yuni::Edalene::Dox2Article::Job::IJob + { + public: + //! Ordered section + typedef std::map OrderedSection; + + public: + /*! + ** \brief Explorer all known symbols + */ + static void Dispatch(); + + public: + //! \name Constructor & Destructor + //@{ + /*! + ** \brief Constructor + */ + explicit CompoundWriter(Compound::Ptr& compound); + //! Destructor + virtual ~CompoundWriter(); + //@} + + protected: + virtual void onExecute(); + + private: + void buildClass(); + void buildNamespace(); + + //! Create the ordered list (Yuni Coding's style) of all sections + void buildSectionMapping(OrderedSection& map, bool isAbstract); + + void appendClassIndex(Clob& output, bool isPublic, CompoundType compoundType, const Clob& data); + void appendClassSection(const Section& section, bool isAbstract); + void prepareClassSubtitle(const Section& section); + void appendClassFunction(const Member& member, bool isPublic); + void appendClassTypedef(const Member& member, bool isPublic); + void appendClassVariable(); + + private: + Compound::Ptr pCompound; + + // Temporary buffer for stream output + Clob out; + //! Temporary stream output (protected / public | compound type) + Clob outC[2][kdMax]; + Clob fileOut; + + // Some temporary variables for class building + String lastVisibility; + String sectionName; + String name; + String type; + String paramType; + String paramName; + String id; + String toggle; + String subtitle; + String visibility; + char umlSymbol; + + }; // class CompoundWriter + + + + + + + + +} // namespace Job +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + +#endif // __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_JOB_COMPOUND_WRITER_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/job.cpp b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job.cpp new file mode 100644 index 0000000000..c4ff8ec92f --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job.cpp @@ -0,0 +1,24 @@ + +#include "job.h" + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ +namespace Job +{ + + + Yuni::Job::QueueService<> queueService; + + + + +} // namespace Job +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/job.h b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job.h new file mode 100644 index 0000000000..1d1a6b606f --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/job.h @@ -0,0 +1,55 @@ +#ifndef __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_JOB_H__ +# define __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_JOB_H__ + +# include +# include "job.h" +# include +# include + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ +namespace Job +{ + + + class IJob : public Yuni::Job::IJob + { + public: + //! \name Constructor & Destructor + //@{ + /*! + ** \brief Default constructor + */ + IJob() {} + /*! + ** \brief Destructor + */ + virtual ~IJob() {} + //@} + + }; // class IJob + + + + + + + //! The queue service + extern Yuni::Job::QueueService<> queueService; + + + + + + +} // namespace Job +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + +#endif // __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_JOB_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/main.cpp b/src/ext/yuni/src/tools/yuni-docmake/dox2article/main.cpp new file mode 100644 index 0000000000..05a9095cb8 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/main.cpp @@ -0,0 +1,86 @@ + +#include +#include "../logs.h" + +#include "compound.h" +#include "options.h" +#include "read-index.h" +#include "job-compound-explorer.h" +#include "job-compound-writer.h" +#include "indexes.h" + + + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ + + + + class Program + { + public: + Program() + { + allSymbols = new Compound::Map[kdMax]; + allSymbolsByName = new Compound::Map[kdMax]; + } + + ~Program() + { + delete[] allSymbols; + delete[] allSymbolsByName; + } + + + int operator () () const + { + logs.checkpoint() << "Edalene Doxygen to Article"; + + if (!ReadXMLCatalogIndex(Options::doxygenXMLIndex)) + return EXIT_FAILURE; + + // Start the queue service + Job::queueService.start(); + + // Analyze all symbols + Job::CompoundExplorer::Dispatch(); + + // Writing articles + Job::CompoundWriter::Dispatch(); + + + Job::queueService.stop(); + + logs.info() << "writing index files"; + CreateNamespaceIndex(); + CreateClassIndex(); + CreateIndex(); + logs.info() << "done."; + + return 0; + } + + }; // class Program + + + + +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + + + + +int main(int /*argc*/, char** /*argv*/) +{ + logs.applicationName("edln-dox2article"); + Yuni::Edalene::Dox2Article::Program program; + return program(); +} + diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/options.cpp b/src/ext/yuni/src/tools/yuni-docmake/dox2article/options.cpp new file mode 100644 index 0000000000..4b33409564 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/options.cpp @@ -0,0 +1,24 @@ + +#include "options.h" + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ +namespace Options +{ + + String doxygenXMLIndex = "../../../docs/tmp/doxygen/xml"; + + String target = "../../../docs/src/001-en/200-documentation/002-v0.2/500-doxygen"; + + + +} // namespace Options +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/options.h b/src/ext/yuni/src/tools/yuni-docmake/dox2article/options.h new file mode 100644 index 0000000000..a9f8c41d67 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/options.h @@ -0,0 +1,28 @@ +#ifndef __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_OPTIONS_H__ +# define __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_OPTIONS_H__ + +# include +# include + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ +namespace Options +{ + + extern String doxygenXMLIndex; + + extern String target; + + + +} // namespace Options +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + +#endif // __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_OPTIONS_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/read-index.cpp b/src/ext/yuni/src/tools/yuni-docmake/dox2article/read-index.cpp new file mode 100644 index 0000000000..05aed09a0e --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/read-index.cpp @@ -0,0 +1,270 @@ + +#include "read-index.h" +#include "compound.h" +#include "../logs.h" +// xml +#include "../tinyxml/tinyxml.h" + + +#define SEP IO::Separator + + + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ + + + namespace // anonymous + { + + class XMLIndexVisitor : public TiXmlVisitor + { + public: + //! \name Constructor + //@{ + /*! + ** \brief Constructor + */ + XMLIndexVisitor(TiXmlDocument& document); + //! Destructor + virtual ~XMLIndexVisitor(); + //@} + + virtual bool VisitEnter(const TiXmlDocument& /*doc*/ ); + + virtual bool VisitExit(const TiXmlDocument& /*doc*/); + + virtual bool VisitEnter(const TiXmlElement& element, const TiXmlAttribute* attr); + + virtual bool VisitExit(const TiXmlElement& element); + + virtual bool Visit(const TiXmlDeclaration& /*declaration*/); + virtual bool Visit(const TiXmlText& /*text*/); + virtual bool Visit(const TiXmlComment& /*comment*/); + virtual bool Visit(const TiXmlUnknown& /*unknown*/); + + + private: + //! XML document + TiXmlDocument& pDocument; + //! + Compound::Deque pStack; + //! Stats + unsigned int pStats[kdMax]; + //! + bool pInName; + //! + bool pTagMemberAlreadyEncountered; + + }; // class XMLIndexVisitor + + + + + + XMLIndexVisitor::XMLIndexVisitor(TiXmlDocument& document) : + pDocument(document), + pInName(false), + pTagMemberAlreadyEncountered(false) + { + assert(&pDocument != NULL); + + for (unsigned int i = 0; i != kdMax; ++i) + pStats[i] = 0u; + } + + + XMLIndexVisitor::~XMLIndexVisitor() + { + CString<128,false> result; + CString<64,false> name; + + logs.info() << "Compound statistics from index"; + for (unsigned int i = 1; i != kdMax; ++i) + { + name.clear(); + Compound::AppendKindToString(name, (CompoundType) i); + + result.clear(); + result.resize(10, ' '); + result.overwriteRight(name); + + logs.info() << result << " : " << pStats[i]; + } + } + + + bool XMLIndexVisitor::VisitEnter(const TiXmlDocument& /*doc*/ ) + { + return true; + } + + + bool XMLIndexVisitor::VisitExit(const TiXmlDocument& /*doc*/) + { + return true; + } + + + bool XMLIndexVisitor::VisitEnter(const TiXmlElement& element, const TiXmlAttribute* /*attr*/) + { + const TIXML_STRING& strname = element.ValueTStr(); + + if (strname == "member" || strname == "compound") + { + pTagMemberAlreadyEncountered = false; + + const AnyString kind = element.Attribute("kind"); + const AnyString refid = element.Attribute("refid"); + + Compound::Ptr compound = new Compound(); + compound->kind = Compound::StringToKind(kind); + compound->refid = refid; + + ++pStats[compound->kind]; + allSymbolsByRefID[compound->refid] = compound; + allSymbols[compound->kind][compound->refid] = compound; + + if (!pStack.empty()) + { + Compound::Ptr parent = pStack.front(); + if (!(!parent)) + parent->members[compound->refid] = compound; + } + + pStack.push_front(compound); + pInName = false; + return true; + } + if (strname == "name") + { + if (!pTagMemberAlreadyEncountered && !pStack.empty()) + pInName = true; + return true; + } + + return true; + } + + + bool XMLIndexVisitor::Visit(const TiXmlText& text) + { + if (pInName && !pStack.empty()) + { + Compound::Ptr compound = pStack.front(); + assert(!(!compound)); + + const TIXML_STRING& name = text.ValueTStr(); + if (!name.empty()) + compound->name.append(name.c_str(), (unsigned int)name.size()); + } + return true; + } + + + bool XMLIndexVisitor::Visit(const TiXmlComment&) + { + return true; + } + + + bool XMLIndexVisitor::Visit(const TiXmlDeclaration&) + { + return true; + } + + + bool XMLIndexVisitor::Visit(const TiXmlUnknown&) + { + return true; + } + + + + bool XMLIndexVisitor::VisitExit(const TiXmlElement& element) + { + const TIXML_STRING& strname = element.ValueTStr(); + + if (strname == "member" || strname == "compound") + { + // Reset in any case @pInName + pInName = false; + + if (pStack.empty()) // strange - should never happen + return true; + Compound::Ptr compound = pStack.front(); + assert(!(!compound) && "invalid compound"); + pStack.pop_front(); + + if (not compound->name.empty()) + allSymbolsByName[compound->kind][compound->name] = compound; + return true; + } + if (strname == "name") + { + pInName = false; + return true; + } + + return true; + } + + + + static void PrepareAllCompounds() + { + const Compound::Map::iterator end = allSymbolsByRefID.end(); + for (Compound::Map::iterator i = allSymbolsByRefID.begin(); i != end; ++i) + (i->second)->prepare(); + } + + + } // anonymous namespace + + + + + + + + + bool ReadXMLCatalogIndex(const String& folder) + { + TiXmlDocument doc; + + // Parsing the XML + { + String filename; + filename << folder << SEP << "index.xml"; + + if (!doc.LoadFile(filename.c_str(), TIXML_ENCODING_UTF8)) + { + logs.error() << "impossible to read the catalog index: " << filename; + return false; + } + } + + // Analyze the XML document + { + XMLIndexVisitor visitor(doc); + if (!doc.Accept(&visitor)) + return false; + } + + PrepareAllCompounds(); + return true; + } + + + + +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + + diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/read-index.h b/src/ext/yuni/src/tools/yuni-docmake/dox2article/read-index.h new file mode 100644 index 0000000000..74d22aea7e --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/read-index.h @@ -0,0 +1,27 @@ +#ifndef __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_READ_INDEX_H__ +# define __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_READ_INDEX_H__ + +# include +# include + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ + + + /*! + ** \brief Read the entire catalog index of a doxygen folder (index.xml) + */ + bool ReadXMLCatalogIndex(const String& folder); + + + +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + +#endif // __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_READ_INDEX_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/dox2article/toolbox.h b/src/ext/yuni/src/tools/yuni-docmake/dox2article/toolbox.h new file mode 100644 index 0000000000..820d5da6dd --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/dox2article/toolbox.h @@ -0,0 +1,67 @@ +#ifndef __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_TOOLBOX_H__ +# define __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_TOOLBOX_H__ + +# include +# include +# include +# include +# include + + +namespace Yuni +{ +namespace Edalene +{ +namespace Dox2Article +{ + + template + static void HtmlEntities(StringT& out, const AnyString& string) + { + out = string; + out.replace("&", "&"); + out.replace("<", "<"); + out.replace(">", ">"); + } + + + + + template + static void ArrangeTypename(StringT& string) + { + string.replace(" *", "*"); + string.replace(" &", "&"); + string.replace(" < ", "<"); + string.replace(" > ", ">"); + string.replace(" >",">"); + string.replace(" , ", ", "); + } + + + template + static void PrepareTitle(StringT1& out, const StringT2& string) + { + out = string; + out.replace("
", ""); + out.replace("
", ""); // should never happen + out.replace("", ""); + out.replace("", ""); + out.replace("", ""); + out.replace("", ""); + out.replace("
", ""); + out.replace("
", ""); + out.replace("

", ""); + out.replace("

", ""); + out.trim(" \t\r\n:.;"); + } + + + + + +} // namespace Dox2Article +} // namespace Edalene +} // namespace Yuni + +#endif // __YUNI_TOOL_DOCMAKE_DOXYGEN_2_ARTICLE_TOOLBOX_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/logs.cpp b/src/ext/yuni/src/tools/yuni-docmake/logs.cpp new file mode 100644 index 0000000000..1fa7752618 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/logs.cpp @@ -0,0 +1,7 @@ + + +#include "logs.h" + + +DocMakeLogs logs; + diff --git a/src/ext/yuni/src/tools/yuni-docmake/logs.h b/src/ext/yuni/src/tools/yuni-docmake/logs.h new file mode 100644 index 0000000000..70dbde0ef9 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/logs.h @@ -0,0 +1,23 @@ +#ifndef __YUNI_DOCMAKE_LOGS_H__ +# define __YUNI_DOCMAKE_LOGS_H__ + +# include +# include +# include + + + +typedef Yuni::Logs::StdCout<> DocMakeLogsHandlers; +typedef /*Yuni::Logs::Time<*/ + Yuni::Logs::ApplicationName< + Yuni::Logs::VerbosityLevel + > > /*>*/ DocMakeLogsDecorators; + + +typedef Yuni::Logs::Logger DocMakeLogs; + + +extern DocMakeLogs logs; + + +#endif // __YUNI_DOCMAKE_LOGS_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/article.cpp b/src/ext/yuni/src/tools/yuni-docmake/make/article.cpp new file mode 100644 index 0000000000..363d0829db --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/article.cpp @@ -0,0 +1,168 @@ + +#include "article.h" +#include "../logs.h" +#include "program.h" +#include "indexes.h" + +using namespace Yuni; +using namespace Yuni::Tool::DocMake; + + + +ArticleData::ArticleData() : + error(true) +{ + allowedTagsInParagraph.insert("a"); + allowedTagsInParagraph.insert("b"); + allowedTagsInParagraph.insert("i"); + allowedTagsInParagraph.insert("u"); + allowedTagsInParagraph.insert("br"); + allowedTagsInParagraph.insert("code"); + allowedTagsInParagraph.insert("sub"); + allowedTagsInParagraph.insert("sup"); + allowedTagsInParagraph.insert("big"); + allowedTagsInParagraph.insert("button"); + allowedTagsInParagraph.insert("em"); + allowedTagsInParagraph.insert("img"); + allowedTagsInParagraph.insert("input"); + allowedTagsInParagraph.insert("kbd"); + allowedTagsInParagraph.insert("small"); + allowedTagsInParagraph.insert("span"); + allowedTagsInParagraph.insert("strong"); + allowedTagsInParagraph.insert("textarea"); +} + + +ArticleData::~ArticleData() +{ +} + + +void ArticleData::reset() +{ + assert(title.capacity() < 1024); + assert(accessPath.capacity() < 1024 * 1024); + + id = -1; + modificationTime = 0; + pageWeight = 1.0f; + coeff = 1.0f; + error = false; + order = (unsigned int) -1; + showTOC = true; + showHistory = true; + showQuickLinks = true; + directoryIndexContent = dicAll; + + language = "en"; + title.clear(); + tags.clear(); + directoryIndex.clear(); + accessPath.clear(); + tocItems.clear(); + wordCount.clear(); +} + + + +void ArticleData::tocAppend(unsigned int level, const String& caption) +{ + TOCItem* item = new TOCItem(); + String& itID = item->hrefID; + String& itCaption = item->caption; + + item->level = level; + itCaption = caption; + itCaption.trim(); + if (!itCaption) + itCaption = "Missing Header"; + + bool lastWasInvalid = true; + const String::const_utf8iterator end = itCaption.utf8end(); + for (String::const_utf8iterator i = itCaption.utf8begin(); i != end; ++i) + { + const char c = (char) *i; + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) + { + itID += c; + lastWasInvalid = false; + } + else + { + if (!lastWasInvalid) + itID += '_'; + lastWasInvalid = true; + } + } + itID.trim('_'); + itID.toLower(); + + // Adding line feed + itCaption.replace(". ", ".
"); + + // adding the new toc item + tocItems.push_back(item); +} + + +void ArticleData::tocRefactoring() +{ + if (tocItems.size() <= 1) + { + tocItems.clear(); + showTOC = false; + } + else + { + typedef std::set Set; + Set set; + String tmp; + for (unsigned int i = 0; i != tocItems.size(); ++i) + { + TOCItem& item = *(tocItems[i]); + String& id = item.hrefID; + if (set.find(id) != set.end()) + { + for (unsigned int rank = 2; rank < 1000; ++rank) + { + tmp.clear() << id << '_' << rank; + if (set.find(tmp) == set.end()) + { + id << '_' << rank; + break; + } + } + } + set.insert(id); + + if (Program::debug) + logs.info() << " :: " << relativeFilename << ": h" << item.level << ' ' << item.caption; + } + } +} + + +void ArticleData::insertTags(const AnyString& text) +{ + if (!text) + return; + Dictionary::Tag::Vector list; + text.split(list, " ,;|\t\r\n/\\"); + if (!list.empty()) + { + const Dictionary::Tag::Vector::iterator end = list.end(); + for (Dictionary::Tag::Vector::iterator i = list.begin(); i != end; ++i) + { + (*i).toLower(); + tags.insert(*i); + } + } +} + + +void ArticleData::reloadTagsFromDatabase() +{ + DocIndex::RetrieveTagList(*this); +} + + diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/article.h b/src/ext/yuni/src/tools/yuni-docmake/make/article.h new file mode 100644 index 0000000000..9f8d0bd26f --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/article.h @@ -0,0 +1,134 @@ +#ifndef __YUNI_DOCMAKE_ARTICLE_H__ +# define __YUNI_DOCMAKE_ARTICLE_H__ + +# include +# include +# include "dictionary.h" +# include +# include + + + class ArticleData + { + public: + typedef std::deque CoeffStack; + + + enum State + { + stNone = 0, + stTitle, + stTOCItem, + }; + + enum DirectoryIndexContent + { + //! The article won't appear in a directory index + dicNoIndex = 0, + //! Only the node will be added + dicNoFollow, + //! The node + all its children will be added + dicAll, + //! The maximum number of flags + dicMax, + }; + + class TOCItem + { + public: + typedef Yuni::SmartPtr Ptr; + typedef std::vector Vector; + + public: + //! Item level (1: h1, 2: h2) + unsigned int level; + //! ID + Yuni::String hrefID; + //! Caption + Yuni::String caption; + }; + + public: + //! \name Constructor & Destructor + //@{ + /*! + ** \brief Default constructor + */ + ArticleData(); + //! Destructor + ~ArticleData(); + //@} + + void reset(); + + void tocAppend(unsigned int level, const Yuni::String& caption); + void tocRefactoring(); + + /*! + ** \brief Insert a list of tags + ** + ** \param text A list of tags, separated by spaces or special characters + */ + void insertTags(const AnyString& text); + + void reloadTagsFromDatabase(); + + public: + //! Article ID + Yuni::sint64 id; + //! The original XML file + Yuni::String originalFilename; + //! Relative filename + Yuni::String relativeFilename; + //! The target filename within the htdocs folder + Yuni::String htdocsFilename; + + //! Language + Yuni::CString<16,false> language; + + //! Date of the last modification + Yuni::sint64 modificationTime; + + //! + Dictionary::TagSet allowedTagsInParagraph; + //! Page weight + float pageWeight; + //! The current coefficient + float coeff; + //! Title of the page + Yuni::String title; + + //! A non empty value to force the display of the access path + Yuni::String accessPath; + + //! An error has occured + bool error; + + //! Order + unsigned int order; + + //! Directory index + Yuni::String directoryIndex; + //! Flag to display the TOC (Table Of Content) + bool showTOC; + //! Flag to display quick links (on the left) + bool showQuickLinks; + //! Flag to display the page history + bool showHistory; + + //! SEO + Dictionary::WordsCount wordCount; + //! TOC items + TOCItem::Vector tocItems; + //! Tags + Dictionary::TagSet tags; + + //! Directory content index + DirectoryIndexContent directoryIndexContent; + + }; // class ArticleData + + + + +#endif // __YUNI_DOCMAKE_ARTICLE_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/dictionary.cpp b/src/ext/yuni/src/tools/yuni-docmake/make/dictionary.cpp new file mode 100644 index 0000000000..cb36c1629b --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/dictionary.cpp @@ -0,0 +1,69 @@ + +#include "dictionary.h" +#include "../sqlite/sqlite3.h" +#include "indexes.h" +#include "../logs.h" +#include "program.h" + + + +using namespace Yuni; + + +namespace Dictionary +{ + + AllWords allWords; + + Yuni::Mutex mutex; + + + + WordID FindWordID(const Word& word) + { + Yuni::MutexLocker locker(mutex); + const AllWords::const_iterator it = allWords.find(word); + if (it == allWords.end()) + return -1; + return it->second; + } + + + void PreloadFromIndexDB() + { + Yuni::MutexLocker locker(mutex); + allWords.clear(); + sqlite3* handle = (sqlite3*) DocIndex::DatabaseHandle(); + if (!handle) + return; + + char** result; + int rowCount, colCount; + if (SQLITE_OK != sqlite3_get_table(handle, "SELECT id,term FROM terms", &result, &rowCount, &colCount, NULL)) + return; + + if (rowCount) + { + if (!Tool::DocMake::Program::quiet) + { + if (rowCount == 1) + logs.info() << "Preloading 1 term from the index db"; + else + logs.info() << "Preloading " << rowCount << " terms from the index db"; + } + + unsigned int y = 2; + for (unsigned int row = 0; row < (unsigned int) rowCount; ++row) + { + const AnyString sid = result[y++]; + const Word term = result[y++]; + allWords[term] = sid.to(); + } + } + sqlite3_free_table(result); + } + + + + +} // namespace Dictionary diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/dictionary.h b/src/ext/yuni/src/tools/yuni-docmake/make/dictionary.h new file mode 100644 index 0000000000..c972c4e280 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/dictionary.h @@ -0,0 +1,66 @@ +#ifndef __DICTIONARY_H__ +# define __DICTIONARY_H__ + +# include +# include +# include +# include + + +namespace Dictionary +{ + + //! A single word + typedef Yuni::CString<32,false> Word; + //! A single tag + typedef Yuni::CString<42,false> Tag; + + //! Word ID + typedef int WordID; + + /*! + ** \brief Statistics for a single word + */ + class WordStat + { + public: + WordStat() : + coeff(0.f), count(0) + {} + float coeff; + unsigned int count; + }; + + + //! Statistics for a set of words + typedef std::map WordsCount; + + //! Set of tags + typedef std::set TagSet; + + + //! Association between a word and its ID + typedef std::map AllWords; + + + extern Yuni::Mutex mutex; + + extern AllWords allWords; + + + + /*! + ** \brief Preload data from the cache + */ + void PreloadFromIndexDB(); + + /*! + ** \brief + ** \return -1 if not found + */ + WordID FindWordID(const Word& word); + + +} // namespace Dictionary + +#endif // __DICTIONARY_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/index-db.sql b/src/ext/yuni/src/tools/yuni-docmake/make/index-db.sql new file mode 100644 index 0000000000..c294852561 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/index-db.sql @@ -0,0 +1,113 @@ + +-- +-- Header +-- +CREATE TABLE index_header ( + -- Version of the index cache + version INTEGER NOT NULL DEFAULT 1, + -- Flag to know if the whole index cache is marked as dirty + -- (means potentially invalid) + dirty INTEGER NOT NULL DEFAULT 0 +); + + + +-- +-- Articles +-- +CREATE TABLE articles ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + -- Lang of the artcile + lang TEXT NOT NULL DEFAULT 'en', + -- original filename (absolute) + rel_path TEXT NOT NULL, + -- Target filename, relative to the htdocs + html_href TEXT NOT NULL UNIQUE, + -- Article's title + title TEXT NOT NULL, + -- SEO weight + weight REAL NOT NULL DEFAULT 1.0, + -- Order + parent_order INTEGER NOT NULL DEFAULT 1000, + -- Flag to know if the article should be rebuilt + dirty INTEGER NOT NULL DEFAULT 1, + -- The number of tags + tag_count INTEGER NOT NULL DEFAULT 0, + -- Flag to show the quick links + show_quick_links INTEGER NOT NULL DEFAULT 1, + -- Flag to show the history + show_history INTEGER NOT NULL DEFAULT 1, + -- Flag to show the table of content + show_toc INTEGER NOT NULL DEFAULT 1, + -- Timestamp of the last modification + modified INTEGER NOT NULL DEFAULT 0, + -- Flag to show the directory index + directory_index INTEGER NOT NULL DEFAULT 2, -- dicAll + -- The parent + parent TEXT NOT NULL, + force_access_path TEXT DEFAULT NULL, + dir_index TEXT DEFAULT NULL +); + +CREATE INDEX ix_art_relpath ON articles(rel_path); +CREATE INDEX ix_art_parent ON articles(parent); +CREATE INDEX ix_art_dirty ON articles(dirty); + + + +-- +-- Table of content +-- +CREATE TABLE toc ( + html_href TEXT NOT NULL REFERENCES articles(html_href) ON DELETE CASCADE, + indx INTEGER NOT NULL, + lvl INTEGER NOT NULL, + href_id TEXT NOT NULL, + caption TEXT NOT NULL, + PRIMARY KEY (html_href,indx) +); + + +-- +-- SEO, terms +-- +CREATE TABLE terms ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + weight_user REAL NOT NULL DEFAULT 1.0, + weight_rel_others REAL NOT NULL DEFAULT 1.0, + -- The total weight + weight REAL NOT NULL DEFAULT 1.0, + term TEXT NOT NULL UNIQUE +); + + +-- +-- SEO +-- +CREATE TABLE terms_per_article ( + term_id INTEGER NOT NULL REFERENCES terms(id) ON DELETE CASCADE, + article_id INTEGER NOT NULL REFERENCES articles(id) ON DELETE CASCADE, + count_in_page INTEGER NOT NULL DEFAULT 0, + weight REAL NOT NULL DEFAULT 1.0 +); + + +-- +-- Tags per article +-- +CREATE TABLE tags_per_article ( + article_id INTEGER NOT NULL REFERENCES articles(id) ON DELETE CASCADE, + tagname TEXT NOT NULL, + PRIMARY KEY (article_id, tagname) +); + + +-- +-- Dependencies +-- +CREATE TABLE deps ( + input TEXT NOT NULL PRIMARY KEY, + html_href TEXT NOT NULL, + article_id INTEGER NOT NULL REFERENCES articles(id) ON DELETE CASCADE +); + diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/indexes.cpp b/src/ext/yuni/src/tools/yuni-docmake/make/indexes.cpp new file mode 100644 index 0000000000..c9c1029b1e --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/indexes.cpp @@ -0,0 +1,999 @@ + +#include "indexes.h" +#include "../sqlite/sqlite3.h" +#include +#include +#include +#include "../logs.h" +#include "index-db.hxx" +#include "program.h" +#ifndef YUNI_OS_WINDOWS +# include "stdlib.h" // man 3 system +#endif + + +# define SEP IO::Separator + + +using namespace Yuni; +using namespace Yuni::Tool::DocMake; + + +namespace DocIndex +{ + + + + namespace // anonymous + { + + enum + { + dbVersion = 10, // arbitrary value + }; + + static sqlite3* gDB = nullptr; + + + template + static sint64 RetrieveArticleID(const StringT& href) + { + if (!gDB || !href) + return -1; + + sqlite3_stmt* stmt; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, "SELECT id FROM articles WHERE html_href = $1", -1, &stmt, NULL)) + return -1; + sqlite3_bind_text(stmt, 1, href.c_str(), href.size(), NULL); + if (SQLITE_ROW != sqlite3_step(stmt)) + { + sqlite3_finalize(stmt); + return -1; + } + const AnyString id = (const char*) sqlite3_column_text(stmt, 0); + sint64 result; + if (!id.to(result)) + { + sqlite3_finalize(stmt); + return -1; + } + sqlite3_finalize(stmt); + return result; + } + + + static bool ResetDBIndex(const String& filename) + { + if (!Program::quiet) + logs.info() << "the index database needs to be rebuilt"; + + // Close the sqlite handle + Close(); + // Destroy the sqlite database + IO::File::Delete(filename); + // Try to reopen it + switch (sqlite3_open(filename.c_str(), &gDB)) + { + case SQLITE_OK: + break; + default: + logs.error() << "impossible to re-open the database after deletion."; + return false; + } + + Clob script; + char* message = nullptr; + + // Create tables + PrepareSQLScript(script); + if (SQLITE_OK != sqlite3_exec(gDB, script.c_str(), NULL, NULL, &message)) + { + logs.error() << "database: " << message; + sqlite3_free(message); + } + + script.clear() << "INSERT INTO index_header (version) VALUES (" << (unsigned int) dbVersion << ");"; + if (SQLITE_OK != sqlite3_exec(gDB, script.c_str(), NULL, NULL, &message)) + { + logs.error() << "database: " << message; + sqlite3_free(message); + } + + return true; + } + + + static bool UsePragma() + { + // UTF-8 + if (SQLITE_OK != sqlite3_exec(gDB, "PRAGMA encoding = \"UTF-8\"; ", NULL, NULL, NULL)) + { + logs.error() << "impossible to use the UTF8 encoding"; + return false; + } + // Foreign keys + if (SQLITE_OK != sqlite3_exec(gDB, "PRAGMA foreign_keys = 1;", NULL, NULL, NULL)) + { + logs.error() << "impossible to enable foreign keys"; + return false; + } + return true; + } + + + static bool CheckDatabaseIntegrity(const String& dbfilename) + { + // prepare the SQL statement from the command line + static const char* const query = "SELECT version,dirty FROM index_header"; + + sqlite3_stmt* stmt; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, query, -1, &stmt, 0)) + { + sqlite3_finalize(stmt); + if (!ResetDBIndex(dbfilename)) + return false; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, query, -1, &stmt, 0)) + { + sqlite3_finalize(stmt); + stmt = nullptr; + if (!Program::quiet) + logs.info() << "The database index format needs update. Performing a full reindex"; + } + } + if (stmt && SQLITE_ROW == sqlite3_step(stmt)) + { + const AnyString version = (const char*) sqlite3_column_text(stmt, 0); + const AnyString dirty = (const char*) sqlite3_column_text(stmt, 1); + if (dirty.to()) + { + logs.info() << "The database index is marked as dirty. Performing a full reindex"; + } + else + { + if (version.to() == dbVersion) + { + sqlite3_finalize(stmt); + return true; + } + if (!Program::quiet) + logs.info() << "The database index format needs update. Performing a full reindex"; + } + } + sqlite3_finalize(stmt); + return ResetDBIndex(dbfilename); + } + + } // anonymous namespace + + + void* DatabaseHandle() + { + return gDB; + } + + + bool Open() + { + if (gDB) + { + sqlite3_close(gDB); + gDB = nullptr; + } + + if (Program::clean) + IO::File::Delete(Program::indexCacheFilename); + + switch (sqlite3_open(Program::indexCacheFilename.c_str(), &gDB)) + { + case SQLITE_OK: + { + if (!UsePragma() || !CheckDatabaseIntegrity(Program::indexCacheFilename)) + { + Close(); + return false; + } + break; + } + case SQLITE_PERM: + logs.error() << "not enough permissions to open " << Program::indexCacheFilename; + return false; + case SQLITE_BUSY: + logs.error() << "The index database is locked."; + return false; + case SQLITE_CORRUPT: + logs.error() << "The index database is malformed"; + return false; + case SQLITE_CANTOPEN: + logs.error() << "Unable to open " << Program::indexCacheFilename; + return false; + default: + return false; + } + + // Mark the database index as dirty + if (SQLITE_OK != sqlite3_exec(gDB, "UPDATE index_header SET dirty = 1", NULL, NULL, NULL)) + return false; + return true; + } + + + void Close() + { + if (gDB) + { + // Mark the database index as non-dirty + sqlite3_exec(gDB, "UPDATE index_header SET dirty = 0", NULL, NULL, NULL); + // Close the handle + sqlite3_close(gDB); + gDB = nullptr; + } + } + + + void Vacuum() + { + if (gDB) + sqlite3_exec(gDB, "VACUUM;", NULL, NULL, NULL); + } + + + Yuni::sint64 ArticleLastModificationTimeFromCache(const String& filename) + { + if (!filename) + return -1; + + // prepare the SQL statement from the command line + sqlite3_stmt* stmt; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, "SELECT modified FROM articles WHERE rel_path = $1", -1, &stmt, 0)) + return -1; + sqlite3_bind_text(stmt, 1, filename.c_str(), filename.size(), NULL); + + if (SQLITE_ROW == sqlite3_step(stmt)) + { + const AnyString modified = (const char*) sqlite3_column_text(stmt, 0); + sint64 value; + if (!modified.to(value)) + value = -1; + sqlite3_finalize(stmt); + return value; + } + return -1; + } + + + void Write(ArticleData& article) + { + if (!gDB) + return; + + CString<256> query; + + // Delete the article, and all its data + query.clear() << "DELETE FROM articles WHERE rel_path = $1;"; + sqlite3_stmt* stmt = nullptr; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, query.c_str(), -1, &stmt, NULL)) + logs.error() << "invalid SQL query " << query; + else + { + sqlite3_bind_text(stmt, 1, article.relativeFilename.c_str(), article.relativeFilename.size(), NULL); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + } + + String parent = article.htdocsFilename; + if (!parent) + parent = '/'; + else + { + String::Size offset = parent.find_last_of("/\\"); + if (offset < parent.size()) + { + if (!offset) + parent = '/'; + else + parent.resize(offset); + } + } + + // Insert the new article + { + query.clear() << "INSERT INTO articles (parent_order, weight, show_quick_links" + << ", show_history" + << ", show_toc, modified, rel_path,html_href, title,parent,directory_index,lang)" + << " VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12);"; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, query.c_str(), -1, &stmt, NULL)) + { + logs.error() << "invalid SQL query: " << query; + return; + } + else + { + sqlite3_bind_int(stmt, 1, (int)article.order); + sqlite3_bind_double(stmt, 2, article.pageWeight); + sqlite3_bind_int(stmt, 3, (article.showQuickLinks ? 1 : 0)); + sqlite3_bind_int(stmt, 4, (article.showHistory ? 1 : 0)); // show history + sqlite3_bind_int(stmt, 5, (article.showTOC ? 1 : 0)); // show toc + sqlite3_bind_int64(stmt, 6, article.modificationTime); + sqlite3_bind_text(stmt, 7, article.relativeFilename.c_str(), article.relativeFilename.size(), NULL); + sqlite3_bind_text(stmt, 8, article.htdocsFilename.c_str(), article.htdocsFilename.size(), NULL); + sqlite3_bind_text(stmt, 9, article.title.c_str(), article.title.size(), NULL); + sqlite3_bind_text(stmt, 10, parent.c_str(), parent.size(), NULL); + sqlite3_bind_int(stmt, 11, (int)article.directoryIndexContent); + sqlite3_bind_text(stmt, 12, article.language.c_str(), article.language.size(), NULL); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + } + } + + // Getting the article ID + article.id = RetrieveArticleID(article.htdocsFilename); + if (article.id < 0) + { + logs.error() << "Invalid article ID after inserting, " << article.htdocsFilename; + return; + } + + if (not article.accessPath.empty()) + { + query.clear() << "UPDATE articles SET force_access_path = $1 WHERE rel_path = $2;"; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, query.c_str(), -1, &stmt, NULL)) + logs.error() << "invalid SQL query " << query; + else + { + sqlite3_bind_text(stmt, 1, article.accessPath.c_str(), article.accessPath.size(), NULL); + sqlite3_bind_text(stmt, 2, article.relativeFilename.c_str(), article.relativeFilename.size(), NULL); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + } + } + + if (not article.directoryIndex.empty()) + { + // We want UNIX-style paths + # ifdef YUNI_OS_WINDOWS + String directoryIndex = article.directoryIndex; + directoryIndex.replace('\\', '/'); + # else + const String& directoryIndex = article.directoryIndex; + # endif + query.clear() << "UPDATE articles SET dir_index = $1 WHERE rel_path = $2;"; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, query.c_str(), -1, &stmt, NULL)) + logs.error() << "invalid SQL query " << query; + else + { + sqlite3_bind_text(stmt, 1, directoryIndex.c_str(), directoryIndex.size(), NULL); + sqlite3_bind_text(stmt, 2, article.relativeFilename.c_str(), article.relativeFilename.size(), NULL); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + } + } + + // TOC + if (!article.tocItems.empty()) + { + for (unsigned int i = 0; i != article.tocItems.size(); ++i) + { + // alias to the current TOC item + assert(article.tocItems[i] && "invalid toc item"); + const ArticleData::TOCItem& item = *(article.tocItems[i]); + + query.clear() << "INSERT INTO toc (html_href,indx,lvl,href_id,caption) VALUES ($1," << i << ',' + << item.level << ",$2,$3);"; + sqlite3_prepare_v2(gDB, query.c_str(), -1, &stmt, NULL); + sqlite3_bind_text(stmt, 1, article.htdocsFilename.c_str(), article.htdocsFilename.size(), NULL); + sqlite3_bind_text(stmt, 2, item.hrefID.c_str(), item.hrefID.size(), NULL); + sqlite3_bind_text(stmt, 3, item.caption.c_str(), item.caption.size(), NULL); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + } + } + + // Tags + if (!article.tags.empty()) + { + Dictionary::TagSet::const_iterator end = article.tags.end(); + for (Dictionary::TagSet::const_iterator i = article.tags.begin(); i != end; ++i) + { + const Dictionary::Tag& tagname = *i; + + query.clear() << "INSERT INTO tags_per_article (article_id,tagname) VALUES (" << article.id << ",$1);"; + int error; + if (SQLITE_OK == (error = sqlite3_prepare_v2(gDB, query.c_str(), query.size(), &stmt, NULL))) + { + sqlite3_bind_text(stmt, 1, tagname.c_str(), tagname.size(), NULL); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + } + else + logs.error() << "impossible to register tag for " << article.htdocsFilename << ", err." << error; + } + } + } + + + void RemoveNonExistingEntries() + { + if (!gDB) + return; + + if (!Program::quiet) + logs.info() << "Looking for deprecated entries in the database"; + + CString<512> s = "DELETE FROM articles WHERE rel_path = \"\";"; + { + sqlite3_stmt* stmt; + sqlite3_prepare_v2(gDB, s.c_str(), -1, &stmt, NULL); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + } + + char** result; + int rowCount, colCount; + if (SQLITE_OK != sqlite3_get_table(gDB, "SELECT rel_path FROM articles", &result, &rowCount, &colCount, NULL)) + return; + + if (rowCount) + { + if (!Program::quiet) + { + if (rowCount == 1) + logs.info() << "1 article available in the index db"; + else + logs.info() << rowCount << " articles available in the index db"; + } + unsigned int y = 1; + for (unsigned int row = 0; row < (unsigned int) rowCount; ++row, ++y) + { + const AnyString relPath = result[y]; + s.clear() << Program::input << SEP << relPath; + if (!IO::File::Exists(s)) + { + if (!Program::quiet) + logs.info() << "The entry '" << relPath << "' is deprecated"; + + s.clear() << "DELETE FROM articles WHERE rel_path = $1;"; + sqlite3_stmt* stmt; + sqlite3_prepare_v2(gDB, s.c_str(), s.size(), &stmt, NULL); + sqlite3_bind_text(stmt, 1, relPath.c_str(), relPath.size(), NULL); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + } + } + } + + sqlite3_free_table(result); + } + + + bool AppendArticleTitleFromPath(String& out, const String& path) + { + if (!gDB) + return false; + + sqlite3_stmt* stmt; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, "SELECT title FROM articles WHERE html_href = $1", -1, &stmt, NULL)) + return false; + sqlite3_bind_text(stmt, 1, path.c_str(), path.size(), NULL); + if (SQLITE_ROW != sqlite3_step(stmt)) + { + sqlite3_finalize(stmt); + return false; + } + const AnyString title = (const char*) sqlite3_column_text(stmt, 0); + if (!title) + { + sqlite3_finalize(stmt); + return false; + } + out += title; + sqlite3_finalize(stmt); + return true; + } + + + + + namespace // anonymous + { + + static void InternalBuildDirectoryIndex(Clob& out, const String& path, unsigned int level) + { + // We want UNIX-styles paths + # ifdef YUNI_OS_WINDOWS + String srcPath = path; + srcPath.replace('\\', '/'); + # else + const String& srcPath = path; + # endif + + char** result; + int rowCount, colCount; + String query = "SELECT title, html_href,directory_index FROM articles WHERE parent = \""; + query << srcPath << "\" AND directory_index > 0 ORDER BY parent_order ASC, title"; + if (SQLITE_OK != sqlite3_get_table(gDB, query.c_str(), &result, &rowCount, &colCount, NULL)) + return; + + if (!rowCount) + { + sqlite3_free_table(result); + return; + } + + if (!level) + { + for (unsigned int x = 0; x != level; ++x) + out << '\t'; + out << "
Directory Index
\n"; + } + for (unsigned int x = 0; x != level; ++x) + out << '\t'; + out << "
    \n"; + unsigned int y = 3; + for (unsigned int row = 0; row < (unsigned int) rowCount; ++row) + { + const AnyString title = result[y++]; + const String href = result[y++]; + unsigned int dic = AnyString(result[y++]).to(); + if (dic >= ArticleData::dicMax) + dic = ArticleData::dicAll; + + if (!href) // must not be empty + continue; + + for (unsigned int x = 0; x != level; ++x) + out << '\t'; + out << "
  • " << title << "
  • \n"; + + if (dic >= ArticleData::dicAll) + InternalBuildDirectoryIndex(out, href, level + 1); + } + + sqlite3_free_table(result); + + for (unsigned int x = 0; x != level; ++x) + out << '\t'; + out << "
\n"; + + if (!level) + { + for (unsigned int x = 0; x != level; ++x) + out << '\t'; + out << "
\n"; + } + } + + } // anonymous namespace + + + + void BuildDirectoryIndex(Clob& out, const String& path) + { + out.clear(); + InternalBuildDirectoryIndex(out, path, 0); + } + + + + void BuildSitemap() + { + String filename; + filename << Program::htdocs << SEP << "sitemap.xml"; + if (Program::verbose) + logs.info() << "writing " << filename; + + IO::File::Stream out; + if (!out.openRW(filename)) + { + logs.error() << "sitemap: impossible to write " << filename; + return; + } + + Clob dat; + // Begining of the sitemap + dat << "\n" + << "\n"; + + + float weightMin = 0.f; + float weightMax = 0.f; + char** result; + int rowCount, colCount; + String href; + + // Looking for weights limits + { + const char* const query = "SELECT MIN(weight), MAX(weight) FROM articles WHERE weight > 0;"; + if (SQLITE_OK == sqlite3_get_table(gDB, query, &result, &rowCount, &colCount, NULL)) + { + if (rowCount == 1) + { + unsigned int y = 2; + const AnyString minW = result[y++]; + const AnyString maxW = result[y++]; + + weightMin = minW.to(); + weightMax = maxW.to(); + + if (Math::Equals(weightMin, weightMax)) + { + // The two values must not be equal to avoid a division by zero + weightMin -= 0.1f; + weightMax += 0.1f; + } + } + sqlite3_free_table(result); + } + } + + const char* const query = "SELECT html_href,weight,modified FROM articles WHERE weight > 0.2 ORDER BY html_href"; + if (SQLITE_OK == sqlite3_get_table(gDB, query, &result, &rowCount, &colCount, NULL)) + { + String tmp; + + if (rowCount) + { + CString<64,false> formattedDate; + + unsigned int y = 3; + for (unsigned int row = 0; row < (unsigned int) rowCount; ++row) + { + href = result[y++]; + const AnyString weightStr = result[y++]; + const String modifiedStr = result[y++]; + + if (href.size() <= 1) // avoid invalid paths, such as '/' + continue; + + // Weight of the article + float weight = weightStr.to(); + + // Checking if the hef is less than 2048 chars + if (href.size() >= 2048) + { + logs.warning() << "sitemap: invalid href (> 2048 char), skipped : " << href; + continue; + } + + // Priority, for the sitemap (%) + float priority = ((weight - weightMin) / (weightMax - weightMin)); + if (priority < 0.1f) + priority = 0.1f; + else + { + if (priority > 1.f) + priority = 1.f; + } + + // Escaping + // TODO use a better routine for doing that + href.replace("&", "&"); + href.replace("'", "'"); + href.replace("\"", """); + href.replace("<", "<"); + href.replace("≤", "≤"); + href.replace(">", ">"); + href.replace("≥", "≥"); + href.replace("//", "/"); + + dat << "\n"; + tmp.clear() << Program::webroot << href; + dat << "\t" << tmp << "\n"; + // The default priority in a sitemap is 0.5 + if (!Math::Equals(priority, 0.5f)) + dat << "\t" << priority << "\n"; + dat << "\t"; + DateTime::TimestampToString(dat, "%Y-%m-%d", modifiedStr.to(), false); + dat << "\n"; + dat << "\n"; + } + } + sqlite3_free_table(result); + } + dat << "\n"; + out << dat; + + // trying gzip + out.close(); + # ifndef YUNI_OS_WINDOWS + //href.clear() << "gzip -f -9 \"" << filename << "\""; + //system(href.c_str()); + # endif + } + + + + static int TryToFindWordID(const Dictionary::Word& term) + { + sqlite3_stmt* stmt; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, "SELECT id FROM terms WHERE term = $1", -1, &stmt, NULL)) + return -1; + sqlite3_bind_text(stmt, 1, term.c_str(), term.size(), NULL); + if (SQLITE_ROW != sqlite3_step(stmt)) + { + sqlite3_finalize(stmt); + return -1; + } + const AnyString idstr = (const char*) sqlite3_column_text(stmt, 0); + int result = -1; + if (!(!idstr)) + { + if (!idstr.to(result)) + result = -1; + } + sqlite3_finalize(stmt); + return result; + } + + + int RegisterWordReference(const Dictionary::Word& term) + { + int id = TryToFindWordID(term); + if (id < 0) + { + sqlite3_stmt* stmt; + const char* const query = "INSERT INTO terms (term) VALUES ($1);"; + sqlite3_prepare_v2(gDB, query, -1, &stmt, NULL); + sqlite3_bind_text(stmt, 1, term.c_str(), term.size(), NULL); + sqlite3_step(stmt); + sqlite3_finalize(stmt); + + // Try again + id = TryToFindWordID(term); + } + return id; + } + + + int FindArticleID(const Yuni::String& href) + { + sqlite3_stmt* stmt; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, "SELECT id FROM articles WHERE html_href = $1", -1, &stmt, NULL)) + return -1; + sqlite3_bind_text(stmt, 1, href.c_str(), href.size(), NULL); + if (SQLITE_ROW != sqlite3_step(stmt)) + { + sqlite3_finalize(stmt); + return -1; + } + const AnyString idstr = (const char*) sqlite3_column_text(stmt, 0); + int result = -1; + if (!(!idstr)) + { + if (!idstr.to(result)) + result = -1; + } + sqlite3_finalize(stmt); + return result; + } + + + void RegisterWordIDsForASingleArticle(ArticleID articleid, const int* termid, + const int* countInArticle, + const float* weights, + unsigned int count) + { + CString<1024> query; + query << "BEGIN;\n"; + query << "DELETE FROM terms_per_article WHERE article_id = " << articleid << ";\n"; + for (unsigned int i = 0; i != count; ++i) + { + query << "INSERT INTO terms_per_article (term_id,article_id,count_in_page,weight) VALUES (" + << termid[i] << ',' + << articleid << ',' + << countInArticle[i] << ',' + << weights[i] << ");\n"; + } + query << "COMMIT;\n"; + + sqlite3_exec(gDB, query.c_str(), NULL, NULL, NULL); + } + + + static uint64 FindMaxOccurrenceForAnyTerm() + { + const char* const query = "SELECT SUM(count_in_page) AS s from terms_per_article GROUP BY term_id ORDER BY s DESC LIMIT 1;"; + sqlite3_stmt* stmt; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, query, -1, &stmt, NULL)) + return 0; + + if (SQLITE_ROW != sqlite3_step(stmt)) + { + sqlite3_finalize(stmt); + return 0; + } + const AnyString rstr = (const char*) sqlite3_column_text(stmt, 0); + const uint64 r = rstr.to(); + sqlite3_finalize(stmt); + return r; + } + + + static void UpdateAllRelativeTermWeight(uint64 maxO) + { + char** result; + int rowCount, colCount; + const char* const query = "SELECT term_id, SUM(count_in_page) FROM terms_per_article GROUP BY term_id;"; + if (SQLITE_OK != sqlite3_get_table(gDB, query, &result, &rowCount, &colCount, NULL)) + return; + + CString<128 * 1024> s; + s << "BEGIN;\n"; + if (rowCount) + { + unsigned int y = 1; + for (unsigned int row = 0; row < (unsigned int) rowCount; ++row) + { + const AnyString termID = result[++y]; + const AnyString scount = result[++y]; + if (!termID || !scount) + continue; + unsigned int count = scount.to(); + double d = 1. - (count * 0.5 / (double)maxO); + s << "UPDATE terms SET weight_rel_others = " << d << " WHERE id = " << termID << ";\n"; + } + } + + sqlite3_free_table(result); + + if (rowCount) + { + s << "COMMIT;\n"; + sqlite3_exec(gDB, s.c_str(), NULL, NULL, NULL); + } + } + + + void UpdateAllSEOWeights() + { + // Finding the maximum occurence of any term + { + uint64 maxO = FindMaxOccurrenceForAnyTerm(); + UpdateAllRelativeTermWeight(maxO); + } + // calculating the total weight for each term + { + const char* const query = "UPDATE terms SET weight = weight_user * weight_rel_others;"; + sqlite3_exec(gDB, query, NULL, NULL, NULL); + } + } + + + void BuildSEOTermReference(Clob& data) + { + char** result; + int rowCount, colCount; + CString<512,false> query; + query << "SELECT w.id,w.term, t.article_id,t.count_in_page,t.weight * w.weight" + << " FROM terms_per_article AS t, terms as w" + << " WHERE w.id = t.term_id ORDER BY term_id"; + if (SQLITE_OK != sqlite3_get_table(gDB, query.c_str(), &result, &rowCount, &colCount, NULL)) + return; + + if (rowCount) + { + sint64 oldTermID = -1; + unsigned int y = 5; + for (unsigned int row = 0; row < (unsigned int) rowCount; ++row) + { + const sint64 termid = AnyString(result[y++]).to(); + const AnyString term = result[y++]; + const AnyString articleID = result[y++]; + const AnyString scount = result[y++]; + const AnyString sweight = result[y++]; + if (termid < 0) + continue; + if (termid != oldTermID) + { + oldTermID = termid; + if (row) + data << "]);\n"; + data << "f(" << termid << ",'" << term << "',["; + } + else + data << ','; + + data + << "{a:" << articleID // article ID + << ",c:" << scount // count + << ",w:" << sweight // weight + << '}'; + } + data << "]);\n"; + } + sqlite3_free_table(result); + } + + + + void BuildSEOArticlesReference() + { + sqlite3_stmt* stmt; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, "SELECT id,html_href,title,weight FROM articles;", -1, &stmt, NULL)) + return; + + CString<1024 * 128> s("if (1) { var f=function(id,d) {SEO.articles[id] = d};"); + + while (SQLITE_ROW == sqlite3_step(stmt)) + { + const AnyString articleID = (const char*) sqlite3_column_text(stmt, 0); + const AnyString href = (const char*) sqlite3_column_text(stmt, 1); + const AnyString title = (const char*) sqlite3_column_text(stmt, 2); + const AnyString sweight = (const char*) sqlite3_column_text(stmt, 3); + s + << "f(" << articleID << ",{" + << "t:\"" << title << '"'// article ID + << ",h:\"" << href << '"'// article ID + << ",w:" << sweight // weight + << "});"; + } + sqlite3_finalize(stmt); + + s << " }\n"; + + // Writing the JS file + String filename; + filename << Program::htdocs << SEP << "seo" << SEP << "data.js"; + IO::File::AppendContent(filename, s); + } + + + void AppendChildrenList(Yuni::String& text, const String& path, const String& current) + { + if (!path) + return; + + sqlite3_stmt* stmt; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, "SELECT title,html_href FROM articles WHERE parent = $1 ORDER BY parent_order,LOWER(title)", -1, &stmt, NULL)) + return; + sqlite3_bind_text(stmt, 1, path.c_str(), path.size(), NULL); + unsigned int count = 0; + while (SQLITE_ROW == sqlite3_step(stmt)) + { + if (!count++) + { + text << '\n'; + text << "\t
    \n"; + } + const AnyString title = (const char*) sqlite3_column_text(stmt, 0); + const AnyString href = (const char*) sqlite3_column_text(stmt, 1); + text << "\t
  • " << title << "
  • \n"; + } + if (count) + text << "\t
"; + + sqlite3_finalize(stmt); + return; + } + + + void RetrieveTagList(ArticleData& article) + { + article.tags.clear(); + if (article.id < 0) + return; + + sqlite3_stmt* stmt; + if (SQLITE_OK != sqlite3_prepare_v2(gDB, "SELECT tagname FROM tags_per_article WHERE article_id = $1", -1, &stmt, NULL)) + return; + sqlite3_bind_int64(stmt, 1, article.id); + while (SQLITE_ROW == sqlite3_step(stmt)) + { + const AnyString tagname = (const char*) sqlite3_column_text(stmt, 0); + article.tags.insert(tagname); + } + sqlite3_finalize(stmt); + } + + + + +} // namespace DocIndex diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/indexes.h b/src/ext/yuni/src/tools/yuni-docmake/make/indexes.h new file mode 100644 index 0000000000..8c9c036d77 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/indexes.h @@ -0,0 +1,86 @@ +#ifndef __YUNI_DOCMAKE_INDEXES_H__ +# define __YUNI_DOCMAKE_INDEXES_H__ + +# include +# include +# include +# include "article.h" +# include "dictionary.h" + + +namespace DocIndex +{ + + //! Article ID + typedef Yuni::sint64 ArticleID; + + + bool Open(); + + void Close(); + + void Write(ArticleData& article); + + + void RemoveNonExistingEntries(); + + void Vacuum(); + + + bool AppendArticleTitleFromPath(Yuni::String& out, const Yuni::String& path); + + + void BuildDirectoryIndex(Yuni::Clob& out, const Yuni::String& path); + + + Yuni::sint64 ArticleLastModificationTimeFromCache(const Yuni::String& filename); + + + /*! + ** \brief Build a sitemap + ** + ** \see http://en.wikipedia.org/wiki/Site_map + ** \see http://en.wikipedia.org/wiki/Google_Sitemaps + ** + ** This method must be ran from the main thread + */ + void BuildSitemap(); + + + /*! + ** \brief Register a term in the database + ** + ** \return The ID in the database + */ + int RegisterWordReference(const Dictionary::Word& term); + + void RegisterWordIDsForASingleArticle(Yuni::sint64 articleid, const int* termid, + const int* countInArticle, + const float* weights, + unsigned int count); + + + void UpdateAllSEOWeights(); + + + int FindArticleID(const Yuni::String& href); + + void AppendChildrenList(Yuni::String& text, const Yuni::String& path, const Yuni::String& current); + + /*! + ** \brief Retrieve the tag list of a single article + */ + void RetrieveTagList(ArticleData& article); + + void BuildSEOTermReference(Yuni::Clob& data); + + void BuildSEOArticlesReference(); + + + void* DatabaseHandle(); + + + +} // namespace DocIndex + +#endif // __YUNI_DOCMAKE_INDEXES_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/job-writer.cpp b/src/ext/yuni/src/tools/yuni-docmake/make/job-writer.cpp new file mode 100644 index 0000000000..924a9ab32f --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/job-writer.cpp @@ -0,0 +1,947 @@ + +#include "job-writer.h" +#include +#include +#include "job.h" +#include "../logs.h" +#include "../tinyxml/tinyxml.h" +#include +#include +#include "indexes.h" +#include "webpage.hxx" +#include "program.h" +#include "dictionary.h" + + +using namespace Yuni; +using namespace Yuni::Tool::DocMake; + +# define SEP IO::Separator + + +namespace // anonymous +{ + static Mutex gMutex; + static std::vector gJobList; + static String gTemplateContent; + + + class Chart + { + public: + typedef SmartPtr Ptr; + typedef std::vector Vector; + + class Curve + { + public: + typedef SmartPtr Ptr; + typedef std::vector Vector; + public: + Curve() : + showPoints(true), + fill(true) + { + } + + public: + CString<16,false> type; + String caption; + String::Vector x; + String::Vector y; + bool showPoints; + bool fill; + }; + + public: + Chart(TiXmlElement* parentNode) : + xmlNode(parentNode), + legendPosition("ne") + { + } + + void generateJS(Clob& script, unsigned int id) const + { + script.clear(); + script + << "$(function () {\n"; + script + << "\t$.plot($(\"#dvchart_" << id << "\"), [\n"; + + for (unsigned int i = 0; i != curves.size(); ++i) + { + const Curve& curve = *(curves[i]); + if (i) + script << ",\n"; + script + << "\t\t\{\n" + << "\t\t\tlabel: \"" << curve.caption << "\",\n" + << "\t\t\tdata: ["; + + unsigned int max = static_cast(Math::Max(curve.x.size(), curve.y.size())); + for (unsigned int pt = 0; pt != max; ++pt) + { + if (pt) + script << ", "; + script << '['; + if (pt < curve.x.size()) + script << curve.x[pt]; + else + script << '0'; + script << ','; + if (pt < curve.y.size()) + script << curve.y[pt]; + else + script << '0'; + script << ']'; + } + script << "],\n"; + script << "\t\t\t" << curve.type << ": { show: true, fill: " + << ((curve.fill) ? "true" : "false") + << " }"; + if (curve.type == "lines" && curve.showPoints) + script << ",\n\t\t\tpoints: { show: true }"; + script << '\n'; + + script + << "\t\t}"; + } + script << '\n'; + + script + << "\t],\n" + << "\t{\n" + << "\t\txaxis: {\n" + << "\t\t},\n" + << "\t\tyaxis: {\n" + << "\t\t},\n" + << "\t\tseries: {\n" + << "\t\t},\n" + << "\t\tlegend: {\n" + << "\t\t\tposition: \"" << legendPosition << "\",\n" + << "\t\t},\n" + << "\t\tgrid: {\n" + << "\t\t\tborderWidth: 1,\n" + << "\t\t\tclickable: true,\n" + << "\t\t\thoverable: true,\n" + << "\t\t\tborderColor: \"rgb(190,190,190)\",\n" + << "\t\t\tautoHighlight: true\n" + << "\t\t}\n" + << "\t});\n" + << "});"; + } + + public: + //! The original XML node + TiXmlElement* xmlNode; + //! + Curve::Ptr currentCurve; + //! + Curve::Vector curves; + //! Legend position + CString<8,false> legendPosition; + }; + + + class XMLVisitor : public TiXmlVisitor + { + public: + //! \name Constructor + //@{ + /*! + ** \brief Constructor + */ + XMLVisitor(ArticleData& article, TiXmlDocument& document); + //! Destructor + virtual ~XMLVisitor(); + //@} + + virtual bool VisitEnter(const TiXmlDocument& /*doc*/ ); + + virtual bool VisitExit(const TiXmlDocument& /*doc*/); + + virtual bool VisitEnter(const TiXmlElement& element, const TiXmlAttribute* attr); + + virtual bool VisitExit(const TiXmlElement& element); + + virtual bool Visit(const TiXmlDeclaration& /*declaration*/); + virtual bool Visit(const TiXmlText& /*text*/); + virtual bool Visit(const TiXmlComment& /*comment*/); + virtual bool Visit(const TiXmlUnknown& /*unknown*/); + + void createAllCharts(); + void deleteUselessTags(); + + private: + //! XML document + TiXmlDocument& pDocument; + ArticleData& pArticle; + std::vector pToDelete; + + //! \name Charting + //@{ + Chart::Ptr pCurrentChart; + Chart::Vector pCharts; + //@} + + unsigned int pCurrentTOCItemIndex; + unsigned int pH2Index; + unsigned int pH3Index; + + }; // class XMLVisitor + + + + + + XMLVisitor::XMLVisitor(ArticleData& article, TiXmlDocument& document) : + pDocument(document), + pArticle(article), + pCurrentTOCItemIndex(0), + pH2Index(0), + pH3Index(0) + { + } + + + XMLVisitor::~XMLVisitor() + { + } + + + bool XMLVisitor::VisitEnter(const TiXmlDocument& /*doc*/ ) + { + return true; + } + + + bool XMLVisitor::VisitExit(const TiXmlDocument& /*doc*/) + { + return true; + } + + + bool XMLVisitor::VisitEnter(const TiXmlElement& element, const TiXmlAttribute* /*attr*/) + { + const TIXML_STRING& name = element.ValueTStr(); + const Dictionary::Tag tag = name.c_str(); + TiXmlElement* e = const_cast(&element); + + // Attributes + TiXmlAttribute* attr = const_cast(element.FirstAttribute()); + for (; attr; attr = attr->Next()) + { + const AnyString e = attr->Value(); + if (e.contains("%%7B") || e.contains("%%7D")) + { + String s = e; + s.replace("%%7B", "{"); + s.replace("%%7D", "}"); + attr->SetValue(s.c_str()); + } + } + if (!(!pCurrentChart)) + { + if (tag == "curve") + { + pCurrentChart->currentCurve = new Chart::Curve(); + pCurrentChart->curves.push_back(pCurrentChart->currentCurve); + pCurrentChart->currentCurve->caption = element.Attribute("label"); + const AnyString type = element.Attribute("type"); + if (!type || (type != "lines" && type != "bars" && type != "points")) + { + if (not type.empty()) + logs.warning() << pArticle.relativeFilename << ": invalid curve type, got '" << type << "'"; + pCurrentChart->currentCurve->type = "lines"; + } + else + pCurrentChart->currentCurve->type = type; + + const AnyString fill = element.Attribute("fill"); + if (not fill.empty()) + pCurrentChart->currentCurve->fill = fill.to(); + + return true; + } + if (tag == "legend") + { + const AnyString pos = element.Attribute("position"); + if (not pos.empty()) + { + if (pos != "ne" && pos != "nw" && pos != "se" && pos != "sw") + { + logs.warning() << pArticle.relativeFilename << ": invalid legend position (valid values: ne, nw, se, sw)"; + return false; + } + pCurrentChart->legendPosition = pos; + } + return true; + } + + if (!pCurrentChart->currentCurve) + return false; + if (tag == "x") + { + const AnyString value = element.GetText(); + if (not value.empty()) + value.split(pCurrentChart->currentCurve->x, " ,;\t\r\n|"); + return true; + } + if (tag == "y") + { + const AnyString value = element.GetText(); + if (not value.empty()) + value.split(pCurrentChart->currentCurve->y, " ,;\t\r\n|"); + return true; + } + + // Invalid tag within a chart + return false; + } + if (tag == "chart") + { + // This node must be removed at the final end + pToDelete.push_back(const_cast(&element)); + pCurrentChart = new Chart(const_cast(&element)); + pCharts.push_back(pCurrentChart); + return true; + } + if (tag == "title" || tag == "tag" || tag.startsWith("pragma:")) + { + pToDelete.push_back(const_cast(&element)); + return true; + } + if (tag == "h2" || tag == "h3") + { + // Forcing the id + if (pCurrentTOCItemIndex < pArticle.tocItems.size()) + { + e->SetAttribute("id", pArticle.tocItems[pCurrentTOCItemIndex]->hrefID.c_str()); + ++pCurrentTOCItemIndex; + } + if (tag[1] == '2') + { + ++pH2Index; + pH3Index = 0; + } + else + ++pH3Index; + return true; + } + if (tag == "source") + { + CString<16,false> type = e->Attribute("type"); + e->SetValue("pre"); + e->RemoveAttribute("type"); + + type.toLower(); + if (type != "none") + { + if (!type || type == "cpp" || type == "c++") + e->SetAttribute("class", "cpp"); + else if (type == "lua") + e->SetAttribute("class", "lua"); + else if (type == "java") + e->SetAttribute("class", "java"); + } + } + return true; + } + + + void XMLVisitor::deleteUselessTags() + { + if (pToDelete.empty()) + return; + // start from the last item to delete + unsigned int i = (unsigned int) pToDelete.size(); + do + { + --i; + TiXmlElement* element = pToDelete[i]; + element->Parent()->RemoveChild(element); + } + while (i); + } + + + bool XMLVisitor::Visit(const TiXmlText&) + { + /* + const TIXML_STRING& name = text.ValueTStr(); + String v = name.c_str(); + if (v.contains("rarr")) + std::cout << v << std::endl; + */ + return true; + } + + + bool XMLVisitor::Visit(const TiXmlComment&) + { + return true; + } + + + bool XMLVisitor::Visit(const TiXmlDeclaration&) + { + return true; + } + + + bool XMLVisitor::Visit(const TiXmlUnknown&) + { + return true; + } + + + + bool XMLVisitor::VisitExit(const TiXmlElement& element) + { + const TIXML_STRING& name = element.ValueTStr(); + const Dictionary::Tag tag = name.c_str(); + + if (!(!pCurrentChart)) + { + if (tag == "chart") + { + pCurrentChart = nullptr; + return true; + } + if (tag == "curve") + { + if (!(!pCurrentChart)) + pCurrentChart->currentCurve = nullptr; + return true; + } + } + return true; + } + + + void XMLVisitor::createAllCharts() + { + if (pCharts.empty()) + return; + Clob script; + String id; + for (unsigned int i = 0; i != pCharts.size(); ++i) + { + id.clear() << "dvchart_" << i; + const Chart& chart = *(pCharts[i]); + chart.generateJS(script, i); + + TiXmlElement td("td"); + td.SetAttribute("id", id.c_str()); + td.SetAttribute("style", "width:600px;height:300px"); + + TiXmlElement emptytd("td"); + emptytd.InsertEndChild(TiXmlText(" ")); + + TiXmlElement tr("tr"); + tr.InsertEndChild(emptytd); + tr.InsertEndChild(td); + tr.InsertEndChild(emptytd); + + TiXmlElement table("table"); + table.SetAttribute("class", "nostyle"); + table.SetAttribute("style", "width:100%"); + table.InsertEndChild(tr); + chart.xmlNode->Parent()->InsertBeforeChild(chart.xmlNode, table); + + TiXmlElement js("script"); + js.SetAttribute("type", "text/javascript"); + TiXmlText text(script.c_str()); + js.InsertEndChild(text); + chart.xmlNode->Parent()->InsertBeforeChild(chart.xmlNode, js); + } + } + + + +} // anonymous namespace + + +void JobWriter::SEOBuildAllTermReferences() +{ + String filename; + filename << Program::htdocs << SEP << "seo" << SEP << "data.js"; + IO::File::Stream file; + + if (file.openRW(filename)) + { + Clob data; + data << "if(1){var f=function(id,n,d) {SEO.termNames[n]=id;SEO.terms[id]=d};"; + DocIndex::BuildSEOTermReference(data); + data << " }\n"; + file << data; + } + else + logs.error() << "impossible to write " << filename; +} + + + +void JobWriter::Add(const String& input, const String& htdocs, const ArticleData& article) +{ + // Preparing a new job + // The article content will be copied + JobWriter* job = new JobWriter(input, htdocs, article); + // The new article + const ArticleData& newArticle = job->article(); + + // Keeping the new job in a safe place, for later use + gMutex.lock(); + gJobList.push_back(job); + gMutex.unlock(); + + // Preparing the global word dictionary + unsigned int registrationCount = 0; + if (!newArticle.wordCount.empty()) + { + // The article ID + int articleID = DocIndex::FindArticleID(newArticle.htdocsFilename); + + // All word ids for the page + Dictionary::WordID* wordIDs = new Dictionary::WordID[newArticle.wordCount.size()]; + float* weights = new float[newArticle.wordCount.size()]; + int* countInArticle = new int[newArticle.wordCount.size()]; + + // Registering all new terms + unsigned int wIx = 0; + const Dictionary::WordsCount::const_iterator end = newArticle.wordCount.end(); + Dictionary::WordsCount::const_iterator i = newArticle.wordCount.begin(); + for (; i != end; ++i, ++wIx) + { + // The word itself + const Dictionary::Word& word = i->first; + const Dictionary::WordStat& stats = i->second; + + countInArticle[wIx] = stats.count; + weights[wIx] = stats.coeff; + + Dictionary::WordID newWordID = Dictionary::FindWordID(word); + if (newWordID < 0) + { + Yuni::MutexLocker locker(Dictionary::mutex); + ++registrationCount; + newWordID = DocIndex::RegisterWordReference(word); + Dictionary::allWords[word] = newWordID; + wordIDs[wIx] = newWordID; + } + else + wordIDs[wIx] = newWordID; + } + + DocIndex::RegisterWordIDsForASingleArticle(articleID, wordIDs, countInArticle, weights, wIx); + + delete[] weights; + delete[] countInArticle; + delete[] wordIDs; + } + + if (registrationCount && Program::debug) + logs.info() << " :: registered " << registrationCount << " terms"; +} + + +void JobWriter::PushAllInQueue() +{ + gMutex.lock(); + for (unsigned int i = 0; i != gJobList.size(); ++i) + queueService += gJobList[i]; + gJobList.clear(); + gMutex.unlock(); +} + + +bool JobWriter::ReadTemplateIndex() +{ + PrepareWebPageHtml(gTemplateContent); + return true; +} + + +JobWriter::JobWriter(const String& input, const String& htdocs, const ArticleData& article) : + pInput(input), + pHtdocs(htdocs), + pArticle(article), + pArticleID(-1) +{ +} + + +JobWriter::~JobWriter() +{ +} + + +void JobWriter::prepareVariables(const String& filenameInHtdocs) +{ + String tmp; + pVars.clear(); + + //! @{MODIFIED} + { + pVars["MODIFIED_TIMESTAMP"] = pArticle.modificationTime; + DateTime::TimestampToString(pVars["MODIFIED"], "%A, %B %e, %Y", pArticle.modificationTime); + } + //! @{MODIFIED_ISO8601} + { + DateTime::TimestampToString(pVars["MODIFIED_ISO8601"], "%Y-%m-%d", pArticle.modificationTime); + } + + // @{LANG} + pVars["LANG"] = pArticle.language; + + // @{INDEX} + if (Program::shortUrl) + pVars["INDEX"] = nullptr; + else + pVars["INDEX"] = Program::indexFilename; + + // @{TITLE} + pVars["TITLE"] = pArticle.title; + + // @{DESCRIPTION} + pVars["DESCRIPTION"] = ""; + + TiXmlDocument doc; + doc.SetTabSize(4); + + if (not pArticle.originalFilename.empty()) + { + if (!doc.LoadFile(pArticle.originalFilename.c_str(), TIXML_ENCODING_UTF8)) + { + logs.error() << pArticle.relativeFilename << ", l" << doc.ErrorRow() << ": " << doc.ErrorDesc(); + return; + } + { + XMLVisitor visitor(pArticle, doc); + doc.Accept(&visitor); + visitor.createAllCharts(); + visitor.deleteUselessTags(); + } + } + + // @{ROOT} + String& root = pVars["ROOT"]; + { + unsigned int c = pArticle.htdocsFilename.countChar('/'); + if (!c) + root = "."; + else + { + tmp.clear() << ".."; + for (unsigned int i = 1; i != c; ++i) + tmp << "/.."; + root = tmp; + } + } + + // @{URL} + pVars["URL"] = pArticle.htdocsFilename; + + // @{URL_PARTS} + { + String address; + if (pArticle.accessPath.empty()) + { + String::Vector list; + pArticle.htdocsFilename.split(list, "/"); + tmp.clear(); + String path; + String caption; + if (!list.empty()) + { + for (unsigned int i = 0; i < list.size(); ++i) + { + tmp << '/' << list[i]; + path.clear() << root << tmp; + if (!i) + continue; + address << "
  • "; + caption.clear(); + if (!DocIndex::AppendArticleTitleFromPath(caption, tmp)) + caption << list[i]; + address << caption << ""; + + IO::ExtractFilePath(path, tmp); + DocIndex::AppendChildrenList(address, path, caption); + address << "
  • \n"; + } + } + } + else + { + if (pArticle.accessPath == "quicklinks") + { + address << "
  • Documentation
  • \n"; + address << "
  • Downloads
  • \n"; + address << "
  • Developers
  • \n"; + address << "
  • Links
  • \n"; + address << "
  • Contacts
  • \n"; + } + } + pVars["URL_PARTS"] = address; + } + + // @{TAGS_BEGIN,...} + // The tags may have been changed because of the dependancies + pArticle.reloadTagsFromDatabase(); + if (pArticle.tags.empty()) + { + pVars["TAGS_BEGIN"] = ""; + pVars["TAGS_LIST"] = nullptr; + pVars["KEYWORDS"] = nullptr; + } + else + { + pVars["TAGS_BEGIN"] = nullptr; + pVars["TAGS_END"] = nullptr; + String& list = pVars["TAGS_LIST"]; + String& keywords = pVars["KEYWORDS"]; + list << "\n\n\n\n\t
    \n"; + switch (pArticle.tags.size()) + { + case 0: list << "0 tag : ";break; + case 1: list << "1 tag : ";break; + default: list << pArticle.tags.size() << " tags : ";break; + } + + Dictionary::TagSet::const_iterator end = pArticle.tags.end(); + bool first = true; + for (Dictionary::TagSet::const_iterator i = pArticle.tags.begin(); i != end; ++i) + { + if (!first) + { + list += "\t\t, "; + keywords += ", "; + } + else + list += "\t\t"; + list << "" << *i << "\n"; + keywords += *i; + first = false; + } + list << "\t
    \n\n"; + } + + // @{TOC_...} + if (pArticle.showTOC && pArticle.tocItems.size() > 1) + { + pVars["TOC_BEGIN"] = nullptr; + pVars["TOC_END"] = nullptr; + } + else + { + pVars["TOC_BEGIN"] = ""; + } + + // @{TOC_CONTENT} + if (pArticle.tocItems.size() != 0 && pArticle.showTOC) + { + tmp.clear(); + tmp << "
      \n"; + bool hasOL = false; + for (unsigned int i = 0; i != pArticle.tocItems.size(); ++i) + { + const ArticleData::TOCItem& item = *pArticle.tocItems[i]; + if (item.level == 2) + { + if (!hasOL) + { + hasOL = true; + tmp << "\t
        \n"; + } + tmp << "\t\t
      1. " + << item.caption << "
      2. \n"; + if (i + 1 == pArticle.tocItems.size()) + tmp << "\t
      \n\t\n"; + } + else + { + if (i) + { + if (hasOL) + tmp << "\t
    \n"; + tmp << "\t\n"; + } + tmp << "\t
  • " + << item.caption << "\n"; + hasOL = false; + if (i + 1 == pArticle.tocItems.size()) + tmp << "\t
  • \n"; + } + } + tmp << "\n"; + pVars["TOC_CONTENT"] = tmp; + } + else + pVars["TOC_CONTENT"].clear(); + + + // Quick links + if (pArticle.showQuickLinks) + { + pVars["QUICKLINKS_BEGIN"] = ""; + pVars["QUICKLINKS_END"] = ""; + } + else + { + pVars["QUICKLINKS_BEGIN"] = ""; + } + + // @{CONTENT} + if (not pArticle.originalFilename.empty()) + { + if (IO::Directory::System::Temporary(tmp)) + { + tmp << SEP << "yuni-doc-tmp-"; + Hash::Checksum::MD5 md5; + tmp << md5[filenameInHtdocs]; + if (Program::debug) + logs.info() << " :: writing " << tmp; + doc.SaveFile(tmp.c_str()); + String srcContent; + IO::File::LoadFromFile(srcContent, tmp); + IO::File::Delete(tmp); + + pVars["CONTENT"] = srcContent; + } + else + { + pVars["CONTENT"] = nullptr; + logs.error() << "impossible to retrieve the temporary folder location"; + } + } + else + pVars["CONTENT"] = nullptr; + + // @{DIRECTORY_INPUT} + if (not pArticle.directoryIndex.empty()) + { + Clob data; + DocIndex::BuildDirectoryIndex(data, pArticle.directoryIndex); + pVars["DIRECTORY_INDEX"] = data; + } + else + pVars["DIRECTORY_INDEX"] = ""; +} + + +bool JobWriter::articleIDIndatabase() +{ + pArticleID = DocIndex::FindArticleID(pArticle.htdocsFilename); + return (pArticleID >= 0); +} + + +void JobWriter::onExecute() +{ + if (!articleIDIndatabase()) + return; + + // temporary string + String key; + + // Looking for the target filename + String filenameInHtdocs; + { + key = pHtdocs; + if (pArticle.htdocsFilename != "/") + { + key << SEP << pArticle.htdocsFilename; + # ifdef YUNI_OS_WINDOWS + key.replace('/', '\\'); + # endif + if (!IO::Directory::Create(key)) + { + logs.error() << "impossible to create the directory " << key; + return; + } + } + + key << SEP << Program::indexFilename; + IO::Normalize(filenameInHtdocs, key); + } + + // Console verbose / debug + { + if (Program::debug) + logs.info() << "generating " << pArticle.htdocsFilename << " -> " << filenameInHtdocs; + else + { + if (Program::verbose) + logs.info() << "generating " << pArticle.htdocsFilename; + } + } + + // Prepare all variables + prepareVariables(filenameInHtdocs); + + CString<8192> content = gTemplateContent; + + String::Size offset = 0; + do + { + offset = content.find("@{", offset); + if (offset < content.size()) + { + String::Size end = content.find('}', offset + 2); + if (end < content.size()) + { + if (end - offset < 64) + { + unsigned int length = end - offset + 1; + if (length < 4) + { + offset += 2; + logs.warning() << pArticle.relativeFilename << ": empty variable name"; + continue; + } + key.assign(content.c_str() + offset + 2, length - 3); + Variables::const_iterator i = pVars.find(key); + if (i != pVars.end()) + { + content.erase(offset, length); + content.insert(offset, i->second); + } + else + { + offset += 2; + logs.warning() << pArticle.relativeFilename << ": unknown variable '" << key << "'"; + } + continue; + } + else + { + logs.warning() << pArticle.relativeFilename << ": variable name too long"; + offset += 2; + continue; + } + } + else + logs.warning() << pArticle.relativeFilename << ": invalid variable definition"; + } + break; + } + while (true); + + // Replace all pseudo linefeed + content.replace(" ", "\n"); + content.replace(" ", "\t"); + content.replace(""", "\""); + + if (!IO::File::SetContent(filenameInHtdocs, content)) + { + logs.error() << "impossible to generate '" << pArticle.htdocsFilename + << "' into '" << filenameInHtdocs << "'"; + } +} + + + diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/job-writer.h b/src/ext/yuni/src/tools/yuni-docmake/make/job-writer.h new file mode 100644 index 0000000000..1b12dc56e3 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/job-writer.h @@ -0,0 +1,61 @@ +#ifndef __YUNI_DOCMAKE_JOB_WRITER_H__ +# define __YUNI_DOCMAKE_JOB_WRITER_H__ + +# include +# include +# include +# include +# include +# include "article.h" + + + +class JobWriter : public Yuni::Job::IJob +{ +public: + static void SEOBuildAllTermReferences(); + +public: + static void Add(const Yuni::String& input, const Yuni::String& htdocs, const ArticleData& article); + + static void PushAllInQueue(); + + static bool ReadTemplateIndex(); + +public: + //! \name Constructor & Destructor + //@{ + /*! + ** \brief Constructor + */ + JobWriter(const Yuni::String& input, const Yuni::String& htdocs, const ArticleData& article); + //! Destructor + virtual ~JobWriter(); + //@} + + + const ArticleData& article() const {return pArticle;} + +private: + virtual void onExecute(); + + bool articleIDIndatabase(); + void prepareVariables(const Yuni::String& filenameInHtdocs); + +private: + typedef std::map Variables; + +private: + const Yuni::String& pInput; + const Yuni::String& pHtdocs; + ArticleData pArticle; + Variables pVars; + //! Article ID in database + int pArticleID; + +}; // class CompileJob + + + + +#endif // __YUNI_DOCMAKE_JOB_WRITER_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/job.cpp b/src/ext/yuni/src/tools/yuni-docmake/make/job.cpp new file mode 100644 index 0000000000..48592c4f90 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/job.cpp @@ -0,0 +1,676 @@ + +#include "job.h" +#include "../logs.h" +#include +#include "../tinyxml/tinyxml.h" +#include +#include +#include "indexes.h" +#include "job-writer.h" +#include "program.h" + + +#define SEP IO::Separator + +using namespace Yuni; +using namespace Yuni::Tool::DocMake; + + +Yuni::Job::QueueService<> queueService; + + + +namespace // anonymous +{ + + class XMLVisitor : public TiXmlVisitor + { + public: + //! \name Constructor + //@{ + /*! + ** \brief Constructor + */ + XMLVisitor(ArticleData& article, TiXmlDocument& document); + //! Destructor + virtual ~XMLVisitor(); + //@} + + virtual bool VisitEnter(const TiXmlDocument& /*doc*/ ); + + virtual bool VisitExit(const TiXmlDocument& /*doc*/); + + virtual bool VisitEnter(const TiXmlElement& element, const TiXmlAttribute* attr); + + virtual bool VisitExit(const TiXmlElement& element); + + virtual bool Visit(const TiXmlDeclaration& /*declaration*/); + virtual bool Visit(const TiXmlText& /*text*/); + virtual bool Visit(const TiXmlComment& /*comment*/); + virtual bool Visit(const TiXmlUnknown& /*unknown*/); + + bool error() const {return pArticle.error;} + + private: + void pushCoeff(float coeff); + + void popCoeff(); + + void pushCoeffFromString(const TIXML_STRING& name); + + void seo(const AnyString& string); + + private: + //! + float pCoeff; + + //! Within a paragraph + bool pWithinParagraph; + //! XML document + TiXmlDocument& pDocument; + //! XML Filename + const String& pFilename; + //! Current state + ArticleData::State pState; + ArticleData& pArticle; + + //! Last TOC level (1: h2, 2: h3...) + unsigned int pLastTOCLevel; + String pTOCCaption; + + enum { coeffStackMax = 256 }; + float pCoeffStack[coeffStackMax]; + unsigned int pCoeffStackIndex; + }; // class XMLVisitor + + + + + + XMLVisitor::XMLVisitor(ArticleData& article, TiXmlDocument& document) : + pCoeff(1.f), + pWithinParagraph(false), + pDocument(document), + pFilename(article.relativeFilename), + pState(ArticleData::stNone), + pArticle(article), + pLastTOCLevel(0), + pCoeffStackIndex(0) + { + memset(pCoeffStack, 0, sizeof(pCoeffStack)); + } + + + XMLVisitor::~XMLVisitor() + { + } + + + bool XMLVisitor::VisitEnter(const TiXmlDocument& /*doc*/ ) + { + return true; + } + + + bool XMLVisitor::VisitExit(const TiXmlDocument& /*doc*/) + { + return true; + } + + + bool XMLVisitor::VisitEnter(const TiXmlElement& element, const TiXmlAttribute* /*attr*/) + { + const TIXML_STRING name = element.ValueTStr(); + const Dictionary::Tag tag = name.c_str(); + + pushCoeffFromString(name); + switch (pState) + { + case ArticleData::stNone: + { + if (tag.startsWith("pragma:")) + { + bool value; + if (tag == "pragma:tag") + { + const AnyString string1 = element.Attribute("value"); + pArticle.insertTags(string1); + const AnyString string2 = element.Attribute("name"); + pArticle.insertTags(string2); + } + else if (tag == "pragma:toc") + { + if (TIXML_SUCCESS == element.QueryBoolAttribute("value", &value)) + logs.warning() << pFilename << ": pragma:toc: the field value is deprecated"; + if (TIXML_SUCCESS == element.QueryBoolAttribute("visible", &value)) + pArticle.showTOC = value; + } + else if (tag == "pragma:lang") + { + // see http://www.seoconsultants.com/meta-tags/language + const AnyString string = element.Attribute("value"); + pArticle.language = string; + pArticle.language.trim(); + pArticle.language.toLower(); + } + else if (tag == "pragma:quicklinks") + { + if (TIXML_SUCCESS == element.QueryBoolAttribute("value", &value)) + pArticle.showQuickLinks = value; + else + logs.error() << pFilename << ": invalid value for pragma:quicklinks"; + } + else if (tag == "pragma:history") + { + if (TIXML_SUCCESS == element.QueryBoolAttribute("value", &value)) + pArticle.showHistory = value; + else + logs.error() << pFilename << ": invalid value for pragma:history"; + } + else if (tag == "pragma:directoryindex") + { + const AnyString string = element.Attribute("src"); + if (not string.empty()) + { + String src = pArticle.htdocsFilename; + src << SEP << string; + IO::Normalize(pArticle.directoryIndex, src); + } + else + { + String src = pArticle.htdocsFilename; + src << SEP << "."; + IO::Normalize(pArticle.directoryIndex, src); + } + + const CString<42,false> content = element.Attribute("content"); + if (not content.empty()) + { + if (content == "nofollow") + pArticle.directoryIndexContent = ArticleData::dicNoFollow; + else if (content == "noindex") + pArticle.directoryIndexContent = ArticleData::dicNoIndex; + else if (content == "all") + pArticle.directoryIndexContent = ArticleData::dicAll; + else + logs.error() << "invalid directory index content flag (expected: 'all', 'nofollow' or 'noindex')"; + } + + if (!string && !content) + logs.warning() << pFilename << ": pragma:directoryindex: missing attribute 'src' or 'content'"; + } + else if (tag == "pragma:accesspath") + { + CString<32,false> string = element.Attribute("value"); + string.toLower(); + if (string != "quicklinks") + logs.error() << pFilename << ": invalid access path overlay"; + else + pArticle.accessPath = string; + } + else if (tag == "pragma:weight") + { + CString<32,false> string = element.Attribute("value"); + float weight; + if (!string.to(weight) || weight < 0.f || weight > 10.f) + logs.error() << pFilename << ": invalid page weight (decimal, range 0..10)"; + else + pArticle.pageWeight = weight; + } + else + logs.warning() << pFilename << ": unknown setting: " << tag; + } + else + { + if (tag == "title") + { + pState = ArticleData::stTitle; + pArticle.title.clear(); + } + else if (tag == "h2") + { + pLastTOCLevel = 1; + pTOCCaption.clear(); + pState = ArticleData::stTOCItem; + } + else if (tag == "h3") + { + pTOCCaption.clear(); + if (!pLastTOCLevel) + { + logs.error() << "found h3 without h2. Adding an empty h2"; + pArticle.tocAppend(1, pTOCCaption); + } + pLastTOCLevel = 2; + pState = ArticleData::stTOCItem; + } + else if (tag == "h1") + { + logs.error() << "The tag h1 is reserved for the page title"; + return false; + } + else if (tag == "tag") + { + const AnyString string1 = element.Attribute("value"); + pArticle.insertTags(string1); + const AnyString string2 = element.Attribute("name"); + pArticle.insertTags(string2); + } + } + if (pWithinParagraph && pArticle.allowedTagsInParagraph.find(tag) == pArticle.allowedTagsInParagraph.end()) + { + logs.error() << pFilename << ": invalid tag within a paragraph"; + pArticle.error = true; + return false; + } + if (tag == "p") + pWithinParagraph = true; + break; + } + case ArticleData::stTitle: + { + logs.error() << pFilename << ": invalid nested tag for 'title'"; + pArticle.error = true; + return false; + } + case ArticleData::stTOCItem: + { + if (tag == "h2" || tag == "h3") + { + logs.error() << "invalid nested header (h2,h3)"; + return false; + } + break; + } + default: + break; + } + return true; + } + + + bool XMLVisitor::Visit(const TiXmlText& node) + { + const TIXML_STRING& text = node.ValueTStr(); + + switch (pState) + { + case ArticleData::stTitle: + { + assert(pArticle.title.capacity() < 1024); + if (pArticle.title.size() + (unsigned int) text.size() > 512) + logs.error() << "invalid title length (> 512)"; + else + { + if (!pArticle.title.empty() && pArticle.title.last() != ' ') + pArticle.title += ' '; + pArticle.title.append(text.c_str(), (unsigned int)text.size()); + pArticle.title.trim(); + } + break; + } + case ArticleData::stTOCItem: + { + assert(pTOCCaption.capacity() < 1024); + if (pTOCCaption.size() + text.size() > 512) + logs.error() << "invalid caption length (>512)"; + else + { + if (!pTOCCaption.empty() && pTOCCaption.last() != ' ') + pTOCCaption += ' '; + pTOCCaption.append(text.c_str(), (unsigned int)text.size()); + pTOCCaption.trim(); + } + break; + } + default: + if (!text.empty()) + { + AnyString adapter; + adapter.adapt(text.c_str(), (unsigned int) text.size()); + seo(adapter); + } + break; + } + return true; + } + + + bool XMLVisitor::Visit(const TiXmlComment&) + { + return true; + } + + + bool XMLVisitor::Visit(const TiXmlDeclaration&) + { + return true; + } + + + bool XMLVisitor::Visit(const TiXmlUnknown&) + { + return true; + } + + + + bool XMLVisitor::VisitExit(const TiXmlElement& element) + { + const TIXML_STRING& name = element.ValueTStr(); + + switch (pState) + { + case ArticleData::stNone: + { + if (name == "p") + pWithinParagraph = false; + } + case ArticleData::stTitle: + { + if (name == "title") + { + pState = ArticleData::stNone; + AnyString s = pArticle.title; + + float oldCoeff = pCoeff; + pCoeff = 5.f; + seo(s); + pCoeff = oldCoeff; + } + break; + } + case ArticleData::stTOCItem: + { + if (name == "h2" || name == "h3") + { + pState = ArticleData::stNone; + float oldCoeff = pCoeff; + pCoeff = (pLastTOCLevel == 1) ? 3.f : 2.f; + AnyString s = pTOCCaption; + seo(s); + pCoeff = oldCoeff; + pArticle.tocAppend(pLastTOCLevel, pTOCCaption); + pTOCCaption.clear(); + } + break; + } + default: + break; + } + + popCoeff(); + return true; + } + + + void XMLVisitor::pushCoeff(float coeff) + { + if (pCoeffStackIndex < coeffStackMax) + pCoeffStack[pCoeffStackIndex] = coeff; + ++pCoeffStackIndex; + pCoeff *= coeff; + } + + + void XMLVisitor::popCoeff() + { + if (pCoeffStack) + { + pCoeff = 1.f; + for (unsigned int i = 0; i != pCoeffStackIndex; ++i) + pCoeff *= pCoeffStack[i]; + --pCoeffStackIndex; + } + else + { + pCoeff = 1.f; + pCoeffStackIndex = 0; + } + } + + + void XMLVisitor::pushCoeffFromString(const TIXML_STRING& name) + { + if (name.empty()) + { + pushCoeff(1.f); + return; + } + if (name == "h2") + { + pushCoeff(3.f); + return; + } + if (name == "h3") + { + pushCoeff(2.0f); + return; + } + if (name == "h4") + { + pushCoeff(1.7f); + return; + } + if (name == "h5") + { + pushCoeff(1.60f); + return; + } + if (name == "h6") + { + pushCoeff(1.55f); + return; + } + if (name == "b") + { + pushCoeff(1.1f); + return; + } + if (name == "i") + { + pushCoeff(1.05f); + return; + } + if (name == "var") + { + pushCoeff(0.f); + return; + } + if (name == "pre") + { + pushCoeff(0.95f); + return; + } + if (name == "code") + { + pushCoeff(0.95f); + return; + } + pushCoeff(1.f); + } + + + void XMLVisitor::seo(const AnyString& string) + { + if (pCoeff < 0.1f) + return; + typedef Yuni::LinkedList List; + List list; + string.split(list, " \r\n\t:;!@#$%^&*()_+{}[]|\"'\\/.,?><=-"); + if (list.empty()) + return; + + Dictionary::Word word; + const List::const_iterator end = list.end(); + for (List::const_iterator i = list.begin(); i != end; ++i) + { + word = *i; + word.toLower(); + + Dictionary::WordStat& stat = pArticle.wordCount[word]; + ++stat.count; + if (pCoeff > stat.coeff) + stat.coeff = pCoeff; + } + } + + + + +} // namespace anonymous + + + + + + + + + +CompileJob::CompileJob(const Yuni::String& input, const Yuni::String& htdocs) : + pInput(input), + pHtdocs(htdocs) +{ +} + + +CompileJob::~CompileJob() +{ +} + + +bool CompileJob::extractOrder(const String& path) +{ + + // Getting the raw folder name + // For the following URL : + // /Users/milipili/projects/yuni/sources/docs/docs/src/001-en/300-developers/100-recommended-softwares/article.xml + // We will get + // /Users/milipili/projects/yuni/sources/docs/docs/src/001-en/300-developers/100-recommended-softwares + IO::ExtractFilePath(pTmp, path); + + // Looking for the final slash + const String::Size offset = pTmp.find_last_of("/\\"); + if (offset == String::npos || offset + 4 >= pTmp.size()) + return false; + // We only want to match string like /XXX-xxxxxx... + if (pTmp[offset + 4] != '-') + return false; + + // We are optimistic. The first 3 chars should be a number most of the time + CString<8,false> s; + s.resize(3); + s[2] = pTmp[offset + 3]; + s[1] = pTmp[offset + 2]; + s[0] = pTmp[offset + 1]; + if (!s.to(pArticle.order)) + return false; + return (pArticle.order < 1000u); +} + + + +void CompileJob::onExecute() +{ + String target; + unsigned int sourceCount = (unsigned int)pSources.size(); + for (unsigned int i = 0; i != sourceCount; ++i) + { + assert(i < pSources.size()); + const String& entry = pSources[i]; + + // Resetting data related to the article + pArticle.reset(); + // The original filename (absolute) + pArticle.originalFilename = entry; + // The relative filename, from the source folder + pArticle.relativeFilename.assign(entry.c_str() + pInput.size() + 1, entry.size() - pInput.size() - 1); + + // Last modification time + pArticle.modificationTime = IO::File::LastModificationTime(entry); + + // The final filename within the htdocs folder + pArticle.htdocsFilename.clear() << '/' << pArticle.relativeFilename; + pArticle.htdocsFilename.replace('\\', '/'); + { + String::Size offset = pArticle.htdocsFilename.find_last_of('/'); + if (offset != String::npos) + pArticle.htdocsFilename.resize(offset); + } + if (!pArticle.htdocsFilename) + pArticle.htdocsFilename = "/"; + + String::Size offset = 0; + do + { + offset = pArticle.htdocsFilename.find('/', offset); + if (pArticle.htdocsFilename.size() < 4 || offset > pArticle.htdocsFilename.size() - 4) + break; + ++offset; + if (pArticle.htdocsFilename[offset + 3] != '-') + break; + + bool isDigit = true; + for (unsigned int j = offset; j < offset + 3; ++j) + { + if (!String::IsDigit(pArticle.htdocsFilename[j])) + { + isDigit = false; + break; + } + } + if (isDigit) + pArticle.htdocsFilename.erase(offset, 4); + } + while (true); + + // Post analyzis about the article + if (!analyzeArticle() || pArticle.error) + continue; + + // Writing the article in the database + DocIndex::Write(pArticle); + // Preparing a new job, with a copy of the data related to the article + JobWriter::Add(pInput, pHtdocs, pArticle); + } +} + + +bool CompileJob::analyzeArticle() +{ + if (Program::verbose) + logs.info() << "reading " << pArticle.relativeFilename; + + // Article order + { + if (!extractOrder(pArticle.originalFilename)) + pArticle.order = 1000u; + if (Program::debug) + logs.info() << " :: " << pArticle.relativeFilename << ", order = " << pArticle.order; + } + + TiXmlDocument doc; + if (!doc.LoadFile(pArticle.originalFilename.c_str(), TIXML_ENCODING_UTF8)) + { + logs.error() << pArticle.relativeFilename << ", l" << doc.ErrorRow() << ": " << doc.ErrorDesc(); + return false; + } + + // Analyze the XML document + XMLVisitor visitor(pArticle, doc); + if (!doc.Accept(&visitor) || visitor.error()) + { + pArticle.error = true; + return false; + } + if (!pArticle.title) + IO::ExtractFileName(pArticle.title, pArticle.htdocsFilename, false); + + // TOC refactoring + pArticle.tocRefactoring(); + + return true; +} + + diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/job.h b/src/ext/yuni/src/tools/yuni-docmake/make/job.h new file mode 100644 index 0000000000..82c791078e --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/job.h @@ -0,0 +1,58 @@ +#ifndef __YUNI_DOCMAKE_JOB_H__ +# define __YUNI_DOCMAKE_JOB_H__ + +# include +# include +# include +# include +# include +# include "article.h" + + + +class CompileJob : public Yuni::Job::IJob +{ +public: + //! \name Constructor & Destructor + //@{ + /*! + ** \brief Constructor + */ + CompileJob(const Yuni::String& input, const Yuni::String& htdocs); + //! Destructor + virtual ~CompileJob(); + //@} + + void add(const Yuni::String& filename) {pSources.push_back(filename);} + + +private: + virtual void onExecute(); + + /*! + ** \brief + ** + */ + bool analyzeArticle(); + + /*! + ** \brief Try to extract the order contained within a given path + */ + bool extractOrder(const Yuni::String& path); + +private: + const Yuni::String& pInput; + const Yuni::String& pHtdocs; + Yuni::String::Vector pSources; + + ArticleData pArticle; + //! Temporary string + Yuni::String pTmp; + +}; // class CompileJob + + +extern Yuni::Job::QueueService<> queueService; + + +#endif // __YUNI_DOCMAKE_JOB_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/main.cpp b/src/ext/yuni/src/tools/yuni-docmake/make/main.cpp new file mode 100644 index 0000000000..39192334f4 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/main.cpp @@ -0,0 +1,80 @@ + +#include +#include "../logs.h" +#include "program.h" +#include "job.h" +#include "job-writer.h" +#include "indexes.h" +#include "../tinyxml/tinyxml.h" +#include + + + + +int main(int argc, char** argv) +{ + using namespace Yuni::Tool::DocMake; + + logs.applicationName("edln-make"); + Program program; + if (!program.parseCommandLine(argc, argv)) + return EXIT_FAILURE; + + if (!Program::quiet) + { + logs.checkpoint() << "Edalene Make"; + program.printInformations(); + } + if (!DocIndex::Open()) + return EXIT_FAILURE; + + // The condensed mode of tinyxml may removed all linefeed + TiXmlBase::SetCondenseWhiteSpace(false); + + // Preload all terms from the index db + Dictionary::PreloadFromIndexDB(); + + // Remove all entries within the database which are no longer + // available + DocIndex::RemoveNonExistingEntries(); + + // Find all articles + program.findAllSourceFiles(); + + // Extract information from all those articles + { + if (!Program::quiet) + logs.info() << "reading articles..."; + queueService.start(); + queueService.wait(); + queueService.stop(); + } + + if (!Program::quiet) + logs.info() << "building SEO data"; + DocIndex::UpdateAllSEOWeights(); + JobWriter::SEOBuildAllTermReferences(); + DocIndex::BuildSEOArticlesReference(); + + if (!Program::quiet) + logs.info() << "generating HTML files into htdocs"; + if (JobWriter::ReadTemplateIndex()) + { + JobWriter::PushAllInQueue(); + queueService.start(); + queueService.wait(); + queueService.stop(); + + if (!Program::quiet) + logs.info() << "Generating sitemap"; + DocIndex::BuildSitemap(); + } + + DocIndex::Vacuum(); + DocIndex::Close(); + + if (!Program::quiet) + logs.info() << "Done."; + return 0; +} + diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/program-find-all-source-files.cpp b/src/ext/yuni/src/tools/yuni-docmake/make/program-find-all-source-files.cpp new file mode 100644 index 0000000000..3aaa4d15a0 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/program-find-all-source-files.cpp @@ -0,0 +1,146 @@ + +#include "program.h" +#include +#include "job.h" +#include "../logs.h" +#include "indexes.h" + +#define SEP IO::Separator + + + +namespace Yuni +{ +namespace Tool +{ +namespace DocMake +{ + + + void Program::findAllSourceFiles() + { + if (!Program::quiet) + logs.notice() << "Looking for articles..."; + + unsigned int upToDateCount = 0; + std::vector jobs; + jobs.resize(nbJobs); + for (unsigned int i = 0; i != jobs.size(); ++i) + jobs[i] = new CompileJob(input, htdocs); + + IO::Directory::Info info(input); + String tmp; + unsigned int slotIndex = 0; + unsigned int count = 0; + String relative; + + for (IO::Directory::Info::recursive_iterator i = info.recursive_begin(); i != info.recursive_end(); ++i) + { + // assert + assert(!(!(*i))); + // aliases + const String& name = *i; + const String& filename = i.filename(); + + // The current element is either a folder, either a file + if (i.isFolder()) + { + // Detecting pseudo folders from source controls tools, such as + // subversion or git + if (filename.contains(".svn") || filename.contains(".git")) + continue; + + // Ok, the folder interrests us + // checking if th default article file is present + tmp.clear() << filename << SEP << "article.xml"; + if (!IO::File::Exists(tmp)) + { + logs.warning() << "missing article.xml in " << filename; + String content; + content << "\n"; + content << "\n"; + IO::File::SetContent(tmp, content); + } + } + else + { + // This should be a file + // In this phase, the only files which interrest us are all + // named 'article.xml' + if (!i.isFile() || name != "article.xml") + continue; + // A few asserts... + assert(filename.size() > input.size()); + assert(slotIndex < jobs.size()); + + // Checking for local modifications + if (!Program::clean) + { + // The relative filename + relative.assign(filename.c_str() + input.size() + 1, filename.size() - input.size() - 1); + sint64 lastWriteFromCache = DocIndex::ArticleLastModificationTimeFromCache(relative); + if (lastWriteFromCache > 0) + { + sint64 lastWrite = IO::File::LastModificationTime(filename); + // Trying to check if we really have to perform an analyzis + if (lastWriteFromCache == lastWrite) + { + ++upToDateCount; + continue; + } + } + } + + // Creating a new job for generating this article + jobs[slotIndex]->add(filename); + if (++slotIndex >= jobs.size()) + slotIndex = 0; + ++count; + } + } // for, all files and folders, recursively + + + // Statistics about the articles to generate + if (count) + { + if (!Program::quiet) + { + logs.info() << count << (count > 1 ? " articles, " : " article, ") << nbJobs + << (nbJobs > 1 ? " threads" : " thread"); + logs.info(); + } + for (unsigned int i = 0; i != jobs.size(); ++i) + queueService += jobs[i]; + } + else + { + // Actually there is nothing to do (??). Destroying all + // useless jobs + for (unsigned int i = 0; i != jobs.size(); ++i) + delete jobs[i]; + } + + if (!Program::quiet) + { + switch (upToDateCount) + { + case 0: + break; + case 1: + logs.info() << "1 article up-to-date"; + break; + default: + logs.info() << upToDateCount << " articles already up to date"; + } + } + } + + + + + +} // namespace DocMake +} // namespace Tool +} // namespace Yuni + + diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/program.cpp b/src/ext/yuni/src/tools/yuni-docmake/make/program.cpp new file mode 100644 index 0000000000..c7e85f54c1 --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/program.cpp @@ -0,0 +1,255 @@ + +#include +#include "program.h" +#include +#include +#include +#include "../logs.h" + + +#define SEP IO::Separator + + +namespace Yuni +{ +namespace Tool +{ +namespace DocMake +{ + + + unsigned int Program::nbJobs = 1; + bool Program::debug = false; + bool Program::verbose = false; + bool Program::clean = false; + bool Program::shortUrl = false; + bool Program::quiet = false; + + String Program::input; + String Program::htdocs; + String Program::indexFilename = "index.html"; + String Program::webroot = "/"; + String Program::target; + String Program::profile; + String Program::indexCacheFilename; + + + + + Program::Program() : + printVersion(false) + { + } + + + Program::~Program() + { + if (pProfileFile.opened()) + { + pProfileFile.unlock(); + pProfileFile.close(); + } + } + + + bool Program::parseCommandLine(int argc, char** argv) + { + // The total number of CPU + const unsigned int cpuCount = System::CPU::Count(); + // The most appropriate number of simultaneous jobs + nbJobs = (cpuCount > 4) ? 4 : cpuCount; + + // The Command line parser + GetOpt::Parser opts; + + // Compiler + opts.addParagraph("\nOptions:"); + opts.remainingArguments(profile); + opts.add(profile ,'p', "profile", "The profile"); + opts.add(target ,'t', "target", "target"); + opts.addFlag(clean ,'c', "clean", "Clean the index db"); + opts.addFlag(shortUrl ,'s', "short-url", "Use short url"); + opts.add(nbJobs ,'j', "jobs", String() << "Number of concurrent jobs (default: " << nbJobs + << ", max: " << cpuCount << ')'); + + // Help + opts.addParagraph("\nHelp"); + opts.addFlag(quiet, 'q', "quiet", "Do not print any message, only warnings and errors"); + opts.addFlag(verbose, ' ', "verbose", "Print any error message"); + opts.addFlag(debug, ' ', "debug", "Print debug messages"); + opts.addFlag(printVersion, 'v', "version", "Print the version and exit"); + + if (!opts(argc, argv)) + { + int status = opts.errors() ? EXIT_FAILURE /*error*/ : 0; + if (verbose || debug) + logs.error() << "Error when parsing the command line"; + exit(status); + return false; + } + + if (!profile || !IO::File::Exists(profile)) + { + if (!profile) + logs.error() << "Please provide a profile"; + else + logs.error() << "Profile not found : " << profile; + return false; + } + + // Read the profile + // The profile will be locked for prevent any concurrent use + if (!readProfile(profile)) + return false; + + if (!input) + { + logs.error() << "Please specify an input folder (--input, see --help for more informations)"; + return false; + } + if (!htdocs) + { + logs.error() << "Please specify a htdocs folder (--htdocs, see --help for more informations)"; + return false; + } + + // Normalize the input / htdocs + { + String tmp; + IO::MakeAbsolute(tmp, input); + IO::Normalize(input, tmp); + IO::MakeAbsolute(tmp, htdocs); + IO::Normalize(htdocs, tmp); + if (!indexCacheFilename) + indexCacheFilename << htdocs << SEP << ".edalene-cache.edlndb"; + IO::MakeAbsolute(tmp, indexCacheFilename); + IO::Normalize(indexCacheFilename, tmp); + + if (!IO::Directory::Exists(input)) + { + logs.error() << "IO Error: Directory does not exist: " << input; + return false; + } + if (!IO::Directory::Exists(htdocs)) + { + logs.error() << "IO Error: Directory does not exist: " << htdocs; + return false; + } + } + + nbJobs = Math::MinMax(nbJobs, 1, cpuCount); + return true; + } + + + void Program::printInformations() const + { + logs.info() << "profile : " << profile; + if (!target) + logs.info() << "target : no-target"; + else + logs.info() << "target : [" << target << ']'; + + logs.info() << " source : " << input; + logs.info() << " htdocs : " << htdocs; + logs.info() << " cache : " << indexCacheFilename; + logs.info() << " directory-index : " << indexFilename; + logs.info() << " short-url : " << (shortUrl ? "true" : "false"); + logs.info(); + } + + + bool Program::readProfile(const String& filename) + { + if (pProfileFile.opened()) + { + pProfileFile.unlock(); + pProfileFile.close(); + } + if (!pProfileFile.open(filename)) + { + logs.error() << "impossible to read the profile : " << filename; + return false; + } + + pProfileFile.lockExclusive(); + + target.toLower(); + Clob buffer; + String key; + String value; + String currentProfile; + bool skip = true; + while (pProfileFile.readline(buffer)) + { + if (!buffer) + continue; + buffer.extractKeyValue(key, value, true); + if (!key) + continue; + + if (key == "[") + { + if (!currentProfile && value != "global") + { + logs.error() << "invalid profile : the first section must be 'global' for global options"; + return false; + } + currentProfile = value; + if (value == "global") + skip = false; + else + skip = (value != target); + continue; + } + + if (skip) + continue; + + if (key == "source") + { + input = value; + continue; + } + if (key == "htdocs") + { + htdocs = value; + continue; + } + if (key == "default") + { + if (!target) + target = value; + continue; + } + if (key == "short-url") + { + shortUrl = value.to(); + continue; + } + if (key == "directory-index") + { + indexFilename = value; + continue; + } + if (key == "cache") + { + indexCacheFilename = value; + continue; + } + + logs.warning() << "profile " << profile << ": unknown key '" << key << "'"; + } + + return true; + } + + + + + + +} // namespace DocMake +} // namespace Tool +} // namespace Yuni + diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/program.h b/src/ext/yuni/src/tools/yuni-docmake/make/program.h new file mode 100644 index 0000000000..dcf4e3cfdf --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/program.h @@ -0,0 +1,75 @@ +#ifndef __YUNI_DOCMAKE_MAKE_H__ +# define __YUNI_DOCMAKE_MAKE_H__ + +# include +# include +# include + + +namespace Yuni +{ +namespace Tool +{ +namespace DocMake +{ + + + class Program + { + public: + //! \name Constructor & Destructor + //@{ + /*! + ** \brief Default constructor + */ + Program(); + //! Destructor + ~Program(); + //@} + + bool parseCommandLine(int argc, char** argv); + + void findAllSourceFiles(); + + bool readProfile(const String& filename); + + void printInformations() const; + + public: + //! The input folder + static String input; + //! The htdocs folder + static String htdocs; + //! The index filename + static String indexFilename; + //! The web root (ex: http://www.libyuni.org) + static String webroot; + //! The profile + static String profile; + //! The target + static String target; + static String indexCacheFilename; + + static unsigned int nbJobs; + bool printVersion; + static bool debug; + static bool verbose; + static bool clean; + static bool shortUrl; + static bool quiet; + + private: + //! Profile file + Yuni::IO::File::Stream pProfileFile; + + }; // class Make + + + + + +} // namespace DocMake +} // namespace Tool +} // namespace Yuni + +#endif // __YUNI_DOCMAKE_MAKE_H__ diff --git a/src/ext/yuni/src/tools/yuni-docmake/make/webpage.html b/src/ext/yuni/src/tools/yuni-docmake/make/webpage.html new file mode 100644 index 0000000000..08dcd6435e --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/make/webpage.html @@ -0,0 +1,195 @@ + + + + + + + +@{TITLE} - Yuni Framework + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    +

    @{TITLE}

    +
    +
      +
    •  
    • +@{URL_PARTS} +
    +
    +
    + + +
    + + + +@{TOC_BEGIN} +
    +
    + Table of Contents [ Show ] + +
    +
    +@{TOC_END} + + + + +
    + +@{CONTENT} +@{DIRECTORY_INDEX} +@{TAGS_LIST} + +
    + + +
    +Last modified : @{MODIFIED} +
    + + +
    + + + +
    + +
    +Yuni Framework +
    + + + + +
    + + + +
    + + + + diff --git a/src/ext/yuni/src/tools/yuni-docmake/www.libyuni.org.profile b/src/ext/yuni/src/tools/yuni-docmake/www.libyuni.org.profile new file mode 100644 index 0000000000..e925ef2cfa --- /dev/null +++ b/src/ext/yuni/src/tools/yuni-docmake/www.libyuni.org.profile @@ -0,0 +1,15 @@ +[global] +source = "../../../docs/src" +htdocs = "../../../docs/html" +cache = "../../../docs/edalene-cache.edlndb" +default = local +directory-index = index.html + + +[local] + + +[production] +webroot = "http://www.libyuni.org" +short-url = true + diff --git a/src/ext/yuni/src/yuni/CMakeLists.txt b/src/ext/yuni/src/yuni/CMakeLists.txt new file mode 100644 index 0000000000..bb74627a63 --- /dev/null +++ b/src/ext/yuni/src/yuni/CMakeLists.txt @@ -0,0 +1,196 @@ + + + +YMESSAGE("") +YMESSAGE("Modules") +YMESSAGE("") + + +# The target directory for static libs +set(LIBRARY_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/../build/${YUNI_TARGET}/lib") +set(ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../build/${YUNI_TARGET}/lib") + + + +# +# Preflight +# +set(YUNI_COMPILED_WITH_SUPPORT_FOR_OPENGL 0) +set(YUNI_COMPILED_WITH_SUPPORT_FOR_DIRECTX 0) +set(YUNI_CMAKE_ERROR 0) + + +# +# Informations for yuni-config +# +set(LIBYUNI_CONFIG_ENABLED true) + + +include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/YuniConfig.cmake") +include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/common-settings.cmake") +include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules.cmake") + + + + +if(YUNI_MODULE_CORE) + # The header yuni.h must be available + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/config.h") + # + if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/yuni.h" AND EXISTS "${CMAKE_CURRENT_BINARY_DIR}/core/string.h") + # The file config.h is at the same place that the sources. + # Consequently there is no need to specify a path + # This is necessary to help distcc as much as possible (see #340) + else() + add_definitions("-DYUNI_CONFIG_H_LOCATION=\"${CMAKE_CURRENT_BINARY_DIR}/config.h\"") + endif() + # Core + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/core/core.cmake") +endif() + +if(YUNI_MODULE_VM) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/vm.cmake") +endif() + + +if(YUNI_MODULE_VFS) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/vfs.cmake") +endif() + + +# +# Module : DBI +# +if(YUNI_MODULE_DBI) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/dbi.cmake") + #include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/dbi-sqlite.cmake") +endif() + + + +if(YUNI_MODULE_DEVICES) + LIBYUNI_CONFIG_LIB("both" "display" "yuni-static-device-display") + LIBYUNI_CONFIG_LIB("both" "mouse" "yuni-static-device-mouse") + LIBYUNI_CONFIG_DEPENDENCY("mouse" "devices") + LIBYUNI_CONFIG_LIB("both" "keyboard" "yuni-static-device-keyboard") + LIBYUNI_CONFIG_DEPENDENCY("keyboard" "devices") + + if(YUNI_MODULE_DEVICE_DISPLAY) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/device-display.cmake") + endif() + if(YUNI_MODULE_DEVICE_KEYBOARD) + endif() + if(YUNI_MODULE_DEVICE_MOUSE) + endif() +endif() + + +# +# Module : marshal +# +if(YUNI_MODULE_MARSHAL) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/marshal.cmake") +endif() + + + +# +# Module : Network +# +If(YUNI_MODULE_NET) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/net.cmake") +endif() + +# +# Module Messaging +# +if(YUNI_MODULE_MESSAGING) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/messaging.cmake") +endif() + + + +if(YUNI_MODULE_LDO) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/ldo.cmake") +endif() + +if(YUNI_MODULE_GRAPHICS) + if (YUNI_MODULE_OPENGL) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/graphics-opengl.cmake") + endif() +endif() + +if(YUNI_MODULE_UI) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/ui.cmake") +endif() + + + +if(YUNI_MODULE_MEDIA) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/media.cmake") +endif() + + +if(YUNI_MODULE_ALGORITHMS) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/algorithms.cmake") +endif(YUNI_MODULE_ALGORITHMS) + + +if(YUNI_MODULE_DOCUMENTATION) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/documentation.cmake") +endif() + + +if(YUNI_MODULE_EXTRA_UUID) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/extra-uuid.cmake") +endif() + + +if(YUNI_MODULE_PARSER) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/parser/parser.cmake") +endif() + + + +if(YUNI_TESTS) + include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/test.cmake") +endif() + + +# Generating config.h +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h) +# Generating version +CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cmake ${CMAKE_CURRENT_SOURCE_DIR}/yuni.version) + + +# +# Misc +# +add_definitions("-DYUNI_LIBRARY_STATIC") +LIBYUNI_CONFIG_DEFINITION("both" "core" "YUNI_LIBRARY_STATIC") + +include_directories(${YUNI_INCLUDE}) + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../") +if (NOT "${CMAKE_CURRENT_BINARY_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") + include_directories("${CMAKE_CURRENT_BINARY_DIR}/../") +endif() + + + +YMESSAGE("") + +if("${YUNI_CMAKE_ERROR}" GREATER 0) + YMESSAGE("") + YERROR("An error has occured. Aborting.") + YMESSAGE("") + message(FATAL_ERROR "Aborting.") +endif() + + +file("WRITE" "${CMAKE_CURRENT_BINARY_DIR}/../compiler-flags-debug-cxx" "${CMAKE_CXX_FLAGS_DEBUG}") +file("WRITE" "${CMAKE_CURRENT_BINARY_DIR}/../compiler-flags-release-cxx" "${CMAKE_CXX_FLAGS_RELEASE}") +file("WRITE" "${CMAKE_CURRENT_BINARY_DIR}/../compiler-flags-debug-cc" "${CMAKE_C_FLAGS_DEBUG}") +file("WRITE" "${CMAKE_CURRENT_BINARY_DIR}/../compiler-flags-release-cc" "${CMAKE_C_FLAGS_RELEASE}") + + diff --git a/src/ext/yuni/src/yuni/Doxygen.txt b/src/ext/yuni/src/yuni/Doxygen.txt new file mode 100644 index 0000000000..1c8451293e --- /dev/null +++ b/src/ext/yuni/src/yuni/Doxygen.txt @@ -0,0 +1,2311 @@ +# Doxyfile 1.8.7 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = LibYuni + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 1.0 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = Cross-platform C++ framework + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../../docs/doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = YES + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = YES + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = YES + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = YES + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 4 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = NO + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = YES + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = ../docs/tmp/doxygen.log + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = private \ + core/system/windows/msinttypes/inttypes.h + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = *::Private::* + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = ../samples/ + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = YES + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 2 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = YES + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /