diff options
Diffstat (limited to 'libs/cassowary')
81 files changed, 13185 insertions, 0 deletions
diff --git a/libs/cassowary/.cvsignore b/libs/cassowary/.cvsignore new file mode 100644 index 0000000000..7ac7ae08ae --- /dev/null +++ b/libs/cassowary/.cvsignore @@ -0,0 +1,15 @@ +.deps +ClReader-lex.cc +ClReader.cc +ClReader.hh +ClReader.cc.h +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +config.h +config.h.in +config.log +config.status +configure +stamp-h1 diff --git a/libs/cassowary/ANNOUNCE b/libs/cassowary/ANNOUNCE new file mode 100644 index 0000000000..e0137fa643 --- /dev/null +++ b/libs/cassowary/ANNOUNCE @@ -0,0 +1,37 @@ +Announcing the release of a free (for research use) constraint solver: + +Cassowary Constraint Solver for Smalltalk, C++, and Java +Version 0.60 + +Web Page: http://www.cs.washington.edu/research/constraints/cassowary +Distribution: ftp://ftp.cs.washington.edu:/pub/constraints/code/cassowary/ +Contact: cassowary@cs.washington.edu + +Greg J. Badros <gjb@cs.washington.edu> and +Alan Borning <borning@cs.washington.edu> +University of Washington +Computer Science and Engineering +15-December-1999 + +with Constraint Drawing Applet (CDA) by Michael Noth <noth@cs.washington.edu> + +Cassowary is an incremental constraint solving toolkit that efficiently +solves systems of linear equalities and inequalities. Constraints may +be either requirements or preferences. Client code specifies the +constraints to be maintained, and the solver updates the constrained +variables to have values that satisfy the constraints. + +A technical report is included in the distribution that describes the +algorithm, interface, and implementation of the Cassowary solver. +Additionally, the distribution contains toy sample applications written +in Smalltalk, C++, Java, and Python, and a more complex example Java +applet, the "Constraint Drawing Application". + +More information is available on our web page: + +http://www.cs.washington.edu/research/constraints/cassowary + +See README for more details on getting started using these packages. +See NEWS for a history of user-visible changes. +See LICENSE for legalese regarding use of this distribution. + diff --git a/libs/cassowary/AUTHORS b/libs/cassowary/AUTHORS new file mode 100644 index 0000000000..51d8592e6f --- /dev/null +++ b/libs/cassowary/AUTHORS @@ -0,0 +1,12 @@ +Cassowary Constraint Solving Toolkit was +Implemented by: + +Greg J. Badros <gjb@cs.washington.edu> and +Alan Borning <borning@cs.washington.edu> +University of Washington +Computer Science and Engineering +Seattle, WA 98195-2350 + +with Constraint Drawing Applet (CDA) by Michael Noth <noth@cs.washington.edu> + +Please send bug reports to cassowary@cs.washington.edu diff --git a/libs/cassowary/COPYING b/libs/cassowary/COPYING new file mode 100644 index 0000000000..d60c31a97a --- /dev/null +++ b/libs/cassowary/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the 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 a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE 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. + + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This 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 Library General +Public License instead of this License. diff --git a/libs/cassowary/COPYING.LGPL b/libs/cassowary/COPYING.LGPL new file mode 100644 index 0000000000..5f66256a83 --- /dev/null +++ b/libs/cassowary/COPYING.LGPL @@ -0,0 +1,444 @@ +GNU LESSER GENERAL PUBLIC LICENSE + +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to +share and change it. By contrast, the GNU General Public Licenses are +intended to guarantee your freedom to share and change free software--to +make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the Free +Software Foundation and other authors who decide to use it. You can use +it too, but we suggest you first think carefully about whether this +license or the ordinary General Public License is the better strategy to +use in any particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish); that you receive source code or can get it if +you want it; that you can change the software and use pieces of it in +new free programs; and that you are informed that you can do these +things. + +To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for you +if you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or +for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide complete +object files to the recipients, so that they can relink them with the +library after making changes to the library and recompiling it. And you +must show them these terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is +no warranty for the free library. Also, if the library is modified by +someone else and passed on, the recipients should know that what they +have is not the original version, so that the original author's +reputation will not be affected by problems that might be introduced by +others. + +Finally, software patents pose a constant threat to the existence of any +free program. We wish to make sure that a company cannot effectively +restrict the users of a free program by obtaining a restrictive license +from a patent holder. Therefore, we insist that any patent license +obtained for a version of the library must be consistent with the full +freedom of use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License. This license, the GNU Lesser General Public +License, applies to certain designated libraries, and is quite different +from the ordinary General Public License. We use this license for +certain libraries in order to permit linking those libraries into +non-free programs. + +When a program is linked with a library, whether statically or using a +shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the entire +combination fits its criteria of freedom. The Lesser General Public +License permits more lax criteria for linking other code with the +library. + +We call this license the "Lesser" General Public License because it does +Less to protect the user's freedom than the ordinary General Public +License. It also provides other free software developers Less of an +advantage over competing non-free programs. These disadvantages are the +reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + +For example, on rare occasions, there may be a special need to encourage +the widest possible use of a certain library, so that it becomes a +de-facto standard. To achieve this, non-free programs must be allowed to +use the library. A more frequent case is that a free library does the +same job as widely used non-free libraries. In this case, there is +little to gain by limiting the free library to free software only, so we +use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of free +software. For example, permission to use the GNU C Library in non-free +programs enables many more people to use the whole GNU operating system, +as well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is linked +with the Library has the freedom and the wherewithal to run that program +using a modified version of the Library. + +The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or other +authorized party saying it may be distributed under the terms of this +Lesser General Public License (also called "this License"). Each +licensee is addressed as "you". + +A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which +has been distributed under these terms. A "work based on the Library" +means either the Library or any derivative work under copyright law: +that is to say, a work containing the Library or a portion of it, either +verbatim or with modifications and/or translated straightforwardly into +another language. (Hereinafter, translation is included without +limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making +modifications to it. For a library, complete source code means all the +source code for all modules it contains, plus any associated interface +definition files, plus the scripts used to control compilation and +installation of the library. + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of running +a program using the Library is not restricted, and output from such a +program is covered only if its contents constitute a work based on the +Library (independent of the use of the Library in a tool for writing +it). Whether that is true depends on what the Library does and what the +program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the notices +that refer to this License and to the absence of any warranty; and +distribute a copy of this License along with the Library. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of +it, thus forming a work based on the Library, and copy and distribute +such modifications or work under the terms of Section 1 above, provided +that you also meet all of these conditions: + + a) The modified work must itself be a software library. b) You + must cause the files modified to carry prominent notices stating + that you changed the files and the date of any change. c) You + must cause the whole of the work to be licensed at no charge to + all third parties under the terms of this License. d) If a + facility in the modified Library refers to a function or a table + of data to be supplied by an application program that uses the + facility, other than as an argument passed when the facility is + invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the + Library, and can be reasonably considered independent and + separate works in themselves, then this License, and its terms, + do not apply to those sections when you distribute them as + separate works. But when you distribute the same sections as part + of a whole which is a work based on the Library, the distribution + of the whole must be on the terms of this License, whose + permissions for other licensees extend to the entire whole, and + thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or + contest your rights to work written entirely by you; rather, the + intent is to exercise the right to control the distribution of + derivative or collective works based on the Library. + + In addition, mere aggregation of another work not based on the + Library with the Library (or with a work based on the Library) on + a volume of a storage or distribution medium does not bring the + other work under the scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so that +they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in these +notices. + +Once this change is made in a given copy, it is irreversible for that +copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the +Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative +of it, under Section 2) in object code or executable form under the +terms of Sections 1 and 2 above provided that you accompany it with the +complete corresponding machine-readable source code, which must be +distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a +designated place, then offering equivalent access to copy the source +code from the same place satisfies the requirement to distribute the +source code, even though third parties are not compelled to copy the +source along with the object code. + +5. A program that contains no derivative of any portion of the Library, +but is designed to work with the Library by being compiled or linked +with it, is called a "work that uses the Library". Such a work, in +isolation, is not a derivative work of the Library, and therefore falls +outside the scope of this License. + +However, linking a "work that uses the Library" with the Library creates +an executable that is a derivative of the Library (because it contains +portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. Section 6 +states terms for distribution of such executables. + +When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is +not. Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + +If such an object file uses only numerical parameters, data structure +layouts and accessors, and small macros and small inline functions (ten +lines or less in length), then the use of the object file is +unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section +6. Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a +"work that uses the Library" with the Library to produce a work +containing portions of the Library, and distribute that work under terms +of your choice, provided that the terms permit modification of the work +for the customer's own use and reverse engineering for debugging such +modifications. + +You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work during +execution displays copyright notices, you must include the copyright +notice for the Library among them, as well as a reference directing the +user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in + the Library will not necessarily be able to recompile the + application to use the modified definitions.) b) Use a suitable + shared library mechanism for linking with the Library. A suitable + mechanism is one that (1) uses at run time a copy of the library + already present on the user's computer system, rather than + copying library functions into the executable, and (2) will + operate properly with a modified version of the library, if the + user installs one, as long as the modified version is + interface-compatible with the version that the work was made + with. c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials specified + in Subsection 6a, above, for a charge no more than the cost of + performing this distribution. d) If distribution of the work is + made by offering access to copy from a designated place, offer + equivalent access to copy the above specified materials from the + same place. e) Verify that the user has already received a copy + of these materials or that you have already sent this user a + copy. + +For an executable, the required form of the "work that uses the Library" +must include any data and utility programs needed for reproducing the +executable from it. However, as a special exception, the materials to be +distributed need not include anything that is normally distributed (in +either source or binary form) with the major components (compiler, +kernel, and so on) of the operating system on which the executable runs, +unless that component itself accompanies the executable. + +It may happen that this requirement contradicts the license restrictions +of other proprietary libraries that do not normally accompany the +operating system. Such a contradiction means you cannot use both them +and the Library together in an executable that you distribute. + +7. You may place library facilities that are a work based on the Library +side-by-side in a single library together with other library facilities +not covered by this License, and distribute such a combined library, +provided that the separate distribution of the work based on the Library +and of the other library facilities is otherwise permitted, and provided +that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. b) Give prominent notice with the combined + library of the fact that part of it is a work based on the + Library, and explaining where to find the accompanying uncombined + form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the +Library except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense, link with, or distribute the +Library is void, and will automatically terminate your rights under this +License. However, parties who have received copies, or rights, from you +under this License will not have their licenses terminated so long as +such parties remain in full compliance. + +9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and all +its terms and conditions for copying, distributing or modifying the +Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted +herein. You are not responsible for enforcing compliance by third +parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot distribute +so as to satisfy simultaneously your obligations under this License and +any other pertinent obligations, then as a consequence you may not +distribute the Library at all. For example, if a patent license would +not permit royalty-free redistribution of the Library by all those who +receive copies directly or indirectly through you, then the only way you +could satisfy both it and this License would be to refrain entirely from +distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is implemented +by public license practices. Many people have made generous +contributions to the wide range of software distributed through that +system in reliance on consistent application of that system; it is up to +the author/donor to decide if he or she is willing to distribute +software through any other system and a licensee cannot impose that +choice. + +This section is intended to make thoroughly clear what is believed to be +a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may +add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among countries +not thus excluded. In such case, this License incorporates the +limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions +of the Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a license +version number, you may choose any version ever published by the Free +Software Foundation. + +14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free Software +Foundation; we sometimes make exceptions for this. Our decision will be +guided by the two goals of preserving the free status of all derivatives +of our free software and of promoting the sharing and reuse of software +generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH +YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL +NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR +DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL +DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY +(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED +INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF +THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR +OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS diff --git a/libs/cassowary/ChangeLog b/libs/cassowary/ChangeLog new file mode 100644 index 0000000000..be31e0e5a9 --- /dev/null +++ b/libs/cassowary/ChangeLog @@ -0,0 +1,2002 @@ +Fri Mar 18 15:41:00 2005 Taybin Rutkin <taybin@earthlink.net> + * Removed ClSet.h, ClMap.h. + * ClReader.l includes ClReader.cc.h instead of ClReader.hh. The + difference between yacc and bison. + * Various changes to fix compliation. + +Wed Jan 29 21:36:15 2003 Taybin Rutkin <trutkin@physics.clarku.edu> + * Updated to work with g++ 3.x compilers. + * More direct use of STL. + * Removed C wrappers + +Sun Mar 12 13:40:44 2000 Greg J. Badros <gjb@cs.washington.edu> + + * guile/cassowary_scm.cc: Give docstrings as arguments + + * guile/cl-snarf.h: Added docstring as an argument to CL_PROC to + be like the revised Scwm documentation extraction system. + +Sat Feb 12 20:34:55 2000 Greg J. Badros <gjb@cs.washington.edu> + + * Makefile.am: Added GTL.h.patch to EXTRA_DIST + +Sat Feb 12 20:31:47 2000 Greg J. Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.cc, c++/ClSimplexSolver.h: Drop + ExternalResetStayConstants, make ResetStayConstants() public. + Test _fResetStayConstantsAutomatically before doing so in + Resolve(). Use _fAutosolve instead of _fOptimizeAutomatically. + Drop DisplayObjective (wasn't defined anyway). Drop field + _fOptimizeAutomatically (use _fAutosolve from parent, instead). + + * guile/cassowary_scm.hpp, guile/cassowary_scm.cc: Drop extra + include of guile/gh.h + + * guile/cassowary_scm.cc: Added `cl-set-auto-solve!', + `cl-set-auto-reset-stay-constants!' + +Sat Jan 29 17:45:32 2000 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in (CASSOWARY_VERSION): Bump to 0.55. + +Sat Jan 29 17:43:05 2000 Greg J. Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.cc (Resolve): Do not comment out + "ResetStayConstants()" as Beurivé had done. This was resulting in + quirky behaviour whereby the windows were "rubber-banding" back to + where they were at the start of an interaction (e.g., if I push a + window out of the way to the left with another window, as I move + the pushing window back to the right, the other window comes back + to the right with the pushing window). Maybe that's desirable + behaviour in some instances, but it's not the behaviour we + document and sure feels weird to me. + +Sat Jan 29 17:38:43 2000 Greg J. Badros <gjb@cs.washington.edu> + + * java/sym.java, java/parser.java, java/Yylex.java: Added -- these + are created by JavaCUP which I don't want to be necessary for + building. + +Mon Jan 24 09:34:20 2000 Greg J. Badros <gjb@cs.washington.edu> + + * c++/ClSymbolicWeight.h: Set SymbolicWeight multiplier to + 1000000, not 10000 (A.Beurivé) + + * c++/ClSimplexSolver.h, c++/ClSimplexSolver.cc: Added + ChangeStrength, ChangeStrengthAndWeight, ChangeWeight, + DisplayObjective, ExternalResetStayConstants fns. + (RemoveConstraintInternal) Avoid picking the objective row when + removing a constraint. (Optimize) Pick any negative row to avoid + unending pivots [I think this is a work-around to avoid having to + implement Bland's anti-cycling rule... maybe I should just do + that, though]. (A.Beurivé) + +Thu Dec 16 11:12:34 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in: Version bumped to 0.54a + +Thu Dec 16 11:10:42 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/Makefile.am: Force prefix ordering in SUBDIRS so that "." + dir gets built before the demos subdirectory. + + * smalltalk/Makefile.am: Fix .dat file -- thanks Alan! + +Wed Dec 15 19:31:48 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/README: More notes re: security problems w/ Java 2. + + * java/cda/Makefile.am: Added run target to ease running it. + + * Makefile.am (EXTRA_DIST): Added c++/{config.h.in,stamp-h.in} + + * java/cda/Makefile.am (EXTRA_DIST): Clean up install of .gif + files. + + * java/Makefile.am (EXTRA_DIST): Added ClReader.{cup,lex} + + * c++/Makefile.am: Do not make symlink to cassowary; let + configure.in do that. + +Wed Dec 15 18:13:14 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/Makefile.am: Put SUBDIRS demo cda back in since they + compile now. + + * scripts/recreate-symlinks: Update with links to ../../EDU from + demo directories for Java code. Use ln -sf, not just ln -s, to avoid + warnings. + + * Makefile.am (EXTRA_DIST): Include scripts/recreate-symlinks + + * configure.in: Run recreate-symlinks script. + +Wed Dec 15 18:07:27 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/cda/Makefile.am: Put Constraint/*, Main/* files into the + distribution and build with them. + + * java/demos/*.java: Move everything into the + EDU.Washington.grad.gjb.cassowary_demos package. + + * java/cda/classes/run.html, java/demos/quaddemo.htm: Fix nl + convention, name class explicitly w/ package in front, w/o + trailing .class. + + * java/cda/**: Move everything into the + EDU.Washington.grad.noth.cda package. + +Wed Dec 15 17:21:08 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/Makefile.am: Build java parser. + + * java/ClParseTest.java: Added. + + * GTL.h.patch: Added -- need by gcc-2.95 when compiling GTL-0.3.1 + + * java/README: Mention java parser. + + * java/ClReader.lex, java/ClReader.cup: Cleanup, guard debug messages. + +Tue Dec 14 11:15:01 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in: Fix -fpermissive test to not check "cc" as well as + $CC. Eliminate the --enable-permissive flag since it is no longer + necessary. + +Mon Dec 13 15:56:19 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/Yylex.java: Added, from Will Portnoy. + + * java/ClReader.cup, java/ClReader.lex: Latest version from Will, + cleaned up line breaks, set a tab-width for Emacs. + +Mon Dec 13 15:55:59 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/Makefile.am: Remove ClReader.cc -- why did I add this + before? + +Fri Dec 10 13:29:00 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/ClSimplexSolver.java (addLowerBound, addUpperBound): Fix + these two functions to call addConstraint before returning. + Thanks Stephen Allain for catching this! Updated exception specs + for those methods and for addBounds. + +Tue Dec 7 08:42:34 1999 Greg J. Badros <gjb@cs.washington.edu> + + * smalltalk/A991206.dat: New image from Alan. Include correct + version of code for "ClSimplexSolver removeConstraint:" to fix bug + when deleting constraints with weights other than 1. Also + disallow invalid comparisons between symbolic weights and floats. + Replace expressions "x clApprox: 0.0" with "x clApproxZero", which + works correctly for both symbolic weights and floats. + + * smalltalk/*.st: Added from Alan. + +Mon Nov 29 16:23:06 1999 <gjb@cs.washington.edu> + + * configure.in: Bump to version 0.54, added -lGTL to GTL_LIB even + when no --with-gtl option is given. No longer create README from + README.in. Added --enable-static-library option, off by default. + + * c++/Makefile.am (sources): Added ClReader.cc + + * cassowary.spec.in, cassowary-both.spec.in: No longer need the + --enable-guile-build option; it's the default now. + +Mon Nov 29 10:52:49 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/Makefile.am: Added use of AM_CONDITIONAL + CL_BUILD_STATIC_LIBRARY; only buile libcassowary.a if that option + was selected. + + * guile/Makefile.am (libconstraints_la_LIBADD): Added @GTL_LIB@ to + make the guile library work with the FD-enabled version of the library. + +Sat Nov 27 16:11:10 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in: Invert sense of --enable-guile-build and call it + --disable-guile-build; build guile wrapper automatically if + guile-config works. + +Sat Nov 27 15:20:03 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in: Use an AM_CONDITIONAL for CL_BUILD_FD_SOLVER, not + an AC_DEFINE. Also, remove duplicate AC_SUBST of GTL_LIB, and fix + AM_CONDITIONAL of CL_BUILD_TESTS. + +Sat Nov 27 15:19:20 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/Makefile.am: Try separating out FD stuff better, and use + CL_BUILD_FD_SOLVER AM_CONDITIONAL to control dependence on that + code. + + * c++/config.h.in: Drop CL_BUILD_FD_SOLVER; it's now an + AM_CONDITIONAL instead of a define. + +Wed Nov 24 15:40:27 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.cc: Fix typo in a throw message. + + * c++/ClLinearInequality.h: Throw an editmisuse when a + ClLinearInequality is created w/o an inequality operator. + +Tue Nov 23 16:54:05 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in: Use guile's pkglibdir, not pkgdatadir, for + choosing cassoguiledir. + +Tue Nov 16 17:35:54 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/ClReader.lex, java/ClReader.cup: Added -- code by Will + Portnoy for adding a parser to the Java implementation. Untested, + and an early version that he emailed me. + +Tue Nov 16 17:34:00 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/ClTestColumns.java, java/ClTests.java: Put in the cassowary + package, instead of importing cassowary.*; jikes needed this + (discovered during testing of java-ml work). + +Sat Nov 13 11:43:48 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/Timer.java (Timer): Remove return type from Timer() + constructor (jikes caught the bug when I used this as a test case + for my java-ml work). + +Sun Oct 24 13:17:14 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in: Updated version to 0.53, generate + smalltalk/Makefile from Makefile.am. + + * NEWS: Updated for 0.53 release. + + * Makefile.am: Added smalltalk directory to SUBDIRS. + +Sat Oct 23 14:34:27 1999 Greg J. Badros <gjb@cs.washington.edu> + + * COPYING.GPL: Added + + * LICENSE: Added Scwm exception + + +Sat Oct 23 14:33:48 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/Makefile.am: Make cassowary/ directory symlink as needed. + +Sun Oct 3 16:50:43 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.cc: Use clvNil some places instead of NULL. + This is important for newer, pickier gcc-2.95.x. Thanks Alexandre + Duret-Lutz for the patch! + +Thu Sep 30 08:17:16 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/ClFDSolver.cc: Added missing #include <stdarg.h> -- Thanks + Harry Hochheiser for bug report. + +Sun Sep 26 13:43:12 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/Makefile.am (libcassowary_la_LDFLAGS): Added -version-info + flag to make libcassowary.so.0.0.1, instead of .0.0.0 + +Sun Sep 26 13:15:32 1999 Greg J. Badros <gjb@cs.washington.edu> + + * README, ANNOUNCE: Removed + + * README.in, ANNOUNCE.in: Added + + * configure.in: Create README, ANNOUNCE, bump to 0.52post + +Sat Sep 25 16:02:22 1999 Greg J. Badros <gjb@cs.washington.edu> + + * cassowary.spec.in, configure.in: Update to version 0.52. + +Fri Sep 24 18:51:42 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in: Remove first of redundant checks for HAVE_SCM_MAKE_SMOB_TYPE_MFPE. + +Mon Sep 20 13:36:45 1999 Greg J. Badros <gjb@cs.washington.edu> + + * guile/cassowary_scm.cc: Fix `cl-int-value' to use gh_int2scm + instead of gh_double2scm + +Sun Sep 19 14:45:59 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.h, c++/ClSimplexSolver.cc: Replace + _editVarMap with _editInfoList, a list. Make ClEditInfo class + contain the variable since its no longer stored as values in a + hash where the key is the variable. Drop the index from + ClEditInfo. Rename ClVarToEditInfoMap to ClEditInfoList. + +Sun Sep 19 14:44:00 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/ClTests.cc (multiedit2): Added this new test to check nested + edits that share an existing variable better. This tests the fix + for the ScwmButtons auto-orientation seg-fault bug in Scwm. + + * c++/ClBug0.cc: Added comment re: new bug fix. + +Sat Sep 18 22:31:54 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in: Added GUILE_LIBS setting. + + * cassowary.spec.in: Use fake_root_for_install to get the + cassowary guile library in proper place. + + * autogen.sh: Only create symlink if not already created. + + * acconfig.h, c++/config.h.in: Added HAVE_SCM_MAKE_SMOB_TYPE_MFPE + + * README: Added note re: enable-permissive + + * guile/cassowary_scm.cc: Use new-style (guile-1.3.2 or better) + SMOBs conditioning on HAVE_SCM_MAKE_SMOB_TYPE_MFPE. + +Wed Sep 8 20:03:25 1999 Greg J. Badros <gjb@cs.washington.edu> + + * cassowary.spec.in: Bump to release 8 + + * cassowary-nofd.spec2.in: Bump to release 2. + +Wed Sep 8 19:43:53 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/Makefile.am: Drop building of config-inline.h -- let + configure handle that-- this was causing a double-build + (!!!ugh!!!) of Cassowary when building from RPMs, e.g. + + * GTL.spec.in: Use install-strip target. + +Tue Sep 7 23:34:49 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in, Makefile.am: use cassowary-nofd.spec2.in + + * cassowary-nofd.spec2.in: Renamed from cassowary-nofd.spec.in, + since having two *.spec files in the top level upsets rpm (it cats + them together and then gets confused by the double .spec file). + + * cassowary-both.spec.in: Added-- rpm doesn't support two %build + tags (one for a subpackage), but if it did, this is what the + corresponding .spec file might look like. + +Tue Sep 7 23:02:26 1999 Greg J. Badros <gjb@cs.washington.edu> + + * Makefile.am: Added cassowary-nofd.spec to EXTRA_DIST, + bin_SCRIPTS = cassowary-config. Added dist-nofd target, and + supporting targets. + + * cassowary.spec.in: Bump to 7, provide virtual package, install + %{prefix}/bin/* (for cassowary-config script). + + * configure.in: Added CASSOWARY_VERSION variable, create + cassowary-config, cassowary-nofd.spec + + * cassowary-config.in, cassowary-nofd.spec.in: Added + +Mon Sep 6 21:40:58 1999 <gjb@cs.washington.edu> + + * cassowary.spec.in: Use install-strip target to remove debug + symbols and save disk space. Remove %{prefix}/doc/* from the + %files list as they are in the %doc listing already. + +Mon Sep 6 12:25:14 1999 Greg J. Badros <gjb@cs.washington.edu> + + * cassowary.spec.in: Use --host=alpha-linux on that platform + (using an %ifarch). Bump to release 6. + + * GTL.spec.in: Fix the ./configure line for alpha platform (was + missing "--" before the "prefix" option). Bump to release 2. + + * c++/ClSymbolicWeight.h, c++/ClSymbolicWeight.cc: Use int, not + unsigned, to remove ambiguity in ClSymbolicWeight constructor. + +Sat Sep 4 15:17:13 1999 Greg J. Badros <gjb@cs.washington.edu> + + * acconfig.h: Added NO_CC_PERMISSIVE flag. + + * autogen.sh: Added #!/bin/sh - to top. + + * configure.in: Test for g++/gcc -fpermissive flag. Hopefully + this will let it get used only where it is accepted. Some better + guile tests, too. + + * cassowary.spec.in: Use --enable-permissive flag, bump from + release 3 to 5. + +Sat Sep 4 14:44:14 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/Makefile.am, guile/Makefile.am: Added CPPEXTRAFLAGS to + AM_CPPFLAGS. + + * guile/Makefile.am: Guard lib_LIBRARIES with HAVE_GUILE test so + that guile stuff is only built when GUILE is desired and we have + the libraries installed. + +Tue Aug 31 22:16:04 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/demos/Makefile.am, java/cda/Makefile.am, java/Makefile.am + (install-javaJAVA): Do not try to install .class files if no + HAVE_JAVA + +Tue Aug 31 21:30:24 1999 Greg J. Badros <gjb@cs.washington.edu> + + * cassowary.spec.in: Do not use --disable-java-build, since that + still invokes the rule which is not what I want. + + * java/demos/Makefile.am, java/cda/Makefile.am: Added bogus + classjava.stamp rule when no HAVE_JAVA to work around getting an + error when trying to run javac with no source files. + + * configure.in: Fix some HAVE_JAVA bugs. Still not perfect, but better. + +Tue Aug 31 17:07:31 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/demos/Makefile.am, java/cda/Makefile.am, java/Makefile.am: + Added EXTRA_DIST. + +Tue Aug 31 16:27:41 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in (HAVA_JAVA): AC_OUTPUT the java/*/Makefiles. + + * cassowary.spec.in: Use --disable-java-build ./configure option. + Bump to release 3. + + * Makefile.am: Do not conditionally do directories-- that is + really broken with automake/rpm building. + +Tue Aug 31 16:20:45 1999 Greg J. Badros <gjb@cs.washington.edu> + + * java/demos/Makefile.am, java/cda/Makefile.am, java/Makefile.am + (java_JAVA): Guard with if HAVE_JAVE. + +Mon Aug 30 12:03:26 1999 Greg J. Badros <gjb@cs.washington.edu> + + * cassowary.spec.in: Bump to release 2 + + * configure.in: Drop the java/* wrappers/* from AC_OUTPUT macro-- + this breaks java builds but make the Cassowary RPM build more + cleanly. I'm going to start making a separate cassowary-java + distribution unless I can figure out how to make automake and Java + co-exist more happily. + +Mon Aug 30 12:00:39 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/ClAbstractVariable.h: #include "cl_auto_ptr.h" and use + cl_auto_ptr, not auto_ptr. + +Mon Aug 30 10:06:50 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/cl_auto_ptr.h: Change the conditional inclusion sandwich to + CL_AUTO_PTR_H. Added "#define cl_auto_ptr auto_ptr" for MSVC. + +Thu Aug 26 22:42:50 1999 Greg J. Badros <gjb@cs.washington.edu> + + * cassowary.spec.in: Require guile 1.3.2, to be safe. Require GTL + >= 0.3.1, not gtl >= 0.3.1 (note capitalization) + +Thu Aug 26 14:12:42 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/ClFDSolver.h, c++/ClCTest.c, c++/ClC.h, c++/ClC.cc, + c++/Cassowary.h, c++/ClConstraint.h: Use LONG_MIN, not MINLONG and + #include <limits.h> not <values.h> since the latter is deprecated + (and does not work in VC++). + + * THANKS: Thank Pengling He for his VC++ bug report re: values.h + +Thu Aug 26 14:08:46 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in (GUILE_PKGDATA_DIR): Set cassoguiledir variable, + and use ${prefix} prefix of GUILE_PKGDATA_DIR to be sure that rpm + building succeeds (was failing because it was trying to write to + an absolute location that guile told it to use, instead of using + the prefix of $RPM_BUILD_ROOT). + + * c++/Makefile.am: Fix lex/yacc building dependencies. + + * guile/Makefile.am (cassoguile_LTLIBRARIES): Do not set + cassoguiledir here-- do it in configure.in instead. + +Thu Aug 26 11:02:36 1999 Greg J. Badros <gjb@cs.washington.edu> + + * guile/Makefile.am (EXTRA_DIST), docs/Makefile.am: Added docs to + EXTRA_DIST. + + * c++/Makefile.am: Added ClReader.l, ClReader.y to EXTRA_DIST, + remove ClReader.cc from sources. Added timer.h to + pkginclude_HEADERS. + + * Makefile.am: Update EXTRA_DIST + +Thu Aug 26 08:45:08 1999 Greg J. Badros <gjb@cs.washington.edu> + + * configure.in: Write cassowary.spec, GTL.spec. Bump version to + 0.51. + + * autogen.sh: Run configure, not config.status + + * VERSION, README, NEWS, ANNOUNCE: Bump to 0.51, add date, notes. + + * Makefile.am: Drop Java, Python to make easier to package. Added + EXTRA_DIST to include some doc files and the cassowary.spec file. + +Wed Aug 25 22:54:18 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/Makefile.am (pkginclude_HEADERS): cl_auto_ptr.h now, not auto_ptr.h + +Mon Aug 23 21:26:31 1999 Greg J. Badros <gjb@cs.washington.edu> + + * ltmain.sh, ltconfig, libtool, configure: Removed -- these are + autogenerated by autogen.sh + +Mon Aug 23 21:23:53 1999 Greg J. Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.cc: Use cl_auto_ptr, not auto_ptr. + + * c++/ClAbstractVariable.h: #include <memory>, not "auto_ptr.h" + + * c++/cl_auto_ptr.h: Added -- renamed from auto_ptr.h since that + was causing some difficulties due to the standard C++ auto_ptr template. + +Mon Jul 26 10:19:35 1999 Greg Badros <gjb@cs.washington.edu> + + * c++/Makefile.am (libcassowary_la_SOURCES): Remove redundant + listing of ClFD* files from this target. + +Mon Jul 26 09:41:09 1999 Greg Badros <gjb@cs.washington.edu> + + * c++/Cl.h: Include ClConstraint.h, since cnLT, etc., need to be + defined for ClReader.y + +Mon Jul 26 09:22:11 1999 Greg Badros <gjb@cs.washington.edu> + + * acconfig.h, configure.in: Use CL_ prefix for BUILD_FD_SOLVER and + HAVE_GTL. + +Mon Jul 26 09:17:56 1999 Greg Badros <gjb@cs.washington.edu> + + * c++/config.h.in,c++/ClC.h,c++/ClC.cc,c++/Cl.h: Use CL_ prefix on + BUILD_FD_SOLVER and HAVE_GTL so that the config-inline.h gets the + right definitions. + + * c++/Makefile.am: Expanded out the sources_for_fd_solver since + the _OBJECTS make variable doesn't get expanded properly if this + step is deferred until later. This breaks builds w/o FD solver, + but I have to get Amaya working ASAP. + +Mon Jul 19 17:08:03 1999 Greg Badros <gjb@cs.washington.edu> + + * c++/ClSymbolicWeight.h: Increase multiplier to 10000 for + AsDouble-- works around the bug in resizing Scwm windows because + the medium stay constraints on width and height are too strong for + the strong edit constraint. + +Sun Jul 11 19:37:39 1999 Greg Badros <gjb@cs.washington.edu> + + * c++/ClLinearExpression.h: Remove "class" from a typedef + ClMap<ClVariable,class T>. Thanks Alexandre 'Pollux' Duret-Lutz + for testing against a more recent egcs (gcc-2.95) that caught this + problem. + + * configure.in: Improve checks for guile so that it uses --prefix + and --exec-prefix to --guile-prefix and --guile-exec-prefix + +Sat Jul 10 19:21:34 1999 Greg Badros <gjb@cs.washington.edu> + + * autogen.sh: rm libtool stuff just in case. + + * README: Updated version number, notes about building it and + needing GTL for fd solver. + + * configure.in: Added --enable-cxx-tests, --enable-fd-solver, + --with-gtl; switch --disable-java-build to --enable-java-build + + * acconfig.h, c++/config.h.in: Added HAVE_GTL, BUILD_FD_SOLVER options. + + * c++/Makefile.am: Make only the library and ClTests get built by + default (other binary test programs are each big when build -g, + and aren't useful to the end user). Use @SOURCES_FOR_FD_SOLVER@ + to permit a version of the toolkit to be build without the finite + domain subsolver. + + * c++/ClC.h, c++/ClC.cc, c++/Cl.h: Add #ifdefs for no fd subsolver. + +Fri May 7 17:02:09 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClC.cc (CL_ClvLookup): Return NULL if varmap is NULL instead + of asserting it is non-NULL + +Thu May 6 19:02:38 1999 Greg J Badros <gjb@bowman.cs.monash.edu.au> + + * c++/ClFDTests.cc: Added return type to connect1. + + * c++/ClFDSolver.cc: Return *this where missing. + + * c++/ClFDConnectorVariable.h: Reorder mem vars to match + initialization order in ctr. + + * c++/ClC.h, c++/ClC.cc: Added CL_ClvIsFD. + +Sun May 2 10:42:00 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClReader.l: Permit "_" in identifiers (needed for env + variable precondition variables). + + * c++/ClLinearInequality.h: Honour _fStrictInequality flag when + testing FIsSatisfied(). + + * c++/ClLinearConstraint.h: Added missing "void" return type for + ChangeConstant. + +Fri Apr 30 09:45:51 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClFDConnectorVariable.cc, c++/ClFDConnectorVariable.h: + Added -- support connecting the FD solver to the simplex solver + via a variable in the FD region that gets its value "copied" to a + analogous variable in the Simplex region. + + * Makefile.am: Added ClFDConnectorVariable.[ch] files. + + * c++/ClLinearConstraint.h: Added ChangeConstant() + + * c++/ClFloatVariable.h, c++/ClFDVariable.h, + c++/ClFloatVariable.cc, c++/ClFDVariable.cc, + c++/ClAbstractVariable.h: Move _pv, SetPv(), Pv() from + ClFloatVariable, ClFDVariable, into common parent + ClAbstractVariable. Drop ClFloatVariable::SetName(). + + * c++/ClFDTests.cc: Added connect1 test to test + ClFDConnectorVariable + + * c++/ClFDSolver.cc: Use 1 + value-rhs for errors to ensure that + strict inequalities behave reasonably. + +Thu Apr 29 19:29:34 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClVariable.h: Register variable in the dictionary when + initialized from a ClFDVariable*. Added const ClAbstractVariable + *operator() const. + + * c++/ClSolver.h, c++/ClSimplexSolver.h: Added _fAutosolve, + _pfnChangeClvCallback; added default ctr to initialize. Added + SolveNoException(); Moved SetAutosolve(), FIsAutosolving(), + SetChangeClvCallback() from ClSimplexSolver up to here. + + * c++/ClSolver.cc: Added PrintTo for list<FDNumber>, operator<< + for same. + + * c++/ClSimplexSolver.cc: Test constraint with + FIsOkayForSimplexSolver() before trying to add it (avoids adding + FD constraints to the simplex solver). + s/_fOptimizeAutomatically/_fAutosolve/g + + * c++/ClParseTest.cc: Use FCanConvertCn() before trying to. + + * c++/ClFDVariable.h: Make PlfdnDomain() const and return const. + + * c++/ClFDVariable.cc: PrintOn now displays value (duh!) + + * c++/ClFDTests.cc: Use new ListPushOnto() instead of a bunch of + push_back. Added simple2, simple3. + + * c++/ClFDSolver.h, c++/ClFDSolver.cc: Added ChangeClv(), + AddConstraintInternal(), RemoveConstraintInternal(), + ListPushOnto(), fDebugFDSolve var, more debugging code. + + * c++/ClConstraint.h, c++/ClFDConstraint.h: Added + FIsOkayForSimplexSolver() returning false for FDCns, true in the + base class. + + * c++/ClFDBinaryOneWayConstraint.h, + c++/ClFDBinaryOneWayConstraint.cc: Make ctr take ClConstraint + instead of ClLinearConstraint. Added EnsurePreconditionsForCn(), + FCanConvertCn(). Throw better exceptions instead of + ExCLEditMisue-- use new ExCLTooDifficultSpecial. + + * c++/ClCTest.c: Use CL_ClvPrint instead of coding by hand. + Added CL_CldvNew() call. + + * c++/ClC.cc, c++/ClC.h: Added FDN_EOL defn, typedefs for Number, + FDNumber, CL_CldvNew(), CL_FDCanConvertCn(), CL_FDCnFromCn(), + CL_ClvPrint(). Use CL_Solver for PfnChangeClvCallback, not CL_SimplexSolver. + + * c++/ClAbstractVariable.h: Throw instead of assert(false) in base + class IsPivotable(), IsRestricted(). + +Wed Apr 28 19:38:46 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClC.cc: Added CL_FDSolverNew() + +Wed Apr 28 19:10:32 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile.am (INCLUDES): Include @GUILE_INCLUDES@ -- actually + done to get cassowary libraries (GJB:FIXME::) + +Wed Apr 28 18:49:51 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile.am: Added ClCTest to the _PROGRAMS, and use + -lstdc++ on them + + * c++/ClSolver.h: Expose Resolve() in base-class interface, along + with <<, and PrintOn. + + * c++/ClSolver.cc: Added << operator. + + * c++/ClC.h, c++/ClC.cc, c++/ClTest.c: Fixed bugs, use + CL_Solver... instead of CL_SimplexSolver... where appropriate. + +Wed Apr 28 17:15:47 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClSymbolicWeight.h: Make CLevels unsigned, not int, and + require all 3 args to the 3 double ctr to remove ambiguity. + + * c++/ClSimplexSolver.h: Check constraint before adding and throw + an error if the constraint is no good for the SimplexSolver. + + * c++/ClParseTest.cc: Don't assume a failed add is due to an + inconsistent system-- could be wrong kind of constraint was read + in. + + * c++/ClLinearInequality.h: Store the strictness of the + inequality, since other solvers may be able to use strict ones. + + * c++/ClFDSolver.cc: Fine-tune the exception objects thrown... use + the richer hierarchy. + + * c++/ClFDBinaryOneWayConstraint.c, + c++/ClFDBinaryOneWayConstraint.h: Added IsStrictInequality(), get + the direction of the inequality correct. + + * c++/ClErrors.h: Richer hierarchy of exceptions to cope with + solver limitations. + + * c++/ClConstraint.h: Added IsStrictInequality(); have + ReadOnlyVars return a const ClVarSet&, not value. + +Wed Apr 28 12:20:47 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile.am: Added ClFDBinaryOneWayConstraint.cc. + + * c++/ClReader.y, c++/ClReader.l: Added tokens GT, LT, and handle + them (for >, <, resp). + + * c++/ClParseTest.cc: try converting to a FD constraint, and show + what that object is. + + * c++/ClFDBinaryOneWayConstraint.h: Added ctr from a + ClLinearConstraint. Added IsInequality(). + +Wed Apr 28 12:08:16 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ro-test.in: Added for testing below. + + * c++/ClFDBinaryOneWayConstraint.cc: Added -- so far just a ctr + from a ClLinearConstraint object (since the parser hands me a + constraint object that is a ClLinearConstraint object). + +Tue Apr 27 20:35:23 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClSymbolicWeight.h, c++/ClSymbolicWeight.cc: Drop default + ctr, and give default arg value to CLevels of 3. Added operator*. + + * c++/ClFDTests.cc: Better test. + + * c++/ClFDSolver.h, c++/ClFDSolver.cc: Use SymbolicWeights for + errors, so hierarchy is handled (i.e., strengths on constraints + are honoured). + + * c++/ClFDConstraint.h: Added ctr with strength, weight. + + * c++/ClFDBinaryOneWayConstraint.h: Added strength, weight + arguments to ctr. + + * c++/ClConstraint.h: Added symbolicWeight() accessor. + +Tue Apr 27 15:04:34 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClFDSolver.cc (RemoveConstraint): Fix some bugs-- handle nil + read-only variable properly, and clean up _mapVarToNode when + erasing nodes. + +Tue Apr 27 10:40:58 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClSolver.cc: Added -- wrote PrintTo, << basic impls, and + simple AddConstraint. + + * c++/QocaBench.cc, c++/ClTests.cc, c++/ClSubgraphTest.cc, + ClLeakTest.cc, ClC.cc: Use Solve(), not solve() + + * c++/ClVariable.h: Added DesiredValue, PlfdnDomain base-class + accessors, handle clvNil in PrintOn. + + * c++/Makefile.am: Added ClSolver.cc, link with -lGTL, added + missing and new .cc, .h files. + + * c++/ClTypedefs.h: added ClVarToConstraintSetMap. + + * c++/ClSolver.h: Added AddConstraint{,NoException}, + RemoveConstraint{,NoException}, Solver here to the abstract + interface, also the prototypes for the PrintTo and << on the + ClTypedefs.h types. + + * c++/ClSimplexSolver.h, c++/ClSimplexSolver.cc: Solve(), not + solve(), move some protos in abstract base class ClSolver. + + * c++/ClLinearInequality.h: Use ClCnRelation, not + ClInequalityOperator. + + * c++/ClFDVariable.h, c++/ClFDVariable.cc: More accessors, + settors, comment-out non-initial-domain ctr. + + * c++/ClFDTests.cc: Test more. + + * c++/ClFDSolver.h, c++/ClFDSolver.cc: Almost complete, but + largely untested implementation. + + * c++/ClFDBinaryOneWayConstraint.h: Added ctrs, setters, getters. + + * c++/ClErrors.h: Fixed throw message for ExCLConstraintNotFound + to not refer to the tableau. + + * c++/ClConstraint.h: Added ClCnRelation (was ClInequalityOperator + in c++/ClLinearInequality.h) and wrote StrCnRelation for printing + it. + + * c++/Cl.h: include ClFDSolver.h + + * c++/Cassowary.h : include values.h, def FDN_NOTSET (FIXME: drop this?) + +Sun Apr 25 18:55:26 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile.am: Added ClFDBinaryOneWayConstraint.h, + ClFDConstraint.h to pkginclude_HEADERS. + + * c++/ClSimplexSolver.h, c++/ClSimplexSolver.cc: Added optional + strength argument to AddPointStays, AddPointStay fns. + + * c++/ClFDVariable.h: Set _plfdnInitialDomain to avoid a warning + for now. + + * c++/ClFDBinaryOneWayConstraint.h: Added return xo to PrintOn. + + * c++/ClConstraint.h: Fix order of initializers. + + * c++/ClC.h, c++/ClC.cc: Document return value for + CL_VarMapDelete, and do proper return. + + * configure.in: Added --enable-cflags, --enable-cxxflags, + --enable-cppextraflags. Not tested yet. + +Sun Apr 25 11:46:28 1999 Greg J Badros <gjb@cs.washington.edu> + + * configure.in: Bump version to .50, for FD features. + +Sun Apr 25 11:37:52 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile.am: Comment out the Bug sources/builds, add the FD + sources. + + * c++/ClSimplexSolver.h: Inherit from ClSolver, too. Move SetPv, + Pv() out into ClSolver base class. + + * c++/ClSimplexSolver.cc, c++/Cl.h: Make szCassowaryVersion a const char *. + + * c++/ClReadery.y, c++/ClReader.l, c++/ClReader.h: Support "?" + read-only annotations, and use Constraint::AddROVars() to track + the ro vars of a constraint expression. + + * c++/ClParseTest.cc: Show whether the constraint is added + successfully or if it is inconsistent. + + * c++/ClLinearConstraint.h: Fix BUG-- super should be + ClConstraint, not ClLinearConstraint. + + * c++/ClFDVariable.cc: Use <, > to delimit FD vars, not [, ]. + + * c++/ClConstraint.h, c++/ClConstraint.cc: Added AddROVars, + FIsReadOnlyVar, ReadOnlyVars. + +Thu Apr 22 20:18:31 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClVariable.h: Added ClVariable ctr that takes a + ClFDVariable*, this ambiguates returning NULL as a ClVariable, so + may not be a good idea, but it does make it less confusing than + having another overloaded version of ClVariable's ctr. Added + IsFloatVariable, IsFDVariable fwding fns. + + * c++/ClSimplexSolver.cc: Disambiguate uses of NULL to be + (ClFloatVariable *)NULL. + + * c++/ClFloatVariable.h: Added IsFloatVariable() to return true + + * c++/ClC.h, c++/ClC.cc: Added CL_ClvLookupTrim for removing ws + around the var name. + + * c++/ClAbstractVariable.h: Make IsPivotable, IsRestricted both + assert false instead of being pure virtual -- they only need to be + overridden if we want to permit them to be called. Added + IsFloatVariable(), IsFDVariable() both returning false in this + base class. + + * c++/Cassowary.h: Added FDNumber typedef to be a long. + + * c++/Makefile.am: Added ClFDVariable.{cc,h} + + * c++/ClFDVariable.cc, c++/ClFDVariable.h: Added, copied from + ClFloatVariable and modified slightly. + +Tue Apr 20 10:18:32 1999 Greg J Badros <gjb@cs.washington.edu> + + * smalltalk/README: Note that smalltalk implementation is now in + the public domain. + + * README: Update to version 0.43, note about smalltalk + implementation being in public domain. + + * LICENSE: Note about not applying to smalltalk implementation + + * ANNOUNCE: Update date to today. + + * *: Changed copyright to be "Greg J. Badros and Alan Borning" + instead of "Alan Borning and Greg J. Badros". Okayed by Alan -- + to hopefully encourage more people to write me with their + questions/problems rather than Alan. + +Mon Apr 19 13:45:35 1999 Greg J Badros <gjb@cs.washington.edu> + + * cassowary.spec: Added --with-guile-prefix + +Mon Apr 19 13:02:46 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClReader.l: Be a bit more careful about end of string + handling in YY_INPUT-- only return result = 1 if we read a + non-null character. Call yy_flush_buffer() before throw-ing an + error, so that we start anew the next time we are asked to return + tokens for the parser. + + * c++/ClC.h, c++/ClC.cc: Added CL_SimplexSolverAddStay. (Fix typo + in .cc) + +Fri Apr 16 16:36:24 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClTests.cc, c++/ClSimplexSolver.h, c++/ClSimplexSolver.cc, : Use "RemoveConstraintNoException", not + "removeConstraintNoException" (fix initial caps.) + + * c++/ClReader.y: Start looking for a constraint, turn on verbose + warnings and DEBUG option (still need to set cldebug = 1 in + debugger) + + * c++/ClReader.h: In operator() for the lookup proc, Return + &clvNil() if _pmapVars is still NULL + + * c++/ClC.h, c++/ClC.cc: Added CL_VariableName(..), CL_VarMapDelete(..), + CL_RemoveConstraint(..) + + +Wed Apr 14 16:56:05 1999 Greg J Badros <gjb@cs.washington.edu> + + * configure.in: Bump to .43. + + * c++/ClC.cc (CL_VarMapDelete, CL_VariableName): Added new functions. + + * cassowary.spec: Added, for building rpms + + * c++/gdbinit-cassowary: Added a bunch of guile debugging macros. + + * c++/Makefile.am: Added ClC.cc to libcassowary_a_SOURCES + + * c++/ClReader.y: Turn off parser debugging messages by default + + * c++/ClC.h, c++/ClC.cc: Added CL_ConstraintPrint, CL_FIsSatisfied + protos + +Wed Mar 31 17:23:18 1999 Greg J Badros <gjb@cs.washington.edu> + + * wrappers/Makefile.in: Rename PYTHON_HEADERS to PYTHON_HEADER_DIR + so it does not get treated specially by automake (?). + + * configure.in: Bump to .42. Added --disable-cpp-build, + --disable-java-build, and disable Python/Guile builds + automatically if directories cannot be found. Drop the + cassowary from c++/cassowary/config.h -- just use c++/config.h + + * autogen.sh: do not fail if config.status is not -x. + + * Makefile.am: Honour the HAVE_foo flags so that not all subdirs + have to be built. + +Mon Mar 29 21:01:21 1999 Greg J Badros <gjb@cs.washington.edu> + + * ltconfig, ltmain.sh: Added -- so libtool isn't broken in + distributions. + +Mon Mar 29 20:59:17 1999 Greg J Badros <gjb@cs.washington.edu> + + * configure.in: Try to undo a bash-ism. Untested on a vendor sh, + but still works with bash. + +Sat Mar 20 19:19:37 1999 Greg J Badros <gjb@cs.washington.edu> + + * Release v0.41. + +Sat Mar 20 19:19:13 1999 Greg J Badros <gjb@cs.washington.edu> + + * Added config.sub and config.guess to the repo -- they were + symlinks before which broke the distribution. + +Thu Mar 18 15:20:51 1999 Greg J Badros <gjb@cs.washington.edu> + + * Release v0.4. + +Thu Mar 18 14:44:39 1999 Greg J Badros <gjb@cs.washington.edu> + + * configure.in: Do not let config-inline.h get overwritten if it + is unchanged. Add some extra messages to tell status of + config-inline.h + +Thu Mar 18 12:59:02 1999 Greg J Badros <gjb@cs.washington.edu> + + * README, configure.in, wrappers/Makefile.in: Added + --with-python-headers configure option. + +Thu Mar 18 12:48:55 1999 Greg J Badros <gjb@cs.washington.edu> + + * README: Added notes about what to do when a subdir build fails, + suggest -k by default. + + * guile/Makefile.am (test): Added this target for easier way to + run cltests.scm. + + * guile/README: Updated with notes about how to run cltests.scm. + + * java/Makefile.in: Fix tests build rule. + +Thu Mar 18 11:42:49 1999 Greg J Badros <gjb@cs.washington.edu> + + * configure.in: Create config-inline.h at end of script. + + * c++/Makefile.am: Do not have rule for building config-inline.h; + let configure script do that. + +Thu Mar 18 11:05:27 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/*.h: Use #include config-inline.h incantation so that header + files don't include config.h (since they may be included by + another package that has its own config.h) + + * c++/*.cc: Use #include config.h as these are build-time-only + used and can thus rely on the full configure details. + +Thu Mar 18 10:57:08 1999 Greg J Badros <gjb@cs.washington.edu> + + * guile/cassowary_scm.hpp: Use #include config-inline.h + incantation. + + * guile/cassowary_scm.h: Drop including config.h; it's not + needed. + + * guile/cassowary_scm.cc: Use cassowary/config.h, not config.h + +Thu Mar 18 10:29:40 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile.am: Install config-inline.h, not config.h, and + build config-inline.h by grepping for #define CL_ in config.h. + This works around the problem caused by Scwm including Cassowary + header files which then included cassowary's config.h and + conflicted with Scwm's config.h. + +Thu Mar 18 10:11:40 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/test-*.cc: Only #include "Cl.h" + +Thu Mar 18 09:50:45 1999 Greg J Badros <gjb@cs.washington.edu> + + * wrappers/Makefile.in (clean): use rm -f so we don't get a + warning if file is missing. + +Thu Mar 18 09:49:35 1999 Greg J Badros <gjb@cs.washington.edu> + + * java/Makefile.in: Use JAVA_CLASS_PATH configure variable. Fix + install target to echo a message about the install happening + during the build. + +Wed Mar 17 18:54:16 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile.am: Use libtool, and added lib_LTLIBRARIES. Put + benchmarks, bugs, and test programs all under $libdir/cassowary. + Drop cassoincludedir, as that's just pkginclude, and use + include_HEADERS for Cl.h and ClC.h, the main top-level includes. + Also install config.h. + + * c++/Cassowary.h: #undef PACKAGE, VERSION before #including + cassowary/config.h as a cheezy workaround. (Switched from "" to + <>, and ../ to cassowary/ also). + +Wed Mar 17 18:50:49 1999 Greg J Badros <gjb@cs.washington.edu> + + * configure.in: Put config.h in c++/cassowary so cassowary must do + #include <cassowary/config.h> so there is no filename conflict + with other packages including cassowary header files (e.g., + Scwm). Added AM_PROG_LIBTOOL call. Set GUILE variables outside + of the guile-prefix ACE_ARG_PATH macro, and set GUILE_PKGDATA_DIR + use guile-config to find out where we should install the .so file. + +Wed Mar 17 18:43:08 1999 Greg J Badros <gjb@cs.washington.edu> + + * guile/Makefile.am: Updated to build using libtool, and to + install header files. Changes name to libconstraints.* so that + the guile module name (cassowary constraints) works out, and set + it to install in the right place. + +Wed Mar 17 18:39:13 1999 Greg J Badros <gjb@cs.washington.edu> + + * guile/cltests.scm: Added #! lines, change name of module to + (cassowary constraints), remove redundant `use-modules' call. + + * guile/cassowary_scm.hpp: #include + cassowary/ClLinearExpression_fwd.h, not ClLinearExpression_fwd.h + + * guile/cassowary_scm.cc: Change name of module to (cassowary + constraints). Make the init_cassowary_scm fn static. + +Wed Mar 17 07:39:10 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Cassowary.h, c++/ClSimplexSolver.cc: Switch back to + including config.h (now ../config.h) from Cassowary.h, instead of + from ClSimplexSolver.cc. + +Tue Mar 16 19:56:02 1999 Greg J Badros <gjb@cs.washington.edu> + + * acconfig.h: Fix missing comment closer */ + + * c++/Makefile.am: Added AM_CPPFLAGS = $(CPPEXTRAFLAGS) + + * configure.in: Use config.h, not c++/config.h, and permit + --enable-warnings option to turn on compile-time warnings (uses + AM_CPPFLAGS in Makefile.am) + +Tue Mar 16 19:26:23 1999 Greg J Badros <gjb@cs.washington.edu> + + * configure.in, acconfig.h: Better autoconf support, including + several --enable options. Added acconfig.h to support autoheader + doing the right thing in making config.h.in. + +Tue Mar 16 19:22:50 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.cc, c++/Cassowary.h: Include "config.h" from + here, not from Cassowary.h (still not right-- problem is scwm gets + the wrong config.h. Maybe config.h should be in ..? + +Tue Mar 16 19:21:06 1999 Greg J Badros <gjb@cs.washington.edu> + + * java/README: Added note about common error when CLASSPATH is wrong. + +Tue Mar 16 15:51:15 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Cassowary.h: #include "config.h" + + * c++/ClSimplexSolver.cc: Use VERSION to init szCassowaryVersion. + +Tue Mar 16 12:44:33 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/**: Updated function names to always start with an uppercase + letter (follows C++ conventions, and brings API of Cassowary and + QOCA closer together). Used scripts/convert-ids to do the + conversion, along with scripts/ids-to-upper as the list of + conversions to do. + +Wed Mar 10 15:28:33 1999 Greg J Badros <gjb@cs.washington.edu> + + * Release v0.32. + +Wed Mar 10 11:36:37 1999 Greg J Badros <gjb@cs.washington.edu> + + * **/Makefile: Removed, since these are now generated by + autoconf from Makefile.in (which itself is generated by + automake from Makefile.am [only for some directories]) + + * configure.in: + + * c++/ClBug2.cc: Added to demonstrate a bug that Anthony Beurivé + reported. + + * c++/ClSimplexSolver.cc: Fix above-mentioned bug by changing the + coefficient of the added in removeConstraintInternal. + + * c++/ClReader.l: Reset the lexer on failed id lookup. + + * c++/ClC.cc, c++/ClC.h: Added VarMap access functionality, make + CL_ParseConstraint catch exceptions and return NULL on error + parsing. + + * c++/config.h.in, c++/stamp-h.in: Added, for automake/autoconf + support. + + * c++/Makefile.am: Improve installation support, updated for + ClBug2 + + * guile/Makefile.am: Build .x using guile-snarf + + * c++/Makefile.linux: Updated for ClBug2 + + * c++/demos/DraggableBox.h: Do not return references to + ClVariable-s -- just return by value since they are a handle + class. + + * guile/Makefile.am: changed name of library to + libcassowaryguile.a from libconstraints.a + + * java/CL.h: Added a String description argument to assert() to + permit easier tracking of failures. + + * java/ClSimplexSolver.java: Fix bug that Emmanuel Pietriga + reported -- use peek() to get at top element of _stkCedns stack + when removing edit variables in removeEditVarsTo(). Added + descriptions to assert()s and to throwing of ExCLInternalError. + Have the addBounds, addUpperBound, addLowerBound functions + propagate out ExCLInternalError-s instead of catching them and + printing an error message. Added messages to all assertions. + + * java/ClLinearExpression.java: Added description to throwing of + ExCLInternalError. + + * java/ClLinearInequality.java: Added description to throwing of + ExCLInternalError. + + * java/ExCLInternalError.java: Require description of the error in + constructor. + + * java/QuadDemo.java: Use System.err when printing errors, and + print the description of the exception. + + * smalltalk/ClKernel.app: Fix bug with not using the weight of a + constraint as the negating coefficient when removing a constraint. + +Mon Mar 8 16:40:17 1999 Greg J Badros <gjb@cs.washington.edu> + + * Added autoconf and partial automake support. Added numerous + Makefile.am's, renamed old Makefiles to Makefile.linux (and copied + to Makefile.in when I did not write a Makefile.am). Added + configure.in. + + * guile/cassowary_scm.cc: Use ClReader.h, not creader.h (I renamed + the file) + +Fri Mar 5 16:24:05 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile, c++/Cl.h: Fix for renaming of creader.* -> + ClReader.*; make C libraries as part of lib, shared_lib rules. + + * c++/ClReader.*: Added, renamed from creader.h, creader.y, + creader.l + + * c++/ClTableau.h, c++/ClTableau.cc: Added + printExternalVariablesTo() fn. + + * c++/ClSimplexSolver.cc: printExternalVariablesTo in + printInternalInfo. + + * c++/ClParseTest.cc: DO not include ClReader.h-- Cl.h includes it + + * c++/ClCTest.c: Make more like a browser-related test, use new + CL_TableauPrintExternalVariables() + + * c++/ClC.h, ClC.cc: Added CL_Tableau, + CL_TableauPrintExternalVariables. Use "ends" to terminate + strstreams. Make Strong Stays use medium strength stays. Make + CL_ParseConstraint call ClsFromSz instead of parsing the char * + itself. + +Thu Mar 4 19:08:23 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClVariable.h: Add assert(pclv) before dereferencing through + ClVariable's pclv member. + + * c++/Makefile: Added DYNLINK = yes/no variable for controlling + dynamic linking more easily. + + * c++/ClSimplexSolver.h: Changed PfnChangeClvCallback to take a + ClVariable * instead of a ClVariable. This make it easier for the + C interface since it has "CLV" as a "ClVariable *" and cannot + reason about ClVariable-s because it doesn't see the struct defn. + + * c++/ClC.cc, c++/ClC.h: Added CL_SimplexSolverSetEditedValue, + CL_SimplexSolverPrint, CL_SimplexSolverSetChangeClvCallback, + CL_VariableSetPv, CL_VariablePv. + + * c++/ClCTest.cc: Test CL_SimplexSolverSetEditedValue, CL_SimplexSolverPrint. + +Wed Mar 3 17:37:17 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.h (UpdateExternalVariables): Added this + function to provide a publicly available way to get at setExternalVariables() + + * c++/ClCTest.c, c++/ClC.h, c++/ClC.cc: Added for the beginnings + of a rudimentary C interface to the c++ library. + + * c++/Makefile: Updated to build ClCTest, libccassowary.so (the C + interface to Cassowary [for Amaya, initially]) + +Mon Mar 1 Greg J Badros <gjb@cs.washington.edu> + + * Release v0.31 + +Mon Mar 1 15:11:52 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClVariable.h: Added explict copy ctr. + + * c++/ClEditConstraint.h, c++/ClStayConstraint.h: Changed output + format so parentheses started by super:: call to ClConstraint.h + are closed properly. + + * c++/ClSimplexSolver.h, c++/ClSimplexSolver.cc: Undo removing a + pass by reference of ClVariable when used as an output argument. + Added printing for ClEditInfo class instancesm, + ClVarToEditInfoMap. + +Mon Mar 1 13:46:48 1999 Greg J Badros <gjb@cs.washington.edu> + + * README: Updated for version 0.31. + + * c++/Makefile: Added QocaBench.o to TEST_OBJS, comment out + CL_USE_HASH_MAP_AND_SET by default. + + * c++/ClTestColumns.cc: Allocate constraint objects on heap, not + as temporaries on local stack + + * c++/ClStayConstraint.h, c++/ClSimplexSolver.h, + c++/ClSimplexSolver.cc, c++/ClPoint.h, c++/ClLinearInequality.h, + c++/ClEditOrStayConstraint.h, c++/ClEditConstraint.h: Pass and + return ClVariable-s by value, not by reference. (Fixes bug in + QocaBench from re-use of a ClVariable object with the underlying + pointer different. + + * c++/Cl.h: include creader.h + + * c++/README: Fix spelling of deprecated, URL for WxWindows. + + * c++/test-ClConstraint.cc: Comment out unused variables + +Mon Mar 1 12:53:02 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/qdemos/QuadDemoWindow.cc: Allocate constraint objects on + heap, not as temporaries on local stack. + +Fri Feb 26 09:16:31 1999 Greg J Badros <gjb@cs.washington.edu> + + * wrappers/cassowary.i: Use .c_str() off of exception descriptions + to get the char * (description() now returns a string) + +Fri Feb 26 09:11:17 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClConstraint.h: Added FIsInSolver() + + * guile/cassowary_scm.cc: Wrap cl-constraint-is-in-solver? + +Thu Feb 25 18:58:55 1999 Greg J Badros <gjb@cs.washington.edu> + + * guile/cltests.scm: Added (use-modules..) invocation to get the + dynamically-loaded module so that it can be tested outside of + scwm. Updated to reflect changed behaviour in cl-add-stay. Added + some test code for make-cl-constraint-from-string. + + * guile/cassowary_scm.hpp: Added ScmMakeClConstraint(..) to + abstract out setting "answer" for the (now) two ClConstraint ctrs. + + * guile/cassowary_scm.cc: Added make-cl-constraint-from-string for + interfacing to the parser. Wrap + cl-constraint-change-{strength,weight}!. Make dynamically loadable + module! Fix BUG: was returning SCM_UNDEFINED instead of + SCM_UNSPECIFIED. + + * guile/Makefile: Build libconstraints.so, and necessary directory + structure if neeeded. + + +Thu Feb 25 18:41:34 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.h, c++/ClSimplexSolver.cc: Make constraints + get told when they're added/removed from a solver. This means + that constraints are no longer const params to add/remove + Constraint functions, and also that removeConstraint needs an + internal version that doesn't do the counting (since + removeConstraint can get called from addConstraint to clean up + after a failed addition). + + * c++/ClSimplexSolver.cc: Clean up uses of ClConstraint &cn -- + prefer ClConstraint *pcn even internally. + + * c++/ClConstraint.h: Added ChangeStrength(..), ChangeWeight(..) + and _times_added memvar along w/ private (for friend + ClSimplexSolver) addedTo(..) and removedFrom(..) functions. Only + permit strength/weight changing if constraint is in no solvers + presently. + + * c++/ClConstraint.cc: Output _times_added memvar in printOn(...) + +Thu Feb 25 15:58:27 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClErrors.h: Added parse error classes, and have description + return a "string" instead of a "char *" + + * c++/creader.y: Use exception ExCLParseErrorMisc in clerror, Use + ClVarLookupFunction instead of mapVars and fAutoCreate + + * c++/creader.l: Use ClVarLookupFunction instead of doing it + inline with mapVars and fAutoCreate; throw exceptions on errors. + + * c++/creader.h: Added ClVarLookupFunction and ClVarLookupInMap + and use them when parsing. + + * c++/Makefile: Added some dependencies for proper building of + .l,.y files + + * c++/ClSimplexSolver.cc: Descend VarInVarSet from + unary_function<..,..> + + * c++/ClParseTest.cc: Catch parse errors and display the message. + Use ClVarLookupInMap class + +Thu Feb 25 12:09:48 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.cc: Simplify removeConstraint to not use + references. + + * c++/ClSimplexSolver.h: Updated a comment + + * c++/ClTests.cc: Use addEditVar, beginEdit, and endEdit, instead + of building EditConstraints directly. + +Tue Feb 23 18:48:21 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/creader.y, c++/creader.h: Remove old crummy lexer. Added + fAutoCreate flag to PcnParseConstraint to allow parsing with + automatic introduction of newly-referenced variables. + + * c++/creader.l: Fixed bugs in missing tokens "|", "(", ")", and + permit "==" as a synonym for "=". Honour the _fAutoCreate flag by + introducing variables when needed. + + * c++/ClTests.cc: Display version id string at startup. + + * c++/ClSimplexSolver.cc, c++/Cl.h: Added szCassowaryVersion id + string. + + * c++/ClParseTest.cc: Test auto-addition of variable (fAutoCreate + = true) + +Tue Feb 23 18:12:23 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile: Build libcassowary.{a,so} by default, not + libcassowary-notrace.{a,so}. Remove special rule for building + ClParseTest; list creader-lex.o, creader.o in OBJS and have them + be a part of the library. + + * c++/ClVariable.h, c++/ClVariable.cc: Rename pmapSzPclv to + pmapStrPclv. Make it a map from "const string" not "string". + Make setName erase the old mapping, and add the new mapping. + + * c++/ClParseTest.cc: Accept "-" option to mean "rename x to foo" + for testing the setName change above. + + * c++/ClFloatVariable.cc: Do not output warning msg in setName -- + instead, do the right thing in ClVariable.h + +Tue Feb 23 08:55:28 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile: Fix build rules for bison/flex parser so + dependencies are correct. Added new targets, all-notests, + all-tests, make 'lib' the default target, and all really build + everything. + + * c++/creader.h, c++/creader.l, c++/creader.y: Take address of + ClVariable-s from the map's values (cannot use ClVariable in the + union directly because union members cannot have constructors). + #include ClVariable.h instead of fwd decl of ClVariable so that we + get the StringToVarMap typedef, too. + +Mon Feb 22 16:33:16 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile: Use CL_LIBRARY, not LIB_FILE, throughout. Use + flags for maximum performance. + + * c++/ClVariable.h, c++/ClConstraintHash.h, c++/Cassowary.h: + Divide pointer address by CL_PTR_HASH_DIVISOR in hash functions + + * c++/ClTests.cc: Added CL_SHOW_CNS_IN_BENCHMARK guard protecting + new displaying of constraints and listing of inconsistent constraints. + +Mon Feb 22 12:18:53 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClTests.cc (inconsistent3): Drop extra redundant + inconsistency for pedagogical reasons. Use simpler pointer-based + addConstraint in benchmark test + + * c++/ClSimplexSolver.h: Added addConstraintNoException, + removeConstraintNoException taking ClConstraint &'s -- deprecated. + Added CL_NO_DEPRECATED guard for turning off availability of + deprecated functions. + +Mon Feb 22 11:12:35 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.h: Added deprecated + FIsConstraintSatisfied(Constraint &) + + * guile/cassowary_scm.cc: Use ClConstraintToVarMap for return + value of ConstraintMap(). Pass Constraint *'s instead of &'s. + Use new name printOnVerbose instead of printDebugInfo. + +Fri Feb 19 Greg J Badros <gjb@cs.washington.edu> + + * Release v0.3. + +Fri Feb 19 18:00:49 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClTests.cc: Updated to fix below interface. + + * c++/ClSimplexSolver.cc, c++/ClSimplexSolver.h: make + addConstraint, addConstraintNoException, removeConstraint, + removeConstraintNoException take ClConstraint *'s instead of + ClConstraint &'s. Clarifies the mental model, and simplifies the + syntax. Old style is still accepted, but is deprecated. + +Fri Feb 19 17:41:45 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClFloatVariable.cc, c++/ClFloatVariable.h: Added -- moved + here from ClVariable.h, and renamed from class ClVariableRep since + they not what ClVariable wraps (ClVariable wraps + ClAbstractVariable) + + * c++/ClAbstractVariable.h: Fatten interface to include set_value, + change_value, setPv, and Pv. + + * c++/ClVariable.h, c++/ClVariable.cc: Move ClVariableRep into + ClFloatVariable.{h,cc}, and use pclv-> for + set_value, change_value, SetPv, and Pv since ClAbstractVariable + now has a fat interface and we do not need to do the dynamic + down-casting. + + * c++/Makefile: Added new files to build rules. + +Fri Feb 19 17:08:29 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/debug.h, c++/ClTableau.h: Move operator<< out into ClTableau.h + + * c++/ClVariable.h, c++/ClVariable.cc: Move some inline functions + into .cc so that the hash function can go in the .h file (some stl + dependency issue, it seems). + + * c++/ClErrors.h, c++/ClTypedefs.h: Move typedef for + ClConstraintSet from ClErrors.h into ClTypedefs.h, and have former + include the latter. + + * c++/Cassowary.h: #include ClConstraintHash.h + + * c++/ClConstraintHash.h: Added. The hash function needs to + appear before any typedef that uses a hash_map or hash_set, so + this file is included by Cassowary.h + +Fri Feb 19 08:45:24 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClSubgraphTest.cc: Fix some bugs just from not testing + completely. + + * c++/*: Fix bugs from not-updated-code hidden by #ifdefs. Builds + w/ all compile-options except -DCL_USE_HASH_MAP_AND_SET. Drop + some gratuitous appearances of ClAbstractVariable + +Thu Feb 18 18:53:56 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClLinearExpression.cc: Use clvNill when returning a + ClVariable instead of NULL + + * c++/ClVariable.h, c++/ClVariable.cc: operators ==, !=, < all should use the + contained pointers address, not value. Also define global clvNil, + isNil(). + + * c++/ClTests.cc: BUGFIX: #if 0 removed from adding stays in + simple1 test + + * c++/ClSimplexSolver.h: Use ClVariable-s internally for + ClObjectiveVariable-s. + + * c++/ClSimplexSolver.cc: Use ClVariable-s internally for + ClObjectiveVariable-s and replace ClAbstractVariable + *p{entryVar,exitVar} with ClVariable-s. (Use clvNil and isNil() + to test for not yet set). + +Thu Feb 18 Greg J Badros <gjb@cs.washington.edu> + + * c++/*: First compilable and almost working version with + ClVariable as a handle to ClVariableRep. Major simplifications + throughout. + +Thu Feb 18 14:22:14 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Makefile: Split out the options into += lists so they can be + flipped independently more easily. + + * c++/ClSimplexSolver.cc, c++/ClSimplexSolver.h: Added output + operation for ClConstraintToVarSetMap; use fFoundErrorVar flag to + simplify some redundant tests in removeConstraint -- no longer use + errorVarsCopy. + + * c++/CLVariable.h: Fix a comment's example. + + * c++/ClTypedefs.h: Use set always for ClTableauVarSet (Steve + Wolfman notes that it's faster as a set than as a hash_set). + + * c++/debug.h: Add CtrTracer, DtrTracer fns that do nothing when + not CL_TRACE + + * c++/ClConstraint.h: Invoke CtrTracer, DtrTracer in ctr, dtr for + finding memory problem + + * c++/ClTests.cc: Fix some long-time bugs in the use of ctrs that + build temporary objects whose lifetime was expected to be longer + than it was. + + * c++/*: Invert sense of CL_NO_TRACE to CL_TRACE + +Wed Feb 17 12:10:28 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClTypedefs.h: Added -- factored out useful typedefs from + ClSimplexSolver.h, ClTableau.h and put them in this file. + + * c++/ClTableau.h, c++/ClSimplexSolver.h, c++/debug.h: Use + ClTypedefs.h. Drop gdb_print (it uses printOn and printTo, now). + Renamed printDebugInfo to printOnVerbose (for generalized gdb + interface) + + * c++/ClSimplexSolver.cc: Fix two bugs where I was modifying data + structures indirectly while iterating over them. Remove a delete + that was premature to fix another bug in optimized builds. + + * c++/ClLinearExpression.h, c++/ClConstraint.h, + c++/ClAbstractVariable.h: Drop gdb_print(). + + * c++/ClSymbolicWeight.h: Use Number instead of double more consistently. + +Tue Feb 16 15:04:06 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/Cassowary.h,ClAbstractVariable.h,ClMap.h,ClSet.h,Makefile: Use + CL_USE_HASH_MAP_AND_SET, not USE_HASH_MAP_AND_SET. + + * c++/Cl.h: #undef CL_TRACE_VERBOSE ifdef CL_NO_IO + +Tue Feb 16 14:55:12 1999 Greg J Badros <gjb@cs.washington.edu> + + * java/ClVariable.java: Add setVarMap(..), getVarMap() for + maintaining symbol table of ClVariables. Added + setAttachedObject(..), getAttachedObject() for hanging something + off of a variable. + + * java/ClConstraint.java: Added setAttachedObject(..), + getAttachedObject() for hanging something off of a constraint. + + * java/ClTests.java: Added inconsistent3() and multiedit() tests + + * java/ClSimplexSolver.java: Manage multiple (nested) edits + properly. Provide access to the _markerVars var through + getConstraintMap() accessor. Deprecate resolve(Vector) fn. + +Tue Feb 16 14:29:46 1999 Greg J Badros <gjb@cs.washington.edu> + + * README: Updated reference to swig web site. + +Tue Feb 16 12:45:04 1999 Greg J Badros <gjb@cs.washington.edu> + + * java/ClSimplexSolver.java, java/ClEditInfo.java, java/Makefile: + Fixed Michael Kaufmann's bug. (See Feb 15 note for C++ version + two entries below.) + + * java/*.java: Updated copyright to include 1999. + +Tue Feb 16 10:51:01 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/*: Added CL_FIND_LEAK guard and ctr/ctr counters for + tracking various variable kinds. + +Mon Feb 15 18:38:06 1999 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClAbstractVariable.{cc,h}, ClSlackVariable.{cc,h}, + ClDummyVariable.{cc,h}: Add counters to ctr/dtr for leakage detection. + + * c++/ClSimplexSolver.{cc,h}: Replace ClConstraintAndIndex with + ClEditInfo, and remove ugliness of parallel vectors for edit + constraints. Drop _editPlusErrorVars, _editMinusErrorVars, + _prevEditConstants, and bundle them all up in the value end of the + map attached to _editVarMap. This fixes a bug reported in the + Java version by Michael Kaufmann long ago, and generally cleans + code up a bit. The resolve(vector<Number>) function is + deprecated, and now implemented in terms of the indices stored in + the new ClEditInfo class. + + * c++/*: Updated copyright to include 1999. + +1999-02-15 Greg J Badros <gjb@cs.washington.edu> + + * c++/ClVariable.{cc,h}, c++/ClAbstractVariable.h: Added + SetVarMap(..), VarMap(), and make variables given names get their + names mapped to the objects in the var map (for access when + parsing constraints as strings). Make setName() virtual so + ClVariable can override it. + +1999-02-12 Greg J Badros <gjb@cs.washington.edu> + + * c++/creader.{y,h}: New version from Steve Wolfman, slightly + updated for cleaner integration. Pass in a map<string,ClVariable + *> instead of an array of ClVariable; improve error handling a + bit. + + * c++/debug.h: Use ClMap, ClSet + + * c++/{ClMap.h,ClSet.h}: Added, for optionally using hash_map, + hash_set instead of map, set. + + * c++/ClSimplexSolver.{cc,h}: Added Steve Wolfman's explanation + support (added back map for marker->constraint, _fExplainFailure + var + getter & settor). Use ClMap, ClSet. Cleaned up some cerr + output, and use DEBUG_FAILURES cpp symbol to guard some output. + + * c++/Cassowary.h: Added operator() for hash<..> to support + hashing things used as keys in hash_map/hash_set + + * c++/ClErrors.h: Added ExCLRequiredFailureWithExplanation class + for explanation support. + + * c++/{ClLinearExpression.h,ClTableau.h}: Use ClMap, not map. Use + ClSet, not set. + + * c++/ClSymbolicWeight.h: Return a symbolic weight even when + assert(false) to avoid compiler warning. + +1999-02-11 Greg J Badros <gjb@cs.washington.edu> + + * guile/cassowary_scm.cc: Use cl-snarf.h, not scwm-snarf.h. Use + CL_PROC to denote primitives, not SCWM_PROC. Use + CL_VAR_INIT_PERMANENT macro for variables, and document them (the + strength objects only, for now). Fix the default strength of + cl-add-editvar to Strong, not Weak, and update docs (was cut&paste + error from the cl-add-stay primitive). Thanks Anthony Beurivé for + noticing this bug, too! + +Sat Jan 30 Greg Badros <gjb@cs.washington.edu> + + * Release v0.23. + +Sat Jan 30 13:16:31 1999 Greg Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.cc: Fixed bug in removing a stay + constraint. Was editing a vector in place while iterating over + it. Now I use remove_if and erase. Thanks to Anthony Beurivé for + noticing the bug. + + * c++/ClBug1.cc: Added -- bug report from Anthony Beurivé. + +Sat Jan 23 Greg Badros <gjb@cs.washington.edu> + + * Release v0.22. + +Sat Jan 23 16:46:27 1999 Greg Badros <gjb@cs.washington.edu> + + * guile/cassowary_scm.cc: Replace iarg uses with literal argument + index numbers. Use const_cast to avoid warnings when calling + ScmMakeClStrength on clsWeak,clsMedium,clsStrong,clsRequired objects + +Sat Jan 23 15:30:16 1999 Greg Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.cc: Added some comments, some explanations + when exceptions are thrown, and some minor cleanups, bug-fixes + + * c++/ClTests.cc: Added inconsistent3() test, and run it. + + * c++/ClStrength.h: Added _pv memvar, and setPv(), Pv() -- needed + for tracking ClStrengths in guile + + * guile/cassowary_scm.cc: Replace all iarg uses with the literal + number. Point ClStrength objects at their scheme-level object + using their new _pv field. Protect ClStrength objects properly. + +Sat Sep 19 17:08:21 1998 Greg Badros <gjb@cs.washington.edu> + + * c++/Makefile (CPPFLAGS): Added USE_GC, commented out, and added + OTHER_LIBS variable for linking with the gc library + +Sat Sep 19 17:01:16 1998 Greg Badros <gjb@cs.washington.edu> + + * c++/ClTableau.h: Added AssertValid() for testing integrity of + Tableau + + * c++/ClSymbolicWeight.h, c++/ClStrength.h, c++/ClSlackVariable.h, + c++/ClLinearExpression.h, c++/ClErrors.h, c++/ClDummyVariable.h, + c++/ClConstraint.h, c++/ClAbstractVariable.h: Descend objects + from "gc" class conditioned on USE_GC* pp macros + + * c++/Cassowary.h: Conditionally include gc_cpp.h ifdef USE_GC; + added NEWVAR and DELVAR macros for outputting debug information at + new/delete sites + + * c++/ClSimplexSolver.h: Call AssertValid before solving + + * c++/ClSimplexSolver.cc: Remove memory leak of the artificial + objective variable + + * c++/ClLinearExpression.h: Fix gdb_print to have a newline + + * c++/ClLeakTest: Added leakTest2 which more obviously leaks, and + use GC_gcollect() to force a collect + +Tue Sep 15 16:36:20 1998 Greg Badros <gjb@cs.washington.edu> + + * c++/ClTableau.h, ClTableau.cc: Handle removing vars from _columns more + carefully, and add gdb_print(), virtual destructor + + * c++/ClLinearExpression.h, c++/ClConstraint.h, + c++/ClAbstractVariable.h: Added gdb_print() + +Tue Sep 14 Greg Badros <gjb@cs.washington.edu> + + * Release v0.21. + +Wed Sep 9 09:46:35 1998 Greg Badros <gjb@cs.washington.edu> + + * c++/ClLinearExpression.h, c++/ClLinearExpression.cc: added uses + of 'typename' keyword as needed by egcs-1.1b's -pedantic (and the + C++ FDIS) + +Sun Sep 6 13:19:01 1998 Greg Badros <gjb@cs.washington.edu> + + * c++/ClSimplexSolver.h: Added _pv field, and Pv() setPv() getter + and setter + + * guile/cassowary_scm.cc: Use solver's _pv field to point + ClSimplexSolver back at the scheme object that wraps it + +Fri Sep 4 18:52:50 1998 Greg Badros <gjb@cs.washington.edu> + + * guile/cassowary_scm.hpp, guile/cassowary_scm.cc: Added PvFromScm + and ScmFromPv to hide the reinterpret casts used to store a scheme + object as the void * Pv() attached to a cassowary object. Attach + the scheme-level cl-variable to a ClVariable object. Added + `clv-attach!' and `clv-attached-object' to manipulate the attached + object (often better to use scheme level properties, though) + +Fri Sep 4 18:51:30 1998 Greg Badros <gjb@cs.washington.edu> + + * guile/Makefile: Use "perl" from path to run extract docs instead + of relying on #! line, and generate the -procedures.txt file as + well as the .sgml file + +Wed Sep 2 17:08:14 1998 Greg Badros <gjb@cs.washington.edu> + + * guile/cassowary_scm.cc, guile/cassowary_scm.hpp: Added + ClStayConstraint wrapper. Make cl-add-stay, cl-add-editvar take a + list of variables instead of a varargs last argument and instead + add two optional arguments STRENGTH and FACTOR (thus those + primitives remain backward compatible as long as only one variable + was given). + +Wed Sep 2 13:55:37 1998 Greg Badros <gjb@cs.washington.edu> + + * ClSimplexSolver.h: Added weight option to addEditVar and use it + + * ClLinearExpression.h: Added PconstClAbstractVariable, use it; + use ClVarToCoeffMap in coefficientFor. + +Thu Aug 6 20:56:45 1998 Greg Badros <gjb@cs.washington.edu> + + * Release v0.2. + +Thu Aug 6 20:41:40 1998 Greg Badros <gjb@cs.washington.edu> + + * ClTests.cc: Added multiedit() test for testing nested + beginEdit-s + + * ClSimplexSolver.h, ClSimplexSolver.cc: Support nested + beginEdit-s -- use removeEditVarsTo(n), and rewrite + removeAllEditVars in terms of the former; Use FIsSatisfied on + constraint and compare with testing internally for + FIsConstraintSatisfied() -- untested. + + * ClLinearInequality.h, ClLinearEquation.h, ClConstraint.h: Added + virtual FIsSatisfied + + * ClLinearExpression.h, ClLinearExpression.cc: Added evaluate() + + * ClAbstractVariable.h: Return 0 for value(), and make it a + virtual function. + +Wed Aug 5 16:10:56 1998 Greg Badros <gjb@cs.washington.edu> + + * ClStrength.h: Have ClStrength::symbolicWeight return a const + ref, instead of by value, make clsXXX const refs. + + * ClSimplexSolver.cc, ClLinearInequality.cc, ClLinearEquation.cc, + ClLinearConstraint.cc: Take ClStrengths by const refs + +Tue Aug 4 15:22:08 1998 Greg Badros <gjb@cs.washington.edu> + + * guile/cassowary_scm.cc, cassowary_scm.hpp: Move all inline + functions into .hpp file. Added cl-is-constraint-satisfied? + + * ClTableau.h: Added a rowExpression() const memfn, for + FIsConstraintSatisfied() + + * ClSimplexSolver.h, ClSimplexSolver.cc: Added (probably broken) + FIsConstraintSatisfied(cn) memfn -- needs testing + +Sun Aug 2 16:49:34 1998 Greg Badros <gjb@cs.washington.edu> + + * ClSimplexSolver.h: Added ConstraintMap() accessor to + _markerVars, for cl-constraint-list guile primitive + + * ClConstraint.h: Added setPv(), Pv(), and _pv field to a + constraint, for attaching extra information. + +Thu Jul 30 19:15:40 1998 Greg Badros <gjb@cs.washington.edu> + + * ClTests.cc: Added simple2, to test new EditMisuse exception on + editing a variable that is nowhere in the solver. + + * ClTableau.h, ClTableau.cc: Be more careful about inserting into + _externalParametricVars; add FIsBasicVar to assist that care. + + * ClSimplexSolver.cc, ClSimplexSolver.h: Added pfnCnSatCallback -- + does nothing for now; throw an ExCLEditMisuse exception if an + edit constraint is added on a variable that is not in the tableau + (needs at least a stay constraint in the solver); replace some + calls to rowExpression with FIsBasicVar when the latter is the + intent. + +Thu Jul 21 Greg Badros <gjb@cs.washington.edu> + + * ClVariable.h, ClVariable.cc: Added _pv field, settor and gettor. + + +ABOVE CHANGES ONLY IN C++ IMPLEMENTATION AND ITS WRAPPERS + +Fri Jul 17 19:24:54 1998 Greg Badros <gjb@cs.washington.edu> + + * ClVariable.h, .java: Added change_value memfn, and make it virtual + instead of setValue -- thus subclasses can specialize behaviour + when the variable gets set by the solver. + + * ClSimplexSolver.h, .java: Use change_value for setEditedValue if + the variable is not in the tableau; call resolve() before + removeAllEditVars in endEdit + + * ClSimplexSolver.cc, .java (setExternalVariables): Use change_value + instead of set_value when so subclasses can override and notice a + changed variable + +Thu Jul 16 19:49:45 1998 Greg Badros <gjb@cs.washington.edu> + + * Added setEditedValue(), FContainsVariable(), and addVar() to c++ + and Java implementations + + * Fixed bug in C++ and Java in solvers lacking stay constraints + that was due to not-updating the external parametric variables + set. + +Fri Jul 10 09:00:15 1998 Greg Badros <gjb@cs.washington.edu> + + * Fixed bug whereby a dummy variable was being pivoted into the + basis because pexpr->anyVariable() didn't guarantee the variable + it returned was a pivotable variable -- now it's called + anyPivotableVariable(), and does the right thing. + + * Fixed bug whereby column mappings that had no rows remained in + the list of columns -- now erase the column key when its value is + the empty set + + * Fixed bug whereby constraints that threw required failure + exceptions remained in the tableau (a removeConstraint on a + constraint that failed to be added used to succeed, now it does + not) + +Monday Jun 29 16:50:00 1998 Greg Badros <gjb@cs.washington.edu> + + * Release Cassowary v0.1 --- see local/POST-ANNOUNCE-TO for + list of places where it was announced + diff --git a/libs/cassowary/ClAbstractVariable.cc b/libs/cassowary/ClAbstractVariable.cc new file mode 100644 index 0000000000..b5502d4fbb --- /dev/null +++ b/libs/cassowary/ClAbstractVariable.cc @@ -0,0 +1,23 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClAbstractVariable.cc + +#include <cassowary/ClAbstractVariable.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +long ClAbstractVariable::iVariableNumber = 0; +#ifdef CL_FIND_LEAK +long ClAbstractVariable::cAbstractVariables = 0; +#endif + diff --git a/libs/cassowary/ClBug0.cc b/libs/cassowary/ClBug0.cc new file mode 100644 index 0000000000..09ca1826cb --- /dev/null +++ b/libs/cassowary/ClBug0.cc @@ -0,0 +1,102 @@ +// $Id$ + +#include <cassowary/Cl.h> + +/* This bug fixed --02/15/99 gjb + Replaced the parallel vectors for edit constraints + (the errorPlus..., errorMinus..., prevEditConstants vectors) + with a ClEditInfo class that is the Value of the _editVarMap map. + + Later I realized that I need to go to a _editVars list so that + multiple edits on the same variable that nest are handled properly. + --09/19/99 gjb +*/ + +int main() +{ + ClSimplexSolver solver; + + ClVariable x("x",7); + ClVariable y("y",8); + ClVariable z("z",9); + + solver + .AddStay(x) + .AddStay(y) + .AddStay(z); + + try { + solver.AddEditVar(x); + solver.AddEditVar(y); + solver.AddEditVar(z); + solver.BeginEdit(); + + solver.SuggestValue(x,1); + solver.SuggestValue(z,2); + + solver.RemoveEditVar(y); + + solver.SuggestValue(x,3); + solver.SuggestValue(z,4); + + solver.EndEdit(); + + } catch (ExCLError &e) { + cerr << e.description() << endl; + } + + cout << x << endl << y << endl << z <<endl; + +} + +#if 0 /* Message below */ + From: "Michael Kaufmann" <Michael.Kaufmann@ubs.com> + To: <noth@cs.washington.edu> + Subject: bugreport + Date: Thu, 1 Oct 1998 11:40:55 +0200 + Message-Id: <000001bded1f$973a2060$230e1fac@itc_mk.sbcs.swissbank.com> + Mime-Version: 1.0 + Content-Type: text/plain; + charset="iso-8859-1" + Content-Transfer-Encoding: 7bit + X-Priority: 3 (Normal) + X-Msmail-Priority: Normal + X-Mailer: Microsoft Outlook 8.5, Build 4.71.2173.0 + Importance: Normal + X-Mimeole: Produced By Microsoft MimeOLE V4.72.2106.4 + + Dear Mr Noth, + + I am currently working with the Java implementation of Cassowary and found + the following bug: + + If I Add several editConstraints, remove some of them again later and + perform a 'ClSimplexSolver.SuggestValue()', the indices of + 'ClConstraintAndIndex' in the variable 'cai' are sometimes wrong (see + ClSimplexSolver.SuggestValue(ClVariable v, double x), the 3rd line). This is + because if you remove an element from a 'java.util.Vector', and the element + is somewhere in the middle of the Vector, the indices of the Vector change. + (see java.util.Vector.removeElementAt(int index): + + public final synchronized void removeElementAt(int index) { + if (index >= elementCount) { + throw new ArrayIndexOutOfBoundsException(index + " >= " + + elementCount); + } + else if (index < 0) { + throw new ArrayIndexOutOfBoundsException(index); + } + int j = elementCount - index - 1; + if (j > 0) { + System.arraycopy(elementData, index + 1, elementData, index, j); + } + elementCount--; + elementData[elementCount] = null; /* to let gc do its work */ + } + + + My workaround now is, that everytime when I remove an EditVariable from the + Solver, I have to remove all the EditVariables and Add then the ones again, + that I do not want to remove. + +#endif diff --git a/libs/cassowary/ClBug1.cc b/libs/cassowary/ClBug1.cc new file mode 100644 index 0000000000..e7543757e3 --- /dev/null +++ b/libs/cassowary/ClBug1.cc @@ -0,0 +1,21 @@ +#include <cassowary/Cl.h> + +int main() +{ + ClVariable *var = new ClVariable(); + ClSimplexSolver *solver = new ClSimplexSolver(); + ClStayConstraint *stcn = new ClStayConstraint(*var,ClsWeak(),1.0); + + cout << *solver; + solver->AddConstraint(*stcn); + cout << *solver; + solver->RemoveConstraint(*stcn); + cout << *solver; +} +/* +The result is a segmentation fault when the constraint is removed. I +don't understand why. + +Anthony Beurive'" <beurive@labri.u-bordeaux.fr> +*/ + diff --git a/libs/cassowary/ClBug2.cc b/libs/cassowary/ClBug2.cc new file mode 100644 index 0000000000..3a1e424259 --- /dev/null +++ b/libs/cassowary/ClBug2.cc @@ -0,0 +1,130 @@ +/* $Id$ + +From: "Anthony Beurive'" <beurive@labri.u-bordeaux.fr> +Subject: cassowary +To: gjb@cs.washington.edu +Date: Tue, 9 Mar 1999 12:42:24 +0100 (CET) + +I believe there's a bug in cassowary. It seems to be related to the +previous one I encountered a while ago, concerning the removal of +constraints. + +The three following examples may help you to track the bug, I hope. + +-------------------------------------------------------------------------------- +#include "Cl.h" + +void main() +{ + ClSimplexSolver *solver = new ClSimplexSolver(); + ClVariable *var = new ClVariable(); + ClStayConstraint *stcn = new ClStayConstraint(*var,ClsWeak(),1.0); + + solver->AddConstraint(*stcn); + cout << *solver; + solver->RemoveConstraint(*stcn); + cout << *solver; +} +-------------------------------------------------------------------------------- +This works fine. + + +Now, the factor of the stay constraint is changed. +-------------------------------------------------------------------------------- +#include "Cl.h" + +void main() +{ + ClSimplexSolver *solver = new ClSimplexSolver(); + ClVariable *var = new ClVariable(); + ClStayConstraint *stcn = new ClStayConstraint(*var,ClsWeak(),2.0); + + solver->AddConstraint(*stcn); + cout << *solver; + solver->RemoveConstraint(*stcn); + cout << *solver; +} +-------------------------------------------------------------------------------- +The result is: +test2: ClSimplexSolver.cc:1199: void ClSimplexSolver::Optimize(class ClVariable): Assertion \ +`pzRow != __null' failed. +Aborted + + +Now, the solver is created after the variable. +-------------------------------------------------------------------------------- +#include "Cl.h" + +void main() +{ + ClVariable *var = new ClVariable(); + ClSimplexSolver *solver = new ClSimplexSolver(); + ClStayConstraint *stcn = new ClStayConstraint(*var,ClsWeak(),2.0); + + solver->AddConstraint(*stcn); + cout << *solver; + solver->RemoveConstraint(*stcn); + cout << *solver; +} +-------------------------------------------------------------------------------- +This works again. + + +Can you reproduce the same results? Maybe the cause is my c++ +compiler (egcs-2.90.29 980515 (egcs-1.0.3 release)). I don't know. + +*/ + +#include <cassowary/Cl.h> + +void foo1() +{ + ClSimplexSolver *solver = new ClSimplexSolver(); + ClVariable *var = new ClVariable(); + ClStayConstraint *stcn = new ClStayConstraint(*var,ClsWeak(),1.0); + + solver->AddConstraint(*stcn); + cout << *solver; + solver->RemoveConstraint(*stcn); + cout << *solver; +} + + +void foo2() +{ + ClSimplexSolver *solver = new ClSimplexSolver(); + ClVariable *var = new ClVariable(); + ClStayConstraint *stcn = new ClStayConstraint(*var,ClsWeak(),2.0); + + solver->AddConstraint(*stcn); + cout << *solver; + solver->RemoveConstraint(*stcn); + cout << *solver; +} + + +void foo3() +{ + ClVariable *var = new ClVariable(); + ClSimplexSolver *solver = new ClSimplexSolver(); + ClStayConstraint *stcn = new ClStayConstraint(*var,ClsWeak(),2.0); + + solver->AddConstraint(*stcn); + cout << *solver; + solver->RemoveConstraint(*stcn); + cout << *solver; +} + + +int main() +{ + cerr << "Test1: " << endl; + foo1(); + + cerr << "\nTest2: " << endl; + foo2(); + + cerr << "\nTest3: " << endl; + foo3(); + +} diff --git a/libs/cassowary/ClConstraint.cc b/libs/cassowary/ClConstraint.cc new file mode 100644 index 0000000000..1bc6be91b3 --- /dev/null +++ b/libs/cassowary/ClConstraint.cc @@ -0,0 +1,32 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClConstraint.cc + +#include <cassowary/ClConstraint.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +#ifndef CL_NO_IO +#include <cassowary/ClTableau.h> // for VarSet printing + +ostream & +ClConstraint::PrintOn(ostream &xo) const +{ + // Note that the trailing "= 0)" or ">= 0)" is missing, as derived classes will + // print the right thing after calling this function + xo << strength() << " w{" << weight() << "} ta{" + << _times_added << "} RO" << _readOnlyVars << " " << "(" << Expression(); + return xo; +} + +#endif diff --git a/libs/cassowary/ClDummyVariable.cc b/libs/cassowary/ClDummyVariable.cc new file mode 100644 index 0000000000..e1e9b39c0c --- /dev/null +++ b/libs/cassowary/ClDummyVariable.cc @@ -0,0 +1,12 @@ +// $Id$ + +#include <cassowary/ClDummyVariable.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +#ifdef CL_FIND_LEAK +long ClDummyVariable::cDummyVariables = 0; +#endif diff --git a/libs/cassowary/ClFDBinaryOneWayConstraint.cc b/libs/cassowary/ClFDBinaryOneWayConstraint.cc new file mode 100644 index 0000000000..e7bf7f1089 --- /dev/null +++ b/libs/cassowary/ClFDBinaryOneWayConstraint.cc @@ -0,0 +1,140 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClFDBinaryOneWayConstraint.cc + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +#include <cassowary/ClFDBinaryOneWayConstraint.h> +#include <cassowary/ClLinearConstraint.h> +#include <cassowary/ClTypedefs.h> +#include <cassowary/ClLinearExpression.h> + + +void +ClFDBinaryOneWayConstraint::EnsurePreconditionsForCn(const ClConstraint &cn) +{ + ClVarSet setRO = cn.ReadOnlyVars(); + if (setRO.size() > 1) + throw ExCLTooDifficultSpecial("Only 0 or 1 read only variables are allowed"); + const ClLinearExpression &expr = cn.Expression(); + const ClVarToNumberMap &terms = expr.Terms(); + if (terms.size() > 2) + throw ExCLTooDifficultSpecial("Cannot have more than 2 variables"); + if (terms.size() == 0) + throw ExCLTooDifficultSpecial("Must have at least 1 variable"); + if (terms.size() == 2 && setRO.size() == 0) + throw ExCLTooDifficultSpecial("Both variables cannot be read-write, one must be read-only"); + if (terms.size() == 1 && setRO.size() == 1) + throw ExCLTooDifficultSpecial("Single read-only variable in LinearConstraint -- must not be read-only."); + ClVariable clv = (*terms.begin()).first; + /* GJB:FIXME:: iterate over all the variables */ + if (!clv->IsFDVariable()) { + throw ExCLTooDifficultSpecial("FD constraint contains non-FD variables"); + } +} + +bool +ClFDBinaryOneWayConstraint::FCanConvertCn(const ClConstraint &cn) +{ + try { + EnsurePreconditionsForCn(cn); + return true; + } catch (...) { + return false; + } +} + + +ClFDBinaryOneWayConstraint::ClFDBinaryOneWayConstraint(const ClConstraint &cn) + :ClFDConstraint(cn.strength(), cn.weight()) +{ + EnsurePreconditionsForCn(cn); + list<FDNumber> l; + /* GJB:FIXME:: varargs inteface, with sentinel as first arg? */ + l.push_back(9); + l.push_back(10); + l.push_back(12); + l.push_back(14); + l.push_back(20); + + ClVarSet setRO = cn.ReadOnlyVars(); + + ClVariable clvRO = clvNil; + ClVariable clvROLinear = clvNil; + Number coeffRO = 0; + + ClVariable clvRW = clvNil; + Number coeffRW = 0; + + if (setRO.size() == 1) { + const ClVariable &clv = *(setRO.begin()); + if (clv->IsFDVariable()) + clvRO = clv; + else + clvRO = new ClFDVariable(clv.Name(),clv.IntValue(),l); + clvROLinear = clv; + } + const ClLinearExpression &expr = cn.Expression(); + const ClVarToNumberMap &terms = expr.Terms(); + + for (ClVarToNumberMap::const_iterator it = terms.begin(); + it != terms.end(); + ++it) { + ClVariable clv = (*it).first; + if (clv == clvROLinear) { + coeffRO = (*it).second; + } else { + if (clv->IsFDVariable()) + clvRW = clv; + else + clvRW = new ClFDVariable(clv.Name(),clv.Value(),l); + coeffRW = (*it).second; + } + } + assert(!clvRW.IsNil()); + if (coeffRW == 0) { + throw ExCLTooDifficultSpecial("RW variable's coefficient must be non-zero"); + } + + bool fInequality = cn.IsInequality(); + bool fStrictInequality = cn.IsStrictInequality(); + double rhs_constant = expr.Constant(); + + // now we have: + // coeffRW * clvRW + coeffRO * clvRO <REL> rhs_constant + // where <REL> is >= if fInequality, or = if !fInequality + // + // need: + // clvRW <REL> coefficient * clvRO + constant + // + // so: + // coefficient = -coeffRO/coeffRW + // constant = rhs_constant/coeffRW + + if (fStrictInequality) + _rel = cnGT; + else if (fInequality) + _rel = cnGEQ; + else + _rel = cnEQ; + + if (coeffRW < 0) + _rel = ReverseInequality(_rel); + + _coefficient = -coeffRO/coeffRW; + _constant = -rhs_constant/coeffRW; + _vRW = clvRW; + _vRO = clvRO; + return; +} diff --git a/libs/cassowary/ClFDConnectorVariable.cc b/libs/cassowary/ClFDConnectorVariable.cc new file mode 100644 index 0000000000..e6618eb9d4 --- /dev/null +++ b/libs/cassowary/ClFDConnectorVariable.cc @@ -0,0 +1,29 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClFDConnectorVariable.cc + +#include <cassowary/ClFDConnectorVariable.h> +#include <cassowary/ClSolver.h> // for list<FDNumber> printing + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +// Use < > for ClFDConnector-s, instead of [ ] +#ifndef CL_NO_IO +ostream &ClFDConnectorVariable::PrintOn(ostream &xo) const +{ + xo << "<" << Name() << "=" << Value() + << "{" << _clvFloat << "}" + << ":" << *PlfdnDomain() << ">"; + return xo; +} +#endif diff --git a/libs/cassowary/ClFDSolver.cc b/libs/cassowary/ClFDSolver.cc new file mode 100644 index 0000000000..7f2d199869 --- /dev/null +++ b/libs/cassowary/ClFDSolver.cc @@ -0,0 +1,364 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClFDSolver.cc + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +#include <cassowary/Cassowary.h> +#include <cassowary/ClFDSolver.h> +#include <cassowary/ClFDBinaryOneWayConstraint.h> +#include <cassowary/ClVariable.h> +#include <cassowary/debug.h> +#include <GTL/topsort.h> +#include <pair.h> +#include <math.h> +#include <stdarg.h> + +static int fDebugFDSolve; + +ClFDSolver & +ClFDSolver::AddConstraint(ClConstraint *const pcn) +{ + AddConstraintInternal(pcn); + if (_fAutosolve) Solve(); + return *this; +} + +ClFDSolver & +ClFDSolver::RemoveConstraint(ClConstraint *const pcn) +{ + RemoveConstraintInternal(pcn); + if (_fAutosolve) Solve(); + return *this; +} + +ClFDSolver & +ClFDSolver::AddConstraintInternal(ClConstraint *const pcn) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << *pcn << ")" << endl; +#endif + + ClFDBinaryOneWayConstraint *const pcnfd = + dynamic_cast<ClFDBinaryOneWayConstraint *const>(pcn); + if (!pcnfd) { + throw ExCLTooDifficultSpecial("Can only add ClFDBinaryOneWayConstraint-s to ClFDSolvers"); + } + ClVariable rw = pcnfd->ClvRW(); + ClVariable ro = pcnfd->ClvRO(); + if (!rw.IsFDVariable()) { + throw ExCLTooDifficultSpecial("RW variable must be an FDVariable"); + } + if (!(ro.IsNil() || ro.IsFDVariable())) { + throw ExCLTooDifficultSpecial("RO variable must be an FDVariable or clvNil"); + } + // add the constraint to our set of cns + _setCns.insert(pcn); + // and add the constraint to the cns that affect var rw + assert(!rw.IsNil()); + _mapClvToCns[rw].insert(pcn); + + + node nRw = GetVarNode(rw); + if (!ro.IsNil()) { + node nRo = GetVarNode(ro); + edge e = G.new_edge(nRo, nRw); + + _mapCnToEdge[pcn] = e; + + if (!G.is_acyclic()) { + /* there is a cycle... give up after cleaning up */ + RemoveConstraint(pcn); + throw ExCLCycleNotAllowed(); + } + } + return *this; +} + +ClFDSolver & +ClFDSolver::RemoveConstraintInternal(ClConstraint *const pcn) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << *pcn << ")" << endl; +#endif + + ClFDBinaryOneWayConstraint *const pcnfd = + dynamic_cast<ClFDBinaryOneWayConstraint *const>(pcn); + + if (!pcnfd) { + throw ExCLInternalError("Could not downcast to a ClFDBinaryOneWayConstraint"); + } + + ClConstraintSet::iterator itCn = _setCns.find(pcnfd); + if (itCn == _setCns.end()) { + throw ExCLConstraintNotFound(); + } + _setCns.erase(itCn); + + ClVariable rw = pcnfd->ClvRW(); + ClVariable ro = pcnfd->ClvRO(); + ClConstraintSet &_cnsAffectingRW = _mapClvToCns[rw]; + ClConstraintSet::iterator it = _cnsAffectingRW.find(pcnfd); + if (it == _cnsAffectingRW.end()) { + throw ExCLInternalError("Cannot find pcnfd"); + } + _cnsAffectingRW.erase(it); + + if (!ro.IsNil()) { + edge e = _mapCnToEdge[pcn]; + G.del_edge(e); + _mapCnToEdge.erase(pcn); + + if (_mapVarToNode.find(ro) != _mapVarToNode.end() && + _mapVarToNode[ro].degree() == 0) { + G.del_node(_mapVarToNode[ro]); + _mapVarToNode.erase(ro); + } + } + if (_mapVarToNode.find(rw) != _mapVarToNode.end() && + _mapVarToNode[rw].degree() == 0) { + G.del_node(_mapVarToNode[rw]); + _mapVarToNode.erase(rw); + } + if (_mapClvToCns[rw].size() == 0) { + _mapClvToCns.erase(rw); + } + + return *this; +} + +ClFDSolver & +ClFDSolver::Solve() +{ + topsort t; + t.run(G); + topsort::topsort_iterator it = t.top_order_begin(); + topsort::topsort_iterator end = t.top_order_end(); + ClSymbolicWeight errorTotal; + ResetSetFlagsOnVariables(); + for (; it != end; ++it) { + ClVariable clv = nodeToVar[*it]; + ClFDVariable *pcldv = dynamic_cast<ClFDVariable*>(clv.get_pclv()); +#ifndef NO_FDSOLVE_DEBUG + if (fDebugFDSolve) { + if (!clv.IsNil()) cout << "node " << (*it) << " is " << clv << endl; + cerr << "Set from: " << endl; + for (ClConstraintSet::iterator itCns = _mapClvToCns[clv].begin(); + itCns != _mapClvToCns[clv].end(); + ++itCns) { + const ClConstraint *pcn = *itCns; + cerr << *pcn << endl; + } + cerr << endl; + } +#endif + pair<ClSymbolicWeight,FDNumber> p = ComputeBest(pcldv); + ClSymbolicWeight e = p.first; + FDNumber v = p.second; + if (v == FDN_NOTSET) + throw ExCLRequiredFailure(); + pcldv->ChangeValue(v); + pcldv->SetFIsSet(true); + errorTotal += e; + } + return *this; +} + +/* return the best (lowest) incremental error and the value + at which that error occurs */ +pair<ClSymbolicWeight,FDNumber> +ClFDSolver::ComputeBest(ClFDVariable *pcldv) +{ + assert(pcldv); + // assert(!pcldv->FIsSet()); //GJB:FIXME:: + ClSymbolicWeight minError = ClsRequired().symbolicWeight(); + FDNumber bestValue = FDN_NOTSET; + // ClVariable clv(pcldv); + // for each domain value + for (list<FDNumber>::const_iterator itVal= pcldv->PlfdnDomain()->begin(); + itVal != pcldv->PlfdnDomain()->end(); + ++itVal) { + FDNumber value = *itVal; + ClSymbolicWeight error; + const ClConstraintSet &setCns = _mapClvToCns[pcldv]; + // for each constraint affecting *pcldv + for (ClConstraintSet::const_iterator itCn = setCns.begin(); + itCn != setCns.end(); + ++itCn) { + const ClConstraint *pcn = *itCn; + ClSymbolicWeight e = ErrorForClvAtValSubjectToCn(pcldv,value,*pcn); + error += e; + } + // now error is the total error for binding clv <- value + if (error < minError) { + minError = error; + bestValue = value; + } + } + // now minError is the lowest error we can get for clv + // and it occurs binding clv <- bestValue + if (bestValue == FDN_NOTSET) + throw ExCLRequiredFailure(); + return pair<ClSymbolicWeight,FDNumber>(minError,bestValue); +} + +ClSymbolicWeight +ClFDSolver::ErrorForClvAtValSubjectToCn(ClFDVariable *pcldv,FDNumber value,const ClConstraint &cn) +{ + const ClFDBinaryOneWayConstraint *pcnFd = dynamic_cast<const ClFDBinaryOneWayConstraint*>(&cn); + if (!pcnFd) throw ExCLInternalError("Not a binary FD constraint."); + ClCnRelation rel = pcnFd->Relation(); + double m = pcnFd->Coefficient(); + double b = pcnFd->Constant(); + ClVariable rw = pcnFd->ClvRW(); + ClVariable ro = pcnFd->ClvRO(); + assert(rw.get_pclv() == pcldv); + double e; + double x = ro.IsNil()? 0 : ro.Value(); + // return the error in satisfying: + // value REL m*x + b + double rhs = m*x + b; + switch (rel) { + case cnLEQ: + if (value <= rhs) e = 0; + else e = 1 + value-rhs; + break; + case cnLT: + if (value < rhs) e = 0; + else e = 1 + value-rhs; + break; + case cnGEQ: + if (value >= rhs) e = 0; + else e = 1+ rhs-value; + break; + case cnGT: + if (value > rhs) e = 0; + else e = 1 + rhs-value; + break; + case cnEQ: + if (value == rhs) e = 0; + else e = 1 + fabs(rhs-value); + break; + case cnNEQ: + if (value != rhs) e = 0; + else e = 1; /* GJB:FIXME:: what makes sense here? */ + break; + default: + e = 0; /* quiet warning */ + assert(false); + } + + ClSymbolicWeight err; + if (cn.IsRequired() && e > 0) + err = ClsRequired().symbolicWeight(); + else + err = cn.symbolicWeight() * (e*cn._weight); +#ifndef NO_FDSOLVE_DEBUG + if (fDebugFDSolve) { + cerr << "Error at " << value << " = " << err << endl; + } +#endif + return err; +} + + +ClFDSolver & +ClFDSolver::ShowSolve() +{ + topsort t; + t.run(G); + topsort::topsort_iterator it = t.top_order_begin(); + topsort::topsort_iterator end = t.top_order_end(); + for (; it != end; ++it) { + ClVariable clv = nodeToVar[*it]; + if (!clv.IsNil()) cout << "Node " << (*it) << " is " << clv << endl; + cout << "Set from: " << endl; + for (ClConstraintSet::iterator itCns = _mapClvToCns[clv].begin(); + itCns != _mapClvToCns[clv].end(); + ++itCns) { + const ClConstraint *pcn = *itCns; + cout << *pcn << endl; + } + cout << endl; + } + return *this; +} + + +/* Turn all FDVariable FIsSet() flags to false */ +void +ClFDSolver::ResetSetFlagsOnVariables() +{ + for (ClVarToConstraintSetMap::iterator it = _mapClvToCns.begin(); + it != _mapClvToCns.end(); + ++it) { + ClVariable clv = (*it).first; + ClFDVariable *pcldv = dynamic_cast<ClFDVariable*>(clv.get_pclv()); + assert(pcldv); + pcldv->SetFIsSet(false); + } +} + + +ostream & +ClFDSolver::PrintOn(ostream &xo) const +{ + xo << "FDSolver: " + << _setCns + << "Graph nodes, edges = " << G.number_of_nodes() << ", " << G.number_of_edges() + << endl; + return xo; +} + +ostream & +ClFDSolver::PrintInternalInfo(ostream &xo) const +{ return xo; } + + +ostream &operator<<(ostream &xo, const ClFDSolver &clfds) +{ return clfds.PrintOn(xo); } + + +//// protected member functions + +/* Create node for v in G, if necessary, + otherwise return the node we already created. */ +node +ClFDSolver::GetVarNode(ClVariable v) +{ + ClMap<ClVariable,node>::iterator it = _mapVarToNode.find(v); + if (it == _mapVarToNode.end()) { + node n = G.new_node(); + _mapVarToNode[v] = n; + nodeToVar[n] = v; + return n; + } else { + return (*it).second; + } +} + + +void +ListPushOnto(list<FDNumber> *pl, ...) +{ + va_list ap; + va_start(ap, pl); + FDNumber n; + while ( (n = va_arg(ap, FDNumber)) != FDN_EOL) { + pl->push_back(n); + } + va_end(ap); +} diff --git a/libs/cassowary/ClFDVariable.cc b/libs/cassowary/ClFDVariable.cc new file mode 100644 index 0000000000..5ab9d518b1 --- /dev/null +++ b/libs/cassowary/ClFDVariable.cc @@ -0,0 +1,27 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClFDVariable.cc + +#include <cassowary/ClFDVariable.h> +#include <cassowary/ClSolver.h> // for list<FDNumber> printing + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +// Use < > for ClFDVariable-s, instead of [ ] +#ifndef CL_NO_IO +ostream &ClFDVariable::PrintOn(ostream &xo) const +{ + xo << "<" << Name() << "=" << Value() << ":" << *PlfdnDomain() << ">"; + return xo; +} +#endif diff --git a/libs/cassowary/ClFloatVariable.cc b/libs/cassowary/ClFloatVariable.cc new file mode 100644 index 0000000000..a3096e4b08 --- /dev/null +++ b/libs/cassowary/ClFloatVariable.cc @@ -0,0 +1,25 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClFloatVariable.cc + +#include <cassowary/ClFloatVariable.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +#ifndef CL_NO_IO +ostream &ClFloatVariable::PrintOn(ostream &xo) const +{ + xo << "[" << Name() << ":" << _value << "]"; + return xo; +} +#endif diff --git a/libs/cassowary/ClLinearExpression.cc b/libs/cassowary/ClLinearExpression.cc new file mode 100644 index 0000000000..72383ffec1 --- /dev/null +++ b/libs/cassowary/ClLinearExpression.cc @@ -0,0 +1,473 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClLinearExpression.cc + +using namespace std; + +#include <cassowary/ClLinearExpression.h> +#include <cassowary/ClSymbolicWeight.h> /// needed only to instantiate with T=ClSymbolicWeight +#include <cassowary/ClVariable.h> +#include <cassowary/ClTableau.h> +#include <cassowary/ClErrors.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +template <class T> +ClGenericLinearExpression<T>::ClGenericLinearExpression(T num) : + _constant(num) +{ } + +// Convert from ClVariable to a ClLinearExpression +// this replaces ClVariable::asLinearExpression +template <class T> +ClGenericLinearExpression<T>::ClGenericLinearExpression(ClVariable clv, T value, + T Constant) : + _constant(Constant) +{ + _terms[clv] = value; +} + +template <class T> +ClGenericLinearExpression<T>::~ClGenericLinearExpression() +{ } + +#ifndef CL_NO_IO +template <class T> +ostream & +ClGenericLinearExpression<T>::PrintOn(ostream &xo) const +{ + typename ClVarToCoeffMap::const_iterator i = _terms.begin(); + + if (!ClApprox(_constant,0.0) || i == _terms.end()) + { + xo << _constant; + } + else + { + if (i == _terms.end()) + return xo; + xo << (*i).second << "*" << (*i).first; + ++i; + } + for ( ; i != _terms.end(); ++i) + { + xo << " + " << (*i).second << "*" << (*i).first; + } + return xo; +} +#endif + + + +// Destructively multiply self by x. +// (private memfn) +template <class T> +ClGenericLinearExpression<T> & +ClGenericLinearExpression<T>::MultiplyMe(T x) +{ + _constant *= x; + + typename ClVarToCoeffMap::const_iterator i = _terms.begin(); + for ( ; i != _terms.end(); ++i) + { + _terms[(*i).first] = (*i).second * x; + } + return *this; +} + +// Return a new linear expression formed by multiplying self by x. +// (Note that this result must be linear.) +template <class T> +ClGenericLinearExpression<T> +ClGenericLinearExpression<T>::Times(Number x) const +{ + ClGenericLinearExpression<T> result = *this; + return result.MultiplyMe(x); +} + +// Return a new linear expression formed by multiplying self by x. +// (Note that this result must be linear.) +// The above function optimizes the specific case of multiplying +// by a Constant, here is the more general case +template <class T> +ClGenericLinearExpression<T> +ClGenericLinearExpression<T>::Times(const ClGenericLinearExpression<T> &expr) const +{ + if (IsConstant()) + { + return expr.Times(_constant); + } + else if (!expr.IsConstant()) + { + // neither are constants, so we'd introduce non-linearity + throw ExCLNonlinearExpression(); + } + return Times(expr._constant); +} + + +// Return a new linear expression formed by adding x to self. +template <class T> +ClGenericLinearExpression<T> +ClGenericLinearExpression<T>::Plus(const ClGenericLinearExpression<T> &expr) const +{ + ClGenericLinearExpression<T> result = *this; + result.AddExpression(expr,1.0); + return result; +} + +// Return a new linear expression formed by subtracting x from self. +template <class T> +ClGenericLinearExpression<T> +ClGenericLinearExpression<T>::Minus(const ClGenericLinearExpression<T> &expr) const +{ + ClGenericLinearExpression<T> result = *this; + result.AddExpression(expr,-1.0); + return result; +} + +// Return a new linear expression formed by dividing self by x. +// (Note that this result must be linear.) +template <class T> +ClGenericLinearExpression<T> +ClGenericLinearExpression<T>::Divide(Number x) const +{ + if (ClApprox(x,0.0)) + { + throw ExCLNonlinearExpression(); + } + return Times(1.0/x); +} + +// Return a new linear expression formed by dividing self by x. +// (Note that this result must be linear.) +template <class T> +ClGenericLinearExpression<T> +ClGenericLinearExpression<T>::Divide(const ClGenericLinearExpression<T> &expr) const +{ + if (!expr.IsConstant()) + { + throw ExCLNonlinearExpression(); + } + return Divide(expr._constant); +} + + +// Return a new linear expression (expr/this). Since the result +// must be linear, this is permissible only if 'this' is a Constant. +template <class T> +ClGenericLinearExpression<T> +ClGenericLinearExpression<T>::DivFrom(const ClGenericLinearExpression<T> &expr) const +{ + if (!IsConstant() || ClApprox(_constant,0.0)) + { + throw ExCLNonlinearExpression(); + } + return expr.Divide(_constant); +} + +// Add n*expr to this expression for another expression expr. +template <class T> +ClGenericLinearExpression<T> & +ClGenericLinearExpression<T>::AddExpression(const ClGenericLinearExpression<T> &expr, Number n) +{ + IncrementConstant(expr.Constant()*n); + + typename ClVarToCoeffMap::const_iterator i = expr._terms.begin(); + for ( ; i != expr._terms.end(); ++i) + { + AddVariable((*i).first, (*i).second * n); + } + return *this; +} + +// Add n*expr to this expression for another expression expr. +// Notify the solver if a variable is added or deleted from this +// expression. +template <class T> +ClGenericLinearExpression<T> & +ClGenericLinearExpression<T>::AddExpression(const ClGenericLinearExpression<T> &expr, Number n, + ClVariable subject, + ClTableau &solver) +{ + IncrementConstant(expr.Constant() * n); + + typename ClVarToCoeffMap::const_iterator i = expr._terms.begin(); + for ( ; i != expr._terms.end(); ++i) + { + AddVariable((*i).first, (*i).second * n, subject, solver); + } + return *this; +} + +// Add a term c*v to this expression. If the expression already +// contains a term involving v, Add c to the existing coefficient. +// If the new coefficient is approximately 0, delete v. +template <class T> +ClGenericLinearExpression<T> & +ClGenericLinearExpression<T>::AddVariable(ClVariable v, T c) +{ // body largely duplicated below +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << v << ", " << c << ")" << endl; +#endif + typename ClVarToCoeffMap::iterator i = _terms.find(v); + if (i != _terms.end()) + { + // expression already contains that variable, so Add to it + T new_coefficient = 0; + new_coefficient = (*i).second + c; + if (ClApprox(new_coefficient,0.0)) + { + // new coefficient is Zero, so erase it + _terms.erase(i); + } + else + { + (*i).second = new_coefficient; + } + } + else // expression did not contain that variable + { + if (!ClApprox(c,0.0)) + { + _terms[v] = c; + } + } + return *this; +} + +// Add a term c*v to this expression. If the expression already +// contains a term involving v, Add c to the existing coefficient. +// If the new coefficient is approximately 0, delete v. Notify the +// solver if v appears or disappears from this expression. +template <class T> +ClGenericLinearExpression<T> & +ClGenericLinearExpression<T>::AddVariable(ClVariable v, T c, + ClVariable subject, + ClTableau &solver) +{ // body largely duplicated above +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << v << ", " << c << ", " << subject << ", ...)" << endl; +#endif + typename ClVarToCoeffMap::iterator i = _terms.find(v); + if (i != _terms.end()) + { + // expression already contains that variable, so Add to it + T new_coefficient = (*i).second + c; + if (ClApprox(new_coefficient,0.0)) + { + // new coefficient is Zero, so erase it + solver.NoteRemovedVariable((*i).first,subject); + _terms.erase(i); + } + else + { + (*i).second = new_coefficient; + } + } + else // expression did not contain that variable + { + if (!ClApprox(c,0.0)) + { + _terms[v] = c; + solver.NoteAddedVariable(v,subject); + } + } +#ifdef CL_TRACE + cerr << "Now *this == " << *this << endl; +#endif + return *this; +} + +// Return a variable in this expression. (It is an error if this +// expression is Constant -- signal ExCLInternalError in that case). +template <class T> +ClVariable +ClGenericLinearExpression<T>::AnyPivotableVariable() const +{ + if (IsConstant()) + { + throw ExCLInternalError("(ExCLInternalError) No pivotable variables in Constant expression"); + } + typename ClVarToCoeffMap::const_iterator i = _terms.begin(); + for ( ; i != _terms.end(); ++i) + { + ClVariable v = (*i).first; + if (v.IsPivotable()) + return v; + } + return clvNil; +} + +// Replace var with a symbolic expression expr that is equal to it. +// If a variable has been added to this expression that wasn't there +// before, or if a variable has been dropped from this expression +// because it now has a coefficient of 0, inform the solver. +// PRECONDITIONS: +// var occurs with a non-Zero coefficient in this expression. +template <class T> +void +ClGenericLinearExpression<T>::SubstituteOut(ClVariable var, + const ClGenericLinearExpression<T> &expr, + ClVariable subject, + ClTableau &solver) +{ +#ifdef CL_TRACE + cerr << "* ClGenericLinearExpression::"; + Tracer TRACER(__FUNCTION__); + cerr << "(" << var << ", " << expr << ", " << subject << ", " + << solver << ")" << endl; + cerr << "*this == " << *this << endl; +#endif + + typename ClVarToCoeffMap::iterator pv = _terms.find(var); + +#ifndef NDEBUG + if (pv == _terms.end()) + { +#ifndef CL_NO_IO + cerr << "SubstituteOut: pv != _terms.end()" << endl; + cerr << "(" << var << ", " << expr << ", " << subject << ", " + << ")" << endl; + cerr << "*this == " << *this << endl; +#endif + throw "SubstituteOut: pv != _terms.end()"; + } +#endif + assert(pv != _terms.end()); + // FIXGJB: this got thrown! assert(!ClApprox((*pv).second,0.0)); + + T multiplier = (*pv).second; + _terms.erase(pv); + IncrementConstant(multiplier * expr._constant); + typename ClVarToCoeffMap::const_iterator i = expr._terms.begin(); + for ( ; i != expr._terms.end(); ++i) + { + ClVariable v = (*i).first; + T c = (*i).second; + typename ClVarToCoeffMap::iterator poc = _terms.find(v); + if (poc != _terms.end()) + { // if oldCoeff is not nil +#ifdef CL_TRACE + cerr << "Considering (*poc) == " << (*poc).second << "*" << (*poc).first << endl; +#endif + // found it, so new coefficient is old one Plus what is in *i + T newCoeff = (*poc).second + (multiplier*c); + if (ClApprox(newCoeff,0.0)) + { + solver.NoteRemovedVariable((*poc).first,subject); + _terms.erase(poc); + } + else + { + (*poc).second = newCoeff; + } + } + else + { // did not have that variable already (oldCoeff == nil) +#ifdef CL_TRACE + cerr << "Adding (*i) == " << (*i).second << "*" << (*i).first << endl; +#endif + _terms[v] = multiplier * c; + solver.NoteAddedVariable(v,subject); + } + } +#ifdef CL_TRACE + cerr << "Now (*this) is " << *this << endl; +#endif +} + +// This linear expression currently represents the equation +// oldSubject=self. Destructively modify it so that it represents +// the equation NewSubject=self. +// +// Precondition: NewSubject currently has a nonzero coefficient in +// this expression. +// +// NOTES +// Suppose this expression is c + a*NewSubject + a1*v1 + ... + an*vn. +// +// Then the current equation is +// oldSubject = c + a*NewSubject + a1*v1 + ... + an*vn. +// The new equation will be +// NewSubject = -c/a + oldSubject/a - (a1/a)*v1 - ... - (an/a)*vn. +// Note that the term involving NewSubject has been dropped. +// +// Basically, we consider the expression to be an equation with oldSubject +// equal to the expression, then Resolve the equation for NewSubject, +// and destructively make the expression what NewSubject is then equal to +template <class T> +void +ClGenericLinearExpression<T>::ChangeSubject(ClVariable old_subject, + ClVariable new_subject) +{ + _terms[old_subject] = NewSubject(new_subject); +} + +inline double ReciprocalOf(double n) +{ return 1.0/n; } + +// This linear expression currently represents the equation self=0. Destructively modify it so +// that subject=self represents an equivalent equation. +// +// Precondition: subject must be one of the variables in this expression. +// NOTES +// Suppose this expression is +// c + a*subject + a1*v1 + ... + an*vn +// representing +// c + a*subject + a1*v1 + ... + an*vn = 0 +// The modified expression will be +// subject = -c/a - (a1/a)*v1 - ... - (an/a)*vn +// representing +// subject = -c/a - (a1/a)*v1 - ... - (an/a)*vn = 0 +// +// Note that the term involving subject has been dropped. +// +// Returns the reciprocal, so that NewSubject can be used by ChangeSubject +template <class T> +T +ClGenericLinearExpression<T>::NewSubject(ClVariable subject) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << subject << ")" << endl; +#endif + typename ClVarToCoeffMap::iterator pnewSubject = _terms.find(subject); + assert(pnewSubject != _terms.end()); + // assert(!ClApprox((*pnewSubject).second,0.0)); + T reciprocal = ReciprocalOf((*pnewSubject).second); + _terms.erase(pnewSubject); + MultiplyMe(-reciprocal); + return reciprocal; +} + +template <class T> +T +ClGenericLinearExpression<T>::Evaluate() const +{ + T answer = _constant; + typename ClVarToCoeffMap::const_iterator i = _terms.begin(); + + for ( ; i != _terms.end(); ++i) + { + ClVariable v = (*i).first; + answer += (*i).second * v.Value(); + } + return answer; +} + + +template class ClGenericLinearExpression<Number>; +// template class ClGenericLinearExpression<ClSymbolicWeight>; diff --git a/libs/cassowary/ClReader.l b/libs/cassowary/ClReader.l new file mode 100644 index 0000000000..77fa13a5a1 --- /dev/null +++ b/libs/cassowary/ClReader.l @@ -0,0 +1,87 @@ +/* $Id$ + Cassowary Incremental Constraint Solver + Original Smalltalk Implementation by Alan Borning + This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> + http://www.cs.washington.edu/homes/gjb + (C) 1998, 1999 Greg J. Badros and Alan Borning + See ../LICENSE for legal details regarding this software + + ClReader.l - Scanner for constraint parsing. + By Greg J. Badros + */ + +%{ +/* Get the token numbers that bison created for us + (uses the -d option of bison) */ + +#include <cassowary/ClReader.h> +#include "ClReader.cc.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +/* global variable for the istream we are reading from; + gets set by PcnParseConstraint */ +istream *pxi_lexer; + +/* Pass in an extra variable (ClParseData *) to cllex so that + it can look up variable names */ +#define YY_DECL int cllex(YYSTYPE *lvalp, void *YYLEX_PARAM) + +/* Make lexer reader from the global variable */ +#define YY_INPUT(buf,result,max_size) \ + do { if (pxi_lexer->get(buf[0]) && buf[0] > 0) result = 1; \ + else result = YY_NULL; } while (0) + +%} + +%option noyywrap + +DIGIT [0-9] +ALPHA [A-Za-z] +ALPHANUM [A-Za-z0-9] +ID_OK_PUNC [-_\[\]] +RO_ANNOTATION "?" +ID {ALPHA}({ALPHANUM}|{ID_OK_PUNC})*({RO_ANNOTATION})? +NUMID "{"{DIGIT}+"}" +ws [ \t\n]+ + +%% +{ws} /* skip whitespace */ +\n|";" { return 0; } +">=" { return GEQ; } +">" { return GT; } +"<=" { return LEQ; } +"<" { return LT; } +"==" { return '='; } +"="|"-"|"+"|"*"|"/"|"("|")" { return yytext[0]; } + +{DIGIT}+("."{DIGIT}*)? | +"."{DIGIT}+ { lvalp->num = strtod(yytext,0); return NUM; } + +{ID} { /* Lookup the variable name */ + ClParseData *pclpd = ((ClParseData *) YYLEX_PARAM); + int cch = strlen(yytext); + ClVariable *pclv = NULL; + bool fReadOnly = false; + if (yytext[cch-1] == '?') { + yytext[cch-1] = '\0'; + fReadOnly = true; + } + const string str = string(yytext); + pclv = pclpd->_lookup_func(str); + if (!pclv->IsNil()) { + lvalp->pclv = pclv; + return fReadOnly?RO_VAR:VAR; + } else { + pxi_lexer = NULL; + yy_flush_buffer(YY_CURRENT_BUFFER); + throw ExCLParseErrorBadIdentifier(str); + return 0; + } + } + +. { pxi_lexer = NULL; throw ExCLParseErrorMisc("Unrecognized character"); } + diff --git a/libs/cassowary/ClReader.y b/libs/cassowary/ClReader.y new file mode 100644 index 0000000000..f9f0dca43e --- /dev/null +++ b/libs/cassowary/ClReader.y @@ -0,0 +1,154 @@ +/* + $Id$ + + Cassowary Incremental Constraint Solver + Original Smalltalk Implementation by Alan Borning + This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> + http://www.cs.washington.edu/homes/gjb + (C) 1998, 1999 Greg J. Badros and Alan Borning + See ../LICENSE for legal details regarding this software + + ClReader.y + Original implementation contributed by Steve Wolfman + Subsequently largely revised by Greg J. Badros + + Supports parsing of read-only variables in constraints via "?" suffix + annotations on variables. If a variable is followed by "?" in any of + its occurrences in the constraint, that variable is deemed read-only + and entered into the constraint object as such. E.g., + + x = 2*y? + + is a one-way constraint that sets x from y's value. + + x = y + y? + and + x = y? + y + + are identical one-way constraints with y read-only. One would prefer + to have it written like so: + + x = y? + y? + + but it need not be, and no warning or error is raised. +*/ + + +%{ + /* C Declarations */ + +#include <cassowary/Cl.h> +#include <string> +#include <map> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +#ifdef USE_CRUMMY_LEXER +string current; /* Global to help in debugging/error messages */ +#endif + +/* Get yyparse, yylex to have an extra argument (type void *) */ +#define YYPARSE_PARAM cl_parse_data +#define YYLEX_PARAM cl_parse_data +#ifndef YYERROR_VERBOSE +#define YYERROR_VERBOSE +#endif +#define YYDEBUG 1 + +%} + + +/* Bison Declarations */ + +%pure_parser + +%union { + double num; + const ClVariable *pclv; + ClLinearExpression *pcle; + ClConstraint *pcn; +} + +%{ +int yylex(YYSTYPE *lvalp, void *YYLEX_PARAM); +void yyerror(const char *sz); +%} + +%start constraint + +%token <num> NUM +%token <pclv> VAR +%token <pclv> RO_VAR + +%token GEQ +%token GT +%token LEQ +%token LT + +%type <pcle> expr +%type <pcn> constraint equation inequality + +%left '-' '+' +%left '*' '/' +%left NEG + +%% +/* Grammar Rules */ + +constraint: equation { $$ = $1; ((ClParseData*)YYPARSE_PARAM)->_pcn = $1; } + | inequality { $$ = $1; ((ClParseData*)YYPARSE_PARAM)->_pcn = $1; } +; + +equation: expr '=' expr { $$ = new ClLinearEquation(*$1, *$3); } +; + +inequality: expr GEQ expr { $$ = new ClLinearInequality(*$1, cnGEQ, *$3); } + | expr LEQ expr { $$ = new ClLinearInequality(*$1, cnLEQ, *$3); } + | expr LT expr { $$ = new ClLinearInequality(*$1, cnLT, *$3); } + | expr GT expr { $$ = new ClLinearInequality(*$1, cnGT, *$3); } +; + +expr: NUM { $$ = new ClLinearExpression($1); } + | VAR { $$ = new ClLinearExpression(*$1); } + | RO_VAR { $$ = new ClLinearExpression(*$1); + ((ClParseData*)YYPARSE_PARAM)->_readOnlyVarsSoFar.insert(*$1); } + | expr '+' expr { $$ = new ClLinearExpression(*$1 + *$3); } + | expr '-' expr { $$ = new ClLinearExpression(*$1 - *$3); } + | expr '*' expr { $$ = new ClLinearExpression(*$1 * *$3); } + | expr '/' expr { $$ = new ClLinearExpression(*$1 / *$3); } + | '-' expr %prec NEG { $$ = new ClLinearExpression(-1 * *$2); } + | '(' expr ')' { $$ = $2; } +; + +%% + +void clerror(const char *sz) +{ + throw ExCLParseErrorMisc(sz); +} + +extern istream *pxi_lexer; + +// xi is the stream from which to read the constraint. +// aVars is an array of variables large enough to account for +// each one that might be mentioned in a constraint +ClConstraint *PcnParseConstraint(istream &xi, const ClVarLookupFunction &lookup_func, + const ClStrength &strength) +{ + ClParseData cl_parse_data(xi, lookup_func); + pxi_lexer = ξ + if (yyparse(&cl_parse_data) == 0) { // success +#ifdef DEBUG_PARSER + cerr << *cl_parse_data.Pcn() << endl; +#endif + cl_parse_data.Pcn()->ChangeStrength(strength); + cl_parse_data.Pcn()->AddROVars(cl_parse_data._readOnlyVarsSoFar); + return cl_parse_data.Pcn(); + } + else { // failed + return 0; + } +} diff --git a/libs/cassowary/ClSimplexSolver.cc b/libs/cassowary/ClSimplexSolver.cc new file mode 100644 index 0000000000..424a5d5aab --- /dev/null +++ b/libs/cassowary/ClSimplexSolver.cc @@ -0,0 +1,1633 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClSimplexSolver.cc + +using namespace std; + +#include <cassowary/debug.h> +#include <cassowary/ClSimplexSolver.h> +#include <cassowary/ClErrors.h> +#include <cassowary/ClVariable.h> +#include <cassowary/ClPoint.h> +#include <cassowary/ClSlackVariable.h> +#include <cassowary/ClObjectiveVariable.h> +#include <cassowary/ClDummyVariable.h> +#include <cassowary/cl_auto_ptr.h> + +#include <algorithm> +#include <float.h> +#include <sstream> +#include <queue> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +const char *szCassowaryVersion = VERSION; + +// Need to delete all expressions +// and all slack and dummy variables +// See NewExpression -- all allocation is done in there +ClSimplexSolver::~ClSimplexSolver() +{ +#ifdef CL_SOLVER_STATS + cerr << "_slackCounter == " << _slackCounter + << "\n_artificialCounter == " << _artificialCounter + << "\n_dummyCounter == " << _dummyCounter << endl; + cerr << "stayMinusErrorVars " << _stayMinusErrorVars.size() << ", " + << "stayPlusErrorVars " << _stayPlusErrorVars.size() << ", " + << "errorVars " << _errorVars.size() << ", " + << "markerVars " << _markerVars.size() << endl; +#endif + // Cannot print *this here, since local ClVariable-s may have been + // destructed already +} + +// Add the constraint cn to the tableau +ClSimplexSolver & +ClSimplexSolver::AddConstraint(ClConstraint *const pcn) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << *pcn << ")" << endl; +#endif + + if (!pcn->FIsOkayForSimplexSolver()) { + throw ExCLTooDifficultSpecial("SimplexSolver cannot handle this constraint object"); + } + + if (pcn->IsStrictInequality()) { + // cannot handle strict inequalities + throw ExCLStrictInequalityNotAllowed(); + } + + if (pcn->ReadOnlyVars().size() > 0) { + // cannot handle read-only vars + throw ExCLReadOnlyNotAllowed(); + } + + if (pcn->IsEditConstraint()) + { + ClEditConstraint *pcnEdit = dynamic_cast<ClEditConstraint *>(pcn); + const ClVariable &v = pcnEdit->variable(); + if (!v.IsExternal() || + (!FIsBasicVar(v) && !ColumnsHasKey(v))) + { + // we could try to make this case work, + // but it'd be unnecessarily inefficient -- + // and probably easier for the client application + // to deal with + throw ExCLEditMisuse("(ExCLEditMisuse) Edit constraint on variable not in tableau."); + } + ClEditInfo *pcei = PEditInfoFromClv(v); + if (pcei) + { + // we need to only add a partial _editInfoList entry for this + // edit constraint since the variable is already being edited. + // otherwise a more complete entry is added later in this function + _editInfoList.push_back(new ClEditInfo(v, NULL, clvNil, clvNil, 0)); + return *this; + } + } + + ClVariable clvEplus, clvEminus; + Number prevEConstant; + ClLinearExpression *pexpr = NewExpression(pcn, /* output to: */ + clvEplus,clvEminus, + prevEConstant); + bool fAddedOkDirectly = false; + + try + { + // If possible Add expr directly to the appropriate tableau by + // choosing a subject for expr (a variable to become basic) from + // among the current variables in expr. If this doesn't work use an + // artificial variable. After adding expr re-Optimize. + fAddedOkDirectly = TryAddingDirectly(*pexpr); + } + catch (ExCLRequiredFailure &error) + { +#ifdef CL_TRACE + cerr << "could not Add directly -- caught ExCLRequiredFailure error" << endl; +#endif + RemoveConstraintInternal(pcn); + throw; + } + + if (!fAddedOkDirectly) + { // could not Add directly + ExCLRequiredFailureWithExplanation e; + if (!AddWithArtificialVariable(*pexpr, e)) + { +#ifdef CL_DEBUG_FAILURES + cerr << "Failed solve! Could not Add constraint.\n" + << *this << endl; +#endif + RemoveConstraintInternal(pcn); + if (FIsExplaining()) + throw e; + else + throw ExCLRequiredFailure(); + } + } + + _fNeedsSolving = true; + + if (pcn->IsEditConstraint()) + { + ClEditConstraint *pcnEdit = dynamic_cast<ClEditConstraint *>(pcn); + ClVariable clv = pcnEdit->variable(); + _editInfoList.push_back(new ClEditInfo(clv, pcnEdit, clvEplus, clvEminus, + prevEConstant)); + } + + if (_fAutosolve) + { + Optimize(_objective); + SetExternalVariables(); + } + + pcn->addedTo(*this); + return *this; +} + +// Add weak stays to the x and y parts of each point. These have +// increasing weights so that the solver will try to satisfy the x +// and y stays on the same point, rather than the x stay on one and +// the y stay on another. +ClSimplexSolver & +ClSimplexSolver::AddPointStays(const vector<const ClPoint *> &listOfPoints, + const ClStrength &strength) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); +#endif + + vector<const ClPoint *>::const_iterator it = listOfPoints.begin(); + double weight = 1.0; + static const double multiplier = 2.0; + for ( ; it != listOfPoints.end(); ++it ) + { + AddPointStay((*it)->X(),(*it)->Y(),strength,weight); + weight *= multiplier; + } + return *this; +} + +ClSimplexSolver & +ClSimplexSolver::AddPointStay(const ClPoint &clp, const ClStrength &strength, double weight) +{ + AddPointStay(clp.X(),clp.Y(),strength,weight); + return *this; +} + + +ClSimplexSolver & +ClSimplexSolver::RemoveEditVarsTo(unsigned int n) +{ + queue<ClVariable> qclv; + ClVarSet sclvStillEditing; // Set of edit variables that we need to *not* remove +#ifdef DEBUG_NESTED_EDITS + cerr << __FUNCTION__ << " " << n << endl; +#endif + unsigned int i = 0; + for ( ClEditInfoList::const_iterator it = _editInfoList.begin(); + (it != _editInfoList.end() && _editInfoList.size() != static_cast<unsigned int>(n)); + ++it, ++i ) + { + const ClEditInfo *pcei = (*it); + assert(pcei); +#ifdef DEBUG_NESTED_EDITS + cerr << __FUNCTION__ << "Checking " << pcei->_clv + << ", index = " << i << endl; +#endif + if (i >= n) + qclv.push(pcei->_clv); + else + sclvStillEditing.insert(pcei->_clv); + } + while (!qclv.empty()) + { + ClVariable clv = qclv.front(); + // only remove the variable if it's not in the set of variable + // from a previous nested outer edit + // e.g., if I do: + // Edit x,y + // Edit w,h,x,y + // EndEdit + // The end edit needs to only get rid of the edits on w,h + // not the ones on x,y + if (sclvStillEditing.find(clv) == sclvStillEditing.end()) + { +#ifdef DEBUG_NESTED_EDITS + cerr << __FUNCTION__ << ": Removing " << clv << endl; +#endif + RemoveEditVar(clv); + } +#ifdef DEBUG_NESTED_EDITS + else + { + cerr << __FUNCTION__ << ": Not removing " << clv << endl; + } +#endif + qclv.pop(); + } + while (_editInfoList.size() > n) { + _editInfoList.pop_back(); + } + + return *this; +} + + +/* A predicate used for remove_if */ +class VarInVarSet : public unary_function<ClVariable,bool> { +public: + VarInVarSet(const ClVarSet &clvset) : + _set(clvset), + _setEnd(clvset.end()) + { } + + bool operator ()(ClVariable clv) const { + return (_set.find(clv) != _setEnd); + } + +private: + const ClVarSet &_set; + const ClVarSet::iterator _setEnd; +}; + + + +// Remove the constraint cn from the tableau +// Also remove any error variable associated with cn +ClSimplexSolver & +ClSimplexSolver::RemoveConstraintInternal(const ClConstraint *const pcn) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << *pcn << ")" << endl; +#endif + + // We are about to remove a constraint. There may be some stay + // constraints that were unsatisfied previously -- if we just + // removed the constraint these could come into play. Instead, + // Reset all of the stays so that things should stay where they are + // at the moment. + _fNeedsSolving = true; + + ResetStayConstants(); + + // remove any error variables from the objective function + ClLinearExpression *pzRow = RowExpression(_objective); + +#ifdef CL_TRACE + cerr << _errorVars << endl << endl; +#endif + + ClConstraintToVarSetMap::iterator + it_eVars = _errorVars.find(pcn); + bool fFoundErrorVar = (it_eVars != _errorVars.end()); + + if (fFoundErrorVar) + { + ClVarSet &eVars = (*it_eVars).second; + ClVarSet::iterator it = eVars.begin(); + for ( ; it != eVars.end(); ++it ) + { + const ClLinearExpression *pexpr = RowExpression(*it); + if (pexpr == NULL ) + { + pzRow->AddVariable(*it,-pcn->weight() * pcn->strength().symbolicWeight().AsDouble(), + _objective,*this); + } + else + { // the error variable was in the basis + pzRow->AddExpression(*pexpr,-pcn->weight() * pcn->strength().symbolicWeight().AsDouble(), + _objective,*this); + } + } + } + + ClConstraintToVarMap::iterator + it_marker = _markerVars.find(pcn); + if (it_marker == _markerVars.end()) + { // could not find the constraint + throw ExCLConstraintNotFound(); + } + // try to make the marker variable basic if it isn't already + const ClVariable marker = (*it_marker).second; + _markerVars.erase(it_marker); + _constraintsMarked.erase(marker); +#ifdef CL_TRACE + cerr << "Looking to remove var " << marker << endl; +#endif + if (!FIsBasicVar(marker)) + { // not in the basis, so need to do some work + // first choose which variable to move out of the basis + // only consider restricted basic variables + ClVarSet &col = _columns[marker]; + ClVarSet::iterator it_col = col.begin(); +#ifdef CL_TRACE + cerr << "Must Pivot -- columns are " << col << endl; +#endif + + ClVariable exitVar = clvNil; + bool fExitVarSet = false; + double minRatio = 0.0; + for ( ; it_col != col.end(); ++it_col) + { + const ClVariable &v = *it_col; + if (v.IsRestricted() ) + { + const ClLinearExpression *pexpr = RowExpression(v); + assert(pexpr != NULL ); + Number coeff = pexpr->CoefficientFor(marker); +#ifdef CL_TRACE + cerr << "Marker " << marker << "'s coefficient in " << *pexpr << " is " + << coeff << endl; +#endif + // only consider negative coefficients + if (coeff < 0.0) + { + Number r = - pexpr->Constant() / coeff; + if (!fExitVarSet || r < minRatio) + { + minRatio = r; + exitVar = v; + fExitVarSet = true; + } + } + } + } + // if we didn't set exitvar above, then either the marker + // variable has a positive coefficient in all equations, or it + // only occurs in equations for unrestricted variables. If it + // does occur in an equation for a restricted variable, pick the + // equation that gives the smallest ratio. (The row with the + // marker variable will become infeasible, but all the other rows + // will still be feasible; and we will be dropping the row with + // the marker variable. In effect we are removing the + // non-negativity restriction on the marker variable.) + if (!fExitVarSet) + { +#ifdef CL_TRACE + cerr << "exitVar did not get set" << endl; +#endif + it_col = col.begin(); + for ( ; it_col != col.end(); ++it_col) + { + ClVariable v = *it_col; + if (v.IsRestricted() ) + { + const ClLinearExpression *pexpr = RowExpression(v); + assert(pexpr != NULL); + Number coeff = pexpr->CoefficientFor(marker); + Number r = pexpr->Constant() / coeff; + if (!fExitVarSet || r < minRatio) + { + minRatio = r; + exitVar = v; + fExitVarSet = true; + } + } + } + } + + if (!fExitVarSet) + { // exitVar is still nil + // If col is empty, then exitVar doesn't occur in any equations, + // so just remove it. Otherwise pick an exit var from among the + // unrestricted variables whose equation involves the marker var + if (col.size() == 0) + { + RemoveColumn(marker); + } + else + { + // A. Beurive' Tue Sep 14 18:26:05 CEST 1999 + // Don't pick the objective, or it will be removed! + it_col = col.begin(); + for ( ; it_col != col.end(); ++it_col) + { + ClVariable v = *it_col; + if (v != _objective) + { + exitVar = v; + fExitVarSet = true; + break; + } + } + assert(fExitVarSet == true); + } + } + + if (fExitVarSet) + { + Pivot(marker,exitVar); + } + } + + if (FIsBasicVar(marker)) + { + ClLinearExpression *pexpr = RemoveRow(marker); +#ifdef CL_TRACE + cerr << "delete@ " << pexpr << endl; +#endif + delete pexpr; + } + + // Delete any error variables. If cn is an inequality, it also + // contains a slack variable; but we use that as the marker variable + // and so it has been deleted when we removed its row. + if (fFoundErrorVar) + { + ClVarSet &eVars = (*it_eVars).second; + ClVarSet::iterator it = eVars.begin(); + for ( ; it != eVars.end(); ++it ) + { + ClVariable v = (*it); + if (v != marker) + { + RemoveColumn(v); + } + } + } + + if (pcn->isStayConstraint()) + { + // iterate over the stay{Plus,Minus}ErrorVars and remove those + // variables v in those vectors that are also in set eVars + if (fFoundErrorVar) + { + ClVarSet &eVars = (*it_eVars).second; + _stayPlusErrorVars + .erase(remove_if(_stayPlusErrorVars.begin(),_stayPlusErrorVars.end(), + VarInVarSet(eVars)), + _stayPlusErrorVars.end()); + _stayMinusErrorVars + .erase(remove_if(_stayMinusErrorVars.begin(),_stayMinusErrorVars.end(), + VarInVarSet(eVars)), + _stayMinusErrorVars.end()); + } + } + else if (pcn->IsEditConstraint()) + { + const ClEditConstraint *pcnEdit = dynamic_cast<const ClEditConstraint *>(pcn); + const ClVariable clv = pcnEdit->variable(); + ClEditInfo *pcei = PEditInfoFromClv(clv); + assert(pcei); + ClVariable clvEditMinus = pcei->_clvEditMinus; + RemoveColumn(clvEditMinus); // clvEditPlus is a marker var and gets removed later + delete pcei; + _editInfoList.remove(pcei); + } + + if (fFoundErrorVar) + { + // This code is not needed since the variables are deleted + // when they are removed from the row -- + // leaving it in results in double deletions + // delete the constraint's error variables + // ClVarSet &evars_set = (*it_eVars).second; + // ClVarSet::const_iterator it_set = evars_set.begin(); + // for ( ; it_set != evars_set.end(); ++it_set) + // { + // delete *it_set; + // } + _errorVars.erase((*it_eVars).first); + } + + if (_fAutosolve) + { + Optimize(_objective); + SetExternalVariables(); + } + + return *this; +} + + +// Re-initialize this solver from the original constraints, thus +// getting rid of any accumulated numerical problems. (Actually, +// Alan hasn't observed any such problems yet, but here's the method +// anyway.) +void +ClSimplexSolver::Reset() +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "()" << endl; +#endif + // FIXGJB -- can postpone writing this for a while + // gotta be careful, though, as it's a likely place for + // a memory leak to sneak in + assert(false); +} + + +// Re-solve the cuurent collection of constraints, given the new +// values for the edit variables that have already been +// suggested (see SuggestValue() method) +void +ClSimplexSolver::Resolve() +{ // CODE DUPLICATED ABOVE +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); +#endif + DualOptimize(); + SetExternalVariables(); + _infeasibleRows.clear(); + if (_fResetStayConstantsAutomatically) + ResetStayConstants(); +} + +ClSimplexSolver & +ClSimplexSolver::SuggestValue(ClVariable v, Number x) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); +#endif + ClEditInfo *pcei = PEditInfoFromClv(v); + if (NULL == pcei) + { +#ifndef CL_NO_IO + std::stringstream ss; + ss << "SuggestValue for variable " << v << ", but var is not an edit variable" << ends; + throw ExCLEditMisuse(ss.str().c_str()); +#else + throw ExCLEditMisuse(v.Name().c_str()); +#endif + } + ClVariable clvEditPlus = pcei->_clvEditPlus; + ClVariable clvEditMinus = pcei->_clvEditMinus; + Number delta = x - pcei->_prevEditConstant; + pcei->_prevEditConstant = x; + DeltaEditConstant(delta,clvEditPlus,clvEditMinus); + return *this; +} + +// Re-solve the cuurent collection of constraints, given the new +// values for the edit variables that have already been +// suggested (see SuggestValue() method) +// This is not guaranteed to work if you remove an edit constraint +// from the middle of the edit constraints you added +// (e.g., edit A, edit B, edit C, remove B -> this will fail!) +// DEPRECATED +void +ClSimplexSolver::Resolve(const vector<Number> &newEditConstants) +{ + ClEditInfoList::iterator it = _editInfoList.begin(); + unsigned int i = 0; + for (; i < newEditConstants.size() && it != _editInfoList.end(); ++it, ++i) + { + ClEditInfo *pcei = (*it); + SuggestValue(pcei->_clv,newEditConstants[i]); + } + Resolve(); +} + + +//// protected + +// Add the constraint expr=0 to the inequality tableau using an +// artificial variable. To do this, create an artificial variable +// av and Add av=expr to the inequality tableau, then make av be 0. +// (Raise an exception if we can't attain av=0 -- and prepare explanation) +bool +ClSimplexSolver::AddWithArtificialVariable(ClLinearExpression &expr, + ExCLRequiredFailureWithExplanation &e) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << expr << ")" << endl; +#endif + + // Allocate the objects on the heap because the objects + // will remain in the tableau if we throw an exception, + // and that will result in the destructor cleaning up + // after us + ClSlackVariable *pav = new ClSlackVariable(++_artificialCounter,"a"); + ClObjectiveVariable *paz = new ClObjectiveVariable("az"); + ClLinearExpression *pazRow = new ClLinearExpression(expr); + // the artificial objective is av, which we know is equal to expr + // (which contains only parametric variables) + +#ifdef CL_FIND_LEAK + cerr << "aC = " << _artificialCounter + << "\nDeletes = " << _cArtificialVarsDeleted << endl; +#endif +#ifdef CL_TRACE + cerr << __FUNCTION__ << " before addRow-s:\n" + << (*this) << endl; +#endif + + // the artificial objective is av, which we know is equal to expr + // (which contains only parametric variables) + + // objective is treated as a row in the tableau, + // so do the substitution for its value (we are minimizing + // the artificial variable) + // this row will be removed from the tableau after optimizing + addRow(*paz,*pazRow); + + // now Add the normal row to the tableau -- when artifical + // variable is minimized to 0 (if possible) + // this row remains in the tableau to maintain the constraint + // we are trying to Add + addRow(*pav,expr); + +#ifdef CL_TRACE + cerr << __FUNCTION__ << " after addRow-s:\n" + << (*this) << endl; +#endif + + // try to Optimize az to 0 + // note we are *not* optimizing the real objective, but optimizing + // the artificial objective to see if the error in the constraint + // we are adding can be set to 0 + Optimize(*paz); + + // Careful, we want to get the Expression that is in + // the tableau, not the one we initialized it with! + ClLinearExpression *pazTableauRow = RowExpression(*paz); +#ifdef CL_TRACE + cerr << "pazTableauRow->Constant() == " << pazTableauRow->Constant() << endl; +#endif + + // Check that we were able to make the objective value 0 + // If not, the original constraint was not satisfiable + if (!ClApprox(pazTableauRow->Constant(),0.0)) + { + BuildExplanation(e, paz, pazTableauRow); + // remove the artificial objective row that we just + // added temporarily + delete RemoveRow(*paz); + // and delete the artificial objective variable that we also added above + delete paz; + return false; + } + + // see if av is a basic variable + const ClLinearExpression *pe = RowExpression(*pav); + if (pe != NULL) + { + // FIXGJB: do we ever even get here? + // Find another variable in this row and Pivot, so that av becomes parametric + // If there isn't another variable in the row then + // the tableau contains the equation av = 0 -- just delete av's row + if (pe->IsConstant()) + { + // FIXGJB: do we ever get here? + assert(ClApprox(pe->Constant(),0.0)); + delete RemoveRow(*pav); + // remove the temporary objective function + // FIXGJB may need this too: delete RemoveRow(*paz); + delete pav; +#ifdef CL_FIND_LEAK + ++_cArtificialVarsDeleted; +#endif + return true; + } + ClVariable entryVar = pe->AnyPivotableVariable(); + if (entryVar.IsNil()) + { + BuildExplanation(e, *pav, pe); + return false; /* required failure */ + } + Pivot(entryVar, *pav); + } + // now av should be parametric + assert(RowExpression(*pav) == NULL); + RemoveColumn(*pav); + delete pav; +#ifdef CL_FIND_LEAK + ++_cArtificialVarsDeleted; +#endif + // remove the temporary objective function + delete RemoveRow(*paz); + delete paz; + return true; +} + + +// Using the given equation (av = cle) build an explanation which +// implicates all constraints used to construct the equation. That +// is, everything for which the variables in the equation are markers. +void ClSimplexSolver::BuildExplanation(ExCLRequiredFailureWithExplanation &e, + ClVariable av, + const ClLinearExpression *pcle) +{ + ClVarToConstraintMap::iterator it_cn; + it_cn = _constraintsMarked.find(av); + if (it_cn != _constraintsMarked.end()) + { + e.AddConstraint((*it_cn).second); + } + + assert(pcle != NULL); + + const ClVarToNumberMap & terms = pcle->Terms(); + ClVarToNumberMap::const_iterator it_term; + for (it_term = terms.begin(); it_term != terms.end(); it_term++) + { + it_cn = _constraintsMarked.find((*it_term).first); + if (it_cn != _constraintsMarked.end()) + { + e.AddConstraint((*it_cn).second); + } + } +} + + + +// We are trying to Add the constraint expr=0 to the appropriate +// tableau. Try to Add expr directly to the tableaus without +// creating an artificial variable. Return true if successful and +// false if not. +bool +ClSimplexSolver::TryAddingDirectly(ClLinearExpression &expr) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << expr << ")" << endl; +#endif + ClVariable subject = ChooseSubject(expr); + if (subject.get_pclv() == NULL ) + { +#ifdef CL_TRACE + cerr << "- returning false" << endl; +#endif + return false; + } + expr.NewSubject(subject); + if (ColumnsHasKey(subject)) + { + SubstituteOut(subject,expr); + } + addRow(subject,expr); +#ifdef CL_TRACE + cerr << "- returning true" << endl; +#endif + return true; // successfully added directly +} + + +// We are trying to Add the constraint expr=0 to the tableaux. Try +// to choose a subject (a variable to become basic) from among the +// current variables in expr. If expr contains any unrestricted +// variables, then we must choose an unrestricted variable as the +// subject. Also, if the subject is new to the solver we won't have +// to do any substitutions, so we prefer new variables to ones that +// are currently noted as parametric. If expr contains only +// restricted variables, if there is a restricted variable with a +// negative coefficient that is new to the solver we can make that +// the subject. Otherwise we can't find a subject, so return nil. +// (In this last case we have to Add an artificial variable and use +// that variable as the subject -- this is done outside this method +// though.) +// +// Note: in checking for variables that are new to the solver, we +// ignore whether a variable occurs in the objective function, since +// new slack variables are added to the objective function by +// 'NewExpression:', which is called before this method. +ClVariable +ClSimplexSolver::ChooseSubject(ClLinearExpression &expr) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << expr << ")" << endl; +#endif + ClVariable subject(clvNil); // the current best subject, if any + + // true iff we have found a subject that is an unrestricted variable + bool foundUnrestricted = false; + + // true iff we have found a restricted variable that is new to the + // solver (except for being in the obj. function) and that has a + // negative coefficient + bool foundNewRestricted = false; + + const ClVarToNumberMap &terms = expr.Terms(); + ClVarToNumberMap::const_iterator it = terms.begin(); + for ( ; it != terms.end(); ++it ) + { + ClVariable v = (*it).first; + Number c = (*it).second; + + if (foundUnrestricted) + { + // We have already found an unrestricted variable. The only + // time we will want to use v instead of the current choice + // 'subject' is if v is unrestricted and new to the solver and + // 'subject' isn't new. If this is the case just pick v + // immediately and return. + if (!v.IsRestricted()) + { + if (!ColumnsHasKey(v)) + return v; + } + } + else + { // we haven't found an restricted variable yet + if (v.IsRestricted()) + { + // v is restricted. If we have already found a suitable + // restricted variable just stick with that. Otherwise, if v + // is new to the solver and has a negative coefficient pick + // it. Regarding being new to the solver -- if the variable + // occurs only in the objective function we regard it as being + // new to the solver, since error variables are added to the + // objective function when we make the Expression. We also + // never pick a dummy variable here. + if (!foundNewRestricted && !v.IsDummy() && c < 0.0) + { + const ClTableauColumnsMap &col = Columns(); + ClTableauColumnsMap::const_iterator it_col = col.find(v); + if (it_col == col.end() || + ( col.size() == 1 && ColumnsHasKey(_objective) ) ) + { + subject = v; + foundNewRestricted = true; + } + } + } + else + { + // v is unrestricted. + // If v is also new to the solver just pick it now + subject = v; + foundUnrestricted = true; + } + } + } + if (!subject.IsNil()) + return subject; + + // subject is nil. + // Make one last check -- if all of the variables in expr are dummy + // variables, then we can pick a dummy variable as the subject + Number coeff = 0; + it = terms.begin(); + for ( ; it != terms.end(); ++it ) + { + ClVariable v = (*it).first; + Number c = (*it).second; + if (!v.IsDummy()) + return clvNil; // nope, no luck + // if v is new to the solver, tentatively make it the subject + if (!ColumnsHasKey(v)) + { + subject = v; + coeff = c; + } + } + + // If we get this far, all of the variables in the Expression should + // be dummy variables. If the Constant is nonzero we are trying to + // Add an unsatisfiable required constraint. (Remember that dummy + // variables must take on a value of 0.) Otherwise, if the Constant + // is Zero, multiply by -1 if necessary to make the coefficient for + // the subject negative." + if (!ClApprox(expr.Constant(),0.0)) + { +#ifdef CL_DEBUG_FAILURES + cerr << "required failure in choose subject:\n" + << *this << endl; +#endif + if (FIsExplaining()) + { + ExCLRequiredFailureWithExplanation e; + BuildExplanation(e, clvNil, &expr); + throw e; + } + else + throw ExCLRequiredFailure(); + } + if (coeff > 0.0) + { + expr.MultiplyMe(-1); + } + return subject; +} + +// Each of the non-required edits will be represented by an equation +// of the form +// v = c + eplus - eminus +// where v is the variable with the edit, c is the previous edit +// value, and eplus and eminus are slack variables that hold the +// error in satisfying the edit constraint. We are about to change +// something, and we want to fix the constants in the equations +// representing the edit constraints. If one of eplus and eminus is +// basic, the other must occur only in the Expression for that basic +// error variable. (They can't both be basic.) Fix the Constant in +// this Expression. Otherwise they are both nonbasic. Find all of +// the expressions in which they occur, and fix the constants in +// those. See the UIST paper for details. +// (This comment was for resetEditConstants(), but that is now +// gone since it was part of the screwey vector-based interface +// to resolveing. --02/15/99 gjb) +void +ClSimplexSolver::DeltaEditConstant(Number delta, + ClVariable plusErrorVar, + ClVariable minusErrorVar) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << delta << ", " << plusErrorVar << ", " << minusErrorVar << ")" << endl; +#endif + // first check if the plusErrorVar is basic + ClLinearExpression *pexprPlus = RowExpression(plusErrorVar); + if (pexprPlus != NULL ) + { + pexprPlus->IncrementConstant(delta); + // error variables are always restricted + // so the row is infeasible if the Constant is negative + if (pexprPlus->Constant() < 0.0) + { + _infeasibleRows.insert(plusErrorVar); + } + return; + } + // check if minusErrorVar is basic + ClLinearExpression *pexprMinus = RowExpression(minusErrorVar); + if (pexprMinus != NULL) + { + pexprMinus->IncrementConstant(-delta); + if (pexprMinus->Constant() < 0.0) + { + _infeasibleRows.insert(minusErrorVar); + } + return; + } + // Neither is basic. So they must both be nonbasic, and will both + // occur in exactly the same expressions. Find all the expressions + // in which they occur by finding the column for the minusErrorVar + // (it doesn't matter whether we look for that one or for + // plusErrorVar). Fix the constants in these expressions. + ClVarSet &columnVars = _columns[minusErrorVar]; + ClVarSet::iterator it = columnVars.begin(); + for (; it != columnVars.end(); ++it) + { + ClVariable basicVar = *it; + ClLinearExpression *pexpr = RowExpression(basicVar); + assert(pexpr != NULL ); + double c = pexpr->CoefficientFor(minusErrorVar); + pexpr->IncrementConstant(c*delta); + if (basicVar.IsRestricted() && pexpr->Constant() < 0.0) + { + _infeasibleRows.insert(basicVar); + } + } +} + +// We have set new values for the constants in the edit constraints. +// Re-Optimize using the dual simplex algorithm. +void +ClSimplexSolver::DualOptimize() +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "()" << endl; +#endif + const ClLinearExpression *pzRow = RowExpression(_objective); + // need to handle infeasible rows + while (!_infeasibleRows.empty()) + { + ClVarSet::iterator it_exitVar = _infeasibleRows.begin(); + ClVariable exitVar = *it_exitVar; + _infeasibleRows.erase(it_exitVar); + ClVariable entryVar; + // exitVar might have become basic after some other pivoting + // so allow for the case of its not being there any longer + ClLinearExpression *pexpr = RowExpression(exitVar); + if (pexpr != NULL ) + { + // make sure the row is still not feasible + if (pexpr->Constant() < 0.0) + { + double ratio = DBL_MAX; + double r; + ClVarToNumberMap &terms = pexpr->Terms(); + ClVarToNumberMap::iterator it = terms.begin(); + for ( ; it != terms.end(); ++it ) + { + ClVariable v = (*it).first; + Number c = (*it).second; + if (c > 0.0 && v.IsPivotable()) + { + Number zc = pzRow->CoefficientFor(v); + r = zc/c; // FIXGJB r:= zc/c or Zero, as ClSymbolicWeight-s + if (r < ratio) + { + entryVar = v; + ratio = r; + } + } + } + if (ratio == DBL_MAX) + { + stringstream ss; + ss << "ratio == nil (DBL_MAX)" << ends; + throw ExCLInternalError(ss.str().c_str()); + } + Pivot(entryVar,exitVar); + } + } + } +} + +// Make a new linear Expression representing the constraint cn, +// replacing any basic variables with their defining expressions. +// Normalize if necessary so that the Constant is non-negative. If +// the constraint is non-required give its error variables an +// appropriate weight in the objective function. +ClLinearExpression * +ClSimplexSolver::NewExpression(const ClConstraint *pcn, + /* output to */ + ClVariable &clvEplus, + ClVariable &clvEminus, + Number &prevEConstant) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << *pcn << ")" << endl; + cerr << "cn.IsInequality() == " << pcn->IsInequality() << endl; + cerr << "cn.IsRequired() == " << pcn->IsRequired() << endl; +#endif + const ClLinearExpression &cnExpr = pcn->Expression(); + cl_auto_ptr<ClLinearExpression> pexpr ( new ClLinearExpression(cnExpr.Constant()) ); + cl_auto_ptr<ClSlackVariable> pslackVar; + cl_auto_ptr<ClDummyVariable> pdummyVar; + cl_auto_ptr<ClSlackVariable> peminus(0); + cl_auto_ptr<ClSlackVariable> peplus(0); + const ClVarToNumberMap &cnTerms = cnExpr.Terms(); + ClVarToNumberMap::const_iterator it = cnTerms.begin(); + for ( ; it != cnTerms.end(); ++it) + { + ClVariable v = (*it).first; + Number c = (*it).second; + const ClLinearExpression *pe = RowExpression(v); + if (pe == NULL) + { + pexpr->AddVariable(v,c); + } + else + { + pexpr->AddExpression(*pe,c); + } + } + + // Add slack and error variables as needed + if (pcn->IsInequality()) + { + // cn is an inequality, so Add a slack variable. The original + // constraint is expr>=0, so that the resulting equality is + // expr-slackVar=0. If cn is also non-required Add a negative + // error variable, giving + // expr-slackVar = -errorVar, in other words + // expr-slackVar+errorVar=0. + // Since both of these variables are newly created we can just Add + // them to the Expression (they can't be basic). + ++_slackCounter; + ReinitializeAutoPtr(pslackVar,new ClSlackVariable (_slackCounter, "s")); + pexpr->setVariable(*pslackVar,-1); + // index the constraint under its slack variable and vice-versa + _markerVars[pcn] = pslackVar.get(); + _constraintsMarked[pslackVar.get()] = pcn; + + if (!pcn->IsRequired()) + { + ++_slackCounter; + ReinitializeAutoPtr(peminus,new ClSlackVariable (_slackCounter, "em")); + pexpr->setVariable(*peminus,1.0); + // Add emnius to the objective function with the appropriate weight + ClLinearExpression *pzRow = RowExpression(_objective); + // FIXGJB: pzRow->AddVariable(eminus,pcn->strength().symbolicWeight() * pcn->weight()); + ClSymbolicWeight sw = pcn->strength().symbolicWeight().Times(pcn->weight()); + pzRow->setVariable(*peminus,sw.AsDouble()); + _errorVars[pcn].insert(peminus.get()); + NoteAddedVariable(*peminus,_objective); + } + } + else + { // cn is an equality + if (pcn->IsRequired()) + { + // Add a dummy variable to the Expression to serve as a marker + // for this constraint. The dummy variable is never allowed to + // enter the basis when pivoting. + ++_dummyCounter; + ReinitializeAutoPtr(pdummyVar,new ClDummyVariable (_dummyCounter, "d")); + pexpr->setVariable(*pdummyVar,1.0); + _markerVars[pcn] = pdummyVar.get(); + _constraintsMarked[pdummyVar.get()] = pcn; +#ifdef CL_TRACE + cerr << "Adding dummyVar == d" << _dummyCounter << endl; +#endif + } + else + { + // cn is a non-required equality. Add a positive and a negative + // error variable, making the resulting constraint + // expr = eplus - eminus, + // in other words: expr-eplus+eminus=0 + ++_slackCounter; + ReinitializeAutoPtr(peplus,new ClSlackVariable (_slackCounter, "ep")); + ReinitializeAutoPtr(peminus,new ClSlackVariable (_slackCounter, "em")); + + pexpr->setVariable(*peplus,-1.0); + pexpr->setVariable(*peminus,1.0); + // index the constraint under one of the error variables + _markerVars[pcn] = peplus.get(); + _constraintsMarked[peplus.get()] = pcn; + + ClLinearExpression *pzRow = RowExpression(_objective); + // FIXGJB: pzRow->AddVariable(eplus,pcn->strength().symbolicWeight() * pcn->weight()); + ClSymbolicWeight sw = pcn->strength().symbolicWeight().Times(pcn->weight()); + double swCoeff = sw.AsDouble(); +#ifdef CL_TRACE + if (swCoeff == 0) + { + cerr << "sw == " << sw << endl + << "cn == " << *pcn << endl; + cerr << "adding " << *peplus << " and " << *peminus + << " with swCoeff == " << swCoeff << endl; + } +#endif + pzRow->setVariable(*peplus,swCoeff); + NoteAddedVariable(*peplus,_objective); + // FIXGJB: pzRow->AddVariable(eminus,pcn->strength().symbolicWeight() * pcn->weight()); + pzRow->setVariable(*peminus,swCoeff); + NoteAddedVariable(*peminus,_objective); + _errorVars[pcn].insert(peminus.get()); + _errorVars[pcn].insert(peplus.get()); + if (pcn->isStayConstraint()) + { + _stayPlusErrorVars.push_back(peplus.get()); + _stayMinusErrorVars.push_back(peminus.get()); + } + else if (pcn->IsEditConstraint()) + { + clvEplus = peplus.get(); + clvEminus = peminus.get(); + prevEConstant = cnExpr.Constant(); + } + } + } + + // the Constant in the Expression should be non-negative. + // If necessary normalize the Expression by multiplying by -1 + if (pexpr->Constant() < 0) + { +#ifdef CL_TRACE + cerr << "NewExpression's Constant is " << pexpr->Constant() << ", < 0, so flipping" << endl; +#endif + pexpr->MultiplyMe(-1); + } +#ifdef CL_TRACE + cerr << "- returning " << *pexpr << endl; +#endif + // Terrible Name -- release() does *not* delete the object, + // only makes sure that the destructor won't delete the object + // (it releases the cl_auto_ptr from the responsibility of deleting the object) + pslackVar.release(); + pdummyVar.release(); + peminus.release(); + peplus.release(); + return pexpr.release(); +} + +// Minimize the value of the objective. (The tableau should already +// be feasible.) +void +ClSimplexSolver::Optimize(ClVariable zVar) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << zVar << ")\n" + << *this << endl; +#endif + ClLinearExpression *pzRow = RowExpression(zVar); + assert(pzRow != NULL); + ClVariable entryVar = clvNil; + ClVariable exitVar = clvNil; + while (true) + { + Number objectiveCoeff = 0; + // Find the most negative coefficient in the objective function + // (ignoring the non-pivotable dummy variables). If all + // coefficients are positive we're done + ClVarToNumberMap &terms = pzRow->Terms(); + ClVarToNumberMap::iterator it = terms.begin(); + for (; it != terms.end(); ++it) + { + ClVariable v = (*it).first; + Number c = (*it).second; + if (v.IsPivotable() && c < objectiveCoeff) + { + objectiveCoeff = c; + entryVar = v; + // A. Beurive' Tue Jul 13 23:03:05 CEST 1999 Why the most + // negative? I encountered unending cycles of pivots! + break; + } + } + // if all coefficients were positive (or if the objective + // function has no pivotable variables) + // we are at an optimum + if (objectiveCoeff >= -_epsilon) + return; +#ifdef CL_TRACE + cerr << "entryVar == " << entryVar << ", " + << "objectiveCoeff == " << objectiveCoeff + << endl; +#endif + + // choose which variable to move out of the basis + // Only consider pivotable basic variables + // (i.e. restricted, non-dummy variables) + double minRatio = DBL_MAX; + ClVarSet &columnVars = _columns[entryVar]; + ClVarSet::iterator it_rowvars = columnVars.begin(); + Number r = 0.0; + for (; it_rowvars != columnVars.end(); ++it_rowvars) + { + ClVariable v = *it_rowvars; +#ifdef CL_TRACE + cerr << "Checking " << v << endl; +#endif + if (v.IsPivotable()) + { + const ClLinearExpression *pexpr = RowExpression(v); + Number coeff = pexpr->CoefficientFor(entryVar); + // only consider negative coefficients + if (coeff < 0.0) + { + r = - pexpr->Constant() / coeff; + if (r < minRatio) + { +#ifdef CL_TRACE + cerr << "New minRatio == " << r << endl; +#endif + minRatio = r; + exitVar = v; + } + } + } + } + // If minRatio is still nil at this point, it means that the + // objective function is unbounded, i.e. it can become + // arbitrarily negative. This should never happen in this + // application. + if (minRatio == DBL_MAX) + { + stringstream ss; + ss << "objective function is unbounded!" << ends; + throw ExCLInternalError(ss.str().c_str()); + } + Pivot(entryVar, exitVar); +#ifdef CL_TRACE + cerr << "After Optimize:\n" + << *this << endl; +#endif + } +} + +// Do a Pivot. Move entryVar into the basis (i.e. make it a basic variable), +// and move exitVar out of the basis (i.e., make it a parametric variable) +void +ClSimplexSolver::Pivot(ClVariable entryVar, ClVariable exitVar) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << entryVar << ", " << exitVar << ")" << endl; +#endif + + // the entryVar might be non-pivotable if we're doing a RemoveConstraint -- + // otherwise it should be a pivotable variable -- enforced at call sites, + // hopefully + + // expr is the Expression for the exit variable (about to leave the basis) -- + // so that the old tableau includes the equation: + // exitVar = expr + ClLinearExpression *pexpr = RemoveRow(exitVar); + + // Compute an Expression for the entry variable. Since expr has + // been deleted from the tableau we can destructively modify it to + // build this Expression. + pexpr->ChangeSubject(exitVar,entryVar); + SubstituteOut(entryVar,*pexpr); + + if (entryVar.IsExternal()) + { + // entry var is no longer a parametric variable since we're moving + // it into the basis + _externalParametricVars.erase(entryVar); + } + addRow(entryVar,*pexpr); +} + + + +// Each of the non-required stays will be represented by an equation +// of the form +// v = c + eplus - eminus +// where v is the variable with the stay, c is the previous value of +// v, and eplus and eminus are slack variables that hold the error +// in satisfying the stay constraint. We are about to change +// something, and we want to fix the constants in the equations +// representing the stays. If both eplus and eminus are nonbasic +// they have value 0 in the current solution, meaning the previous +// stay was exactly satisfied. In this case nothing needs to be +// changed. Otherwise one of them is basic, and the other must +// occur only in the Expression for that basic error variable. +// Reset the Constant in this Expression to 0. +void +ClSimplexSolver::ResetStayConstants() +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "()" << endl; +#endif + ClVarVector::const_iterator + itStayPlusErrorVars = _stayPlusErrorVars.begin(); + ClVarVector::const_iterator + itStayMinusErrorVars = _stayMinusErrorVars.begin(); + + for ( ; itStayPlusErrorVars != _stayPlusErrorVars.end(); + ++itStayPlusErrorVars, ++itStayMinusErrorVars ) + { + ClLinearExpression *pexpr = RowExpression(*itStayPlusErrorVars); + if (pexpr == NULL ) + { + pexpr = RowExpression(*itStayMinusErrorVars); + } + if (pexpr != NULL) + { + pexpr->Set_constant(0.0); + } + } +} + +// Set the external variables known to this solver to their appropriate values. +// Set each external basic variable to its value, and set each +// external parametric variable to 0. (It isn't clear that we will +// ever have external parametric variables -- every external +// variable should either have a stay on it, or have an equation +// that defines it in terms of other external variables that do have +// stays. For the moment I'll put this in though.) Variables that +// are internal to the solver don't actually store values -- their +// values are just implicit in the tableu -- so we don't need to set +// them." +void +ClSimplexSolver::SetExternalVariables() +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "()\n" + << *this << endl; +#endif + + // FIXGJB -- oughta check some invariants here + + // Set external parametric variables first + // in case I've screwed up + ClVarSet::iterator itParVars = _externalParametricVars.begin(); + for ( ; itParVars != _externalParametricVars.end(); ++itParVars ) + { + ClVariable v = *itParVars; +#ifndef NDEBUG + // defensively skip it if it is basic -- ChangeValue is virtual + // so don't want to call it twice; this should never + // happen + if (FIsBasicVar(v)) + { +#ifndef CL_NO_IO + // WARNING + cerr << __FUNCTION__ << "Error: variable " << v + << " in _externalParametricVars is basic" << endl; + cerr << "Row is: " << *RowExpression(v) << endl; +#endif + continue; + } +#endif + ChangeClv(v,0.0); + } + + // Only iterate over the rows w/ external variables + ClVarSet::iterator itRowVars = _externalRows.begin(); + for ( ; itRowVars != _externalRows.end() ; ++itRowVars ) + { + ClVariable v = *itRowVars; + ClLinearExpression *pexpr = RowExpression(v); + ChangeClv(v,pexpr->Constant()); + } + + _fNeedsSolving = false; + if (_pfnResolveCallback) + _pfnResolveCallback(this); +} + +#ifndef CL_NO_IO +ostream & +PrintTo(ostream &xo, const ClVarVector &varlist) +{ + ClVarVector::const_iterator it = varlist.begin(); + xo << varlist.size() << ":" << "[ "; + if (it != varlist.end()) + { + xo << *it; + ++it; + } + for (; it != varlist.end(); ++it) + { + xo << ", " << *it; + } + xo << " ]"; + return xo; +} + +ostream &operator<<(ostream &xo, const ClVarVector &varlist) +{ return PrintTo(xo,varlist); } + + +ostream & +PrintTo(ostream &xo, const ClConstraintToVarSetMap &mapCnToVarSet) +{ + ClConstraintToVarSetMap::const_iterator it = mapCnToVarSet.begin(); + for ( ; it != mapCnToVarSet.end(); ++it) { + const ClConstraint *pcn = (*it).first; + const ClVarSet &set = (*it).second; + xo << "CN: " << pcn << *pcn << ":: " << set << endl; + } + return xo; +} + +ostream &operator <<(ostream &xo, const ClConstraintToVarSetMap &mapCnToVarSet) +{ return PrintTo(xo,mapCnToVarSet); } + + + +ostream & +ClSimplexSolver::PrintOn(ostream &xo) const +{ + ClTableau::PrintOn(xo); + + xo << "_stayPlusErrorVars: " + << _stayPlusErrorVars << endl; + xo << "_stayMinusErrorVars: " + << _stayMinusErrorVars << endl; + xo << "_editInfoList:\n" + << _editInfoList << endl; + return xo; +} + + +ostream & +ClSimplexSolver::PrintInternalInfo(ostream &xo) const +{ + ClTableau::PrintInternalInfo(xo); + xo << "; edvars: " << _editInfoList.size(); + xo << endl; + printExternalVariablesTo(xo); + return xo; +} + +ostream &operator<<(ostream &xo, const ClSimplexSolver &clss) +{ + return clss.PrintOn(xo); +} + +#endif + +bool +ClSimplexSolver::FIsConstraintSatisfied(const ClConstraint *const pcn) const +{ + ClConstraintToVarMap::const_iterator it_marker = _markerVars.find(pcn); + if (it_marker == _markerVars.end()) + { // could not find the constraint + throw ExCLConstraintNotFound(); + } + +#ifndef CL_NO_IO + bool fCnsays = pcn->FIsSatisfied(); +#endif + + ClConstraintToVarSetMap::const_iterator it_eVars = _errorVars.find(pcn); + + if (it_eVars != _errorVars.end()) + { + const ClVarSet &eVars = (*it_eVars).second; + ClVarSet::const_iterator it = eVars.begin(); + for ( ; it != eVars.end(); ++it ) + { + const ClLinearExpression *pexpr = RowExpression(*it); + if (pexpr != NULL && !ClApprox(pexpr->Constant(),0.0)) + { +#ifndef CL_NO_IO + if (fCnsays) + cerr << __FUNCTION__ << ": constraint says satisfiable, but solver does not" << endl; +#endif + return false; + } + } + } + +#ifndef CL_NO_IO + if (!fCnsays) + cerr << __FUNCTION__ << ": solver says satisfiable, but constraint does not" << endl; +#endif + return true; +} + + + +#ifndef CL_NO_ID + +ostream &PrintTo(ostream &xo, const ClSimplexSolver::ClEditInfoList &listPEditInfo) +{ + ClSimplexSolver::ClEditInfoList::const_iterator it = listPEditInfo.begin(); + for ( ; it != listPEditInfo.end(); ++it) { + const ClSimplexSolver::ClEditInfo *pcei = (*it); + xo << *pcei << endl; + } + return xo; +} + + +ostream &operator<<(ostream &xo, const ClSimplexSolver::ClEditInfoList &listPEditInfo) +{ return PrintTo(xo,listPEditInfo); } + +#endif + +// A. Beurive' Tue Jul 6 17:03:32 CEST 1999 +void +ClSimplexSolver::ChangeStrengthAndWeight(ClConstraint *pcn, const ClStrength &strength, double weight) +{ + ClConstraintToVarSetMap::iterator it_eVars = _errorVars.find(pcn); + // Only for constraints that already have error variables (i.e. non-required constraints) + assert(it_eVars != _errorVars.end()); + + ClLinearExpression *pzRow = RowExpression(_objective); + + Number old_coeff = pcn->weight() * pcn->strength().symbolicWeight().AsDouble(); + pcn->setStrength(strength); + pcn->setWeight(weight); + Number new_coeff = pcn->weight() * pcn->strength().symbolicWeight().AsDouble(); + + if (new_coeff != old_coeff) + { +#ifdef CL_TRACE + cerr << "Changing strength and/or weight for constraint: " << endl << *pcn << endl; + cerr << "Updating objective row from:" << endl << *pzRow << endl; +#endif + ClVarSet &eVars = (*it_eVars).second; + ClVarSet::iterator it = eVars.begin(); + for ( ; it != eVars.end(); ++it ) + { + const ClLinearExpression *pexpr = RowExpression(*it); + if (pexpr == NULL ) + { + pzRow->AddVariable(*it,-old_coeff,_objective,*this); + pzRow->AddVariable(*it,new_coeff,_objective,*this); + } + else + { + pzRow->AddExpression(*pexpr,-old_coeff,_objective,*this); + pzRow->AddExpression(*pexpr,new_coeff,_objective,*this); + } + } +#ifdef CL_TRACE + cerr << "to: " << endl << *pzRow << endl; +#endif + + if (_fAutosolve) + { + Optimize(_objective); + SetExternalVariables(); + } + } +} + +// A. Beurive' Tue Jul 6 17:03:42 CEST 1999 +void +ClSimplexSolver::ChangeStrength(ClConstraint *pcn, const ClStrength &strength) +{ + ChangeStrengthAndWeight(pcn,strength,pcn->weight()); +} + +// A. Beurive' Tue Jul 6 17:03:42 CEST 1999 +void +ClSimplexSolver::ChangeWeight(ClConstraint *pcn, double weight) +{ + ChangeStrengthAndWeight(pcn,pcn->strength(),weight); +} diff --git a/libs/cassowary/ClSlackVariable.cc b/libs/cassowary/ClSlackVariable.cc new file mode 100644 index 0000000000..eaf0432eb0 --- /dev/null +++ b/libs/cassowary/ClSlackVariable.cc @@ -0,0 +1,12 @@ +// $Id$ + +#include <cassowary/ClSlackVariable.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +#ifdef CL_FIND_LEAK +long ClSlackVariable::cSlackVariables = 0; +#endif diff --git a/libs/cassowary/ClSolver.cc b/libs/cassowary/ClSolver.cc new file mode 100644 index 0000000000..18b0b7f9cc --- /dev/null +++ b/libs/cassowary/ClSolver.cc @@ -0,0 +1,59 @@ +// $Id$ + +using namespace std; + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +#include <cassowary/Cassowary.h> +#include <cassowary/ClSolver.h> +#include <cassowary/ClConstraint.h> +#include <cassowary/ClErrors.h> +#include <cassowary/ClTypedefs.h> + + +ClSolver & +ClSolver::AddConstraint(ClConstraint *const ) +{ + return *this; +} + + +ostream & +PrintTo(ostream &xo, const ClConstraintSet &setCn) +{ + ClConstraintSet::const_iterator it = setCn.begin(); + for (; it != setCn.end(); ++it) { + const ClConstraint *pcn = *it; + xo << *pcn << endl; + } + return xo; +} + +ostream & +PrintTo(ostream &xo, const list<FDNumber> &listFDN) +{ + list<FDNumber>::const_iterator it = listFDN.begin(); + for (; it != listFDN.end(); ) { + FDNumber n = *it; + xo << n; + ++it; + if (it != listFDN.end()) + xo << ","; + } + return xo; +} + + +ostream &operator<<(ostream &xo, const ClConstraintSet &setCn) +{ return PrintTo(xo,setCn); } + + +ostream &operator<<(ostream &xo, const ClSolver &solver) +{ return solver.PrintOn(xo); } + +ostream &operator<<(ostream &xo, const list<FDNumber> &listFDN) +{ return PrintTo(xo,listFDN); } + diff --git a/libs/cassowary/ClStrength.cc b/libs/cassowary/ClStrength.cc new file mode 100644 index 0000000000..0629d4afff --- /dev/null +++ b/libs/cassowary/ClStrength.cc @@ -0,0 +1,52 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClStrength.cc + +#include <cassowary/ClStrength.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +// Use the singleton pattern for the strength objects +const ClStrength &ClsRequired() +{ + // required is distinct by equality to this static object, + // but I still use an especially high symbolic weight, just in case + // FIXGJB: hack? + static ClStrength required_strength("<Required>", 1000, 1000, 1000); + return required_strength; +} + +const ClStrength &ClsStrong() +{ + static ClStrength strong_strength("strong", 1.0, 0.0, 0.0); + return strong_strength; +} + +const ClStrength &ClsMedium() +{ + static ClStrength medium_strength("medium", 0.0, 1.0, 0.0); + return medium_strength; +} + + +const ClStrength &ClsWeak() +{ + static ClStrength weak_strength("weak", 0.0, 0.0, 1.0); + return weak_strength; +} + +// special case for when nLevels = 3, should assert nLevels() == 3 +ClStrength::ClStrength(const string &Name, double w1, double w2, double w3) : + _name(Name), _symbolicWeight(w1, w2, w3) +{ +} diff --git a/libs/cassowary/ClSymbolicWeight.cc b/libs/cassowary/ClSymbolicWeight.cc new file mode 100644 index 0000000000..9dddaa5949 --- /dev/null +++ b/libs/cassowary/ClSymbolicWeight.cc @@ -0,0 +1,149 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClSymbolicWeight.cc + +#include <cassowary/Cassowary.h> +#include <cassowary/ClSymbolicWeight.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +// Help g++ out, tell it to instantiate this +//template vector<double> &vector<double>::operator =(const vector<double> &); + +ClSymbolicWeight::ClSymbolicWeight(unsigned int CLevels, double value) : + _values(CLevels, value) +{ + assert(_values.size() == CLevels); +} + +ClSymbolicWeight::ClSymbolicWeight(double w1, double w2, double w3) +{ + _values.push_back(w1); + _values.push_back(w2); + _values.push_back(w3); + assert(_values.size() == 3); +} + +ClSymbolicWeight::ClSymbolicWeight(const vector<double> &weights) : + _values(weights) +{ } + +ClSymbolicWeight & +ClSymbolicWeight::Zero() +{ + static ClSymbolicWeight Zero(0.0, 0.0, 0.0); + return Zero; +} + + +ClSymbolicWeight & +ClSymbolicWeight::negated() +{ + vector<double>::iterator it = _values.begin(); + for (; it != _values.end(); ++it) + { + *it = -*it; + } + return *this; +} + +ClSymbolicWeight & +ClSymbolicWeight::MultiplyMe(Number n) +{ + vector<double>::iterator it = _values.begin(); + for (; it != _values.end(); ++it) + { + *it *= n; + } + return *this; +} + + +ClSymbolicWeight +ClSymbolicWeight::DivideBy(Number n) const +{ + assert(n!=0); + ClSymbolicWeight clsw(0); + vector<double>::const_iterator i = _values.begin(); + for (; i != _values.end(); ++i) + { + clsw.push_back(*i / n); + } + return clsw; +} + +ClSymbolicWeight & +ClSymbolicWeight::addtoMe(const ClSymbolicWeight &cl) +{ + assert(cl.CLevels() == CLevels()); + + vector<double>::iterator i1 = _values.begin(); + vector<double>::const_iterator i2 = cl._values.begin(); + for (; i1 != _values.end(); ++i1, ++i2) + { + *i1 += *i2; + } + return *this; +} + +ClSymbolicWeight +ClSymbolicWeight::Subtract(const ClSymbolicWeight &cl) const +{ + assert(cl.CLevels() == CLevels()); + + ClSymbolicWeight clsw(0); + vector<double>::const_iterator i1 = _values.begin(); + vector<double>::const_iterator i2 = cl._values.begin(); + for (; i1 != _values.end(); ++i1, ++i2) + { + clsw.push_back(*i1 - *i2); + } + return clsw; +} + + +bool +ClSymbolicWeight::lessThan(const ClSymbolicWeight &cl) const +{ + return _values < cl._values; +} + +bool +ClSymbolicWeight::lessThanOrEqual(const ClSymbolicWeight &cl) const +{ + return _values <= cl._values; +} + +bool +ClSymbolicWeight::equal(const ClSymbolicWeight &cl) const +{ + return _values == cl._values; +} + +bool +ClSymbolicWeight::greaterThan(const ClSymbolicWeight &cl) const +{ + return _values > cl._values; +} + +bool +ClSymbolicWeight::greaterThanOrEqual(const ClSymbolicWeight &cl) const +{ + return _values >= cl._values; +} + +bool +ClSymbolicWeight::isNegative() const +{ + return _values < Zero()._values; +} diff --git a/libs/cassowary/ClTableau.cc b/libs/cassowary/ClTableau.cc new file mode 100644 index 0000000000..85ac841725 --- /dev/null +++ b/libs/cassowary/ClTableau.cc @@ -0,0 +1,297 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClTableau.cc + +using namespace std; + +#include <cassowary/ClTableau.h> +#include <cassowary/debug.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + + +// delete the linear expressions +// let ClSimplexSolver worry about deleting the variables +ClTableau::~ClTableau() +{ + ClTableauRowsMap::iterator it = _rows.begin(); + for (; it != _rows.end(); ++it) + { + // free the ClLinearExpression that we new-ed +#ifdef CL_TRACE + cerr << "Deleting row delete@ " << ((*it).second) << endl; +#endif + delete (*it).second; + } +} + +#ifndef CL_NO_IO +// Some extra debugging info +ostream & +ClTableau::PrintInternalInfo(ostream &xo) const +{ + xo << "ncns:" << _rows.size() -1 + << "; cols:" << _columns.size() + << "; infrows:" << _infeasibleRows.size() + << "; ebvars:" << _externalRows.size() + << "; epvars:" << _externalParametricVars.size(); + return xo; +} + + +ostream & +ClTableau::printExternalVariablesTo(ostream &xo) const +{ + xo << "Parametric: "; + ClVarSet::iterator itParVars = _externalParametricVars.begin(); + for ( ; itParVars != _externalParametricVars.end(); ++itParVars ) { + ClVariable v = *itParVars; + xo << v << " "; + } + xo << "\nBasic: "; + ClVarSet::iterator itRowVars = _externalRows.begin(); + for ( ; itRowVars != _externalRows.end() ; ++itRowVars ) { + ClVariable v = *itRowVars; + xo << v << " "; + } + return xo << endl; +} + +#endif + + +// Add v, update column cross indices +// v becomes a basic variable +// expr is now owned by ClTableau class, +// and ClTableauis responsible for deleting it +// (also, expr better be allocated on the heap!) +void +ClTableau::addRow(ClVariable var, const ClLinearExpression &expr) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << var << ", " << expr << ")" << endl; +#endif + _rows[var] = const_cast<ClLinearExpression *>(&expr); + ClVarToNumberMap::const_iterator it = expr.Terms().begin(); + // for each variable in expr, Add var to the set of rows which have that variable + // in their Expression + for (; it != expr.Terms().end(); ++it) + { + ClVariable v = (*it).first; + _columns[v].insert(var); + if (v.IsExternal() && !FIsBasicVar(v)) + { + _externalParametricVars.insert(v); + } + } + if (var.IsExternal()) + { + _externalRows.insert(var); + } +#ifdef CL_TRACE + cerr << *this << endl; +#endif +} + +// Remove var from the tableau -- remove the column cross indices for var +// and remove var from every Expression in rows in which v occurs +// Remove the parametric variable var, updating the appropriate column and row entries. +// (Renamed from Smalltalk implementation's `removeParametricVar') +ClVariable +ClTableau::RemoveColumn(ClVariable var) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << var << ")" << endl; +#endif + ClTableauColumnsMap::iterator it_var = _columns.find(var); + if (it_var == _columns.end()) + return var; // nothing to do + + ClVarSet &varset = (*it_var).second; + // remove the rows with the variables in varset + ClVarSet::iterator it = varset.begin(); + for (; it != varset.end(); ++it) + { + ClVariable v = (*it); + ClVarToNumberMap &Terms = _rows[v]->Terms(); + Terms.erase(Terms.find(var)); + } + if (var.IsExternal()) + { + _externalRows.erase(var); + _externalParametricVars.erase(var); + } + _columns.erase(it_var); + return var; +} + +// Remove the basic variable v from the tableau row v=expr +// Then update column cross indices +ClLinearExpression * +ClTableau::RemoveRow(ClVariable var) +{ +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + cerr << "(" << var << ")" << endl; +#endif + ClTableauRowsMap::iterator it = _rows.find(var); + assert(it != _rows.end()); + ClLinearExpression *pexpr = (*it).second; + ClVarToNumberMap &Terms = pexpr->Terms(); + ClVarToNumberMap::iterator it_term = Terms.begin(); + for (; it_term != Terms.end(); ++it_term) + { + ClVariable v = (*it_term).first; + _columns[v].erase(var); + if (_columns[v].size() == 0) + { + _columns.erase(v); + _externalParametricVars.erase(v); + } + } + + _infeasibleRows.erase(var); + + if (var.IsExternal()) + { + _externalRows.erase(var); + _externalParametricVars.erase(var); + } + + _rows.erase(it); +#ifdef CL_TRACE + cerr << "- returning " << *pexpr << endl; +#endif + return pexpr; +} + +// Replace all occurrences of oldVar with expr, and update column cross indices +// oldVar should now be a basic variable +// Uses the Columns data structure and calls SubstituteOut on each +// row that has oldVar in it +// oldVar is leaving the basis, and becoming parametric +void +ClTableau::SubstituteOut(ClVariable oldVar, const ClLinearExpression &expr) +{ +#ifdef CL_TRACE + cerr << "* ClTableau::"; + Tracer TRACER(__FUNCTION__); + cerr << "(" << oldVar << ", " << expr << ")" << endl; + cerr << (*this) << endl; +#endif + + ClTableauColumnsMap::iterator it_oldVar = _columns.find(oldVar); + if (it_oldVar == _columns.end()) + return; + + ClVarSet &varset = (*it_oldVar).second; + ClVarSet::iterator it = varset.begin(); + for (; it != varset.end(); ++it) + { + ClVariable v = (*it); + ClLinearExpression *prow = _rows[v]; + prow->SubstituteOut(oldVar,expr,v,*this); + if (v.IsRestricted() && prow->Constant() < 0.0) + { + _infeasibleRows.insert(v); + } + } + _columns.erase(it_oldVar); + if (oldVar.IsExternal()) + { + if (_columns[oldVar].size() > 0) + { + _externalRows.insert(oldVar); + } + _externalParametricVars.erase(oldVar); + } +} + + +#ifndef CL_NO_IO + +ostream & +PrintTo(ostream &xo, const ClVarSet & varset) +{ + ClVarSet::const_iterator it = varset.begin(); + xo << "{ "; + if (it != varset.end()) + { + xo << *it; + ++it; + } + for (; it != varset.end(); ++it) + { + xo << ", " << *it; + } + xo << " }"; + return xo; +} + +ostream &operator<<(ostream &xo, const ClVarSet & varset) +{ return PrintTo(xo,varset); } + +ostream & +PrintTo(ostream &xo, const ClTableauColumnsMap & varmap) +{ + ClTableauColumnsMap::const_iterator it = varmap.begin(); + for (; it != varmap.end(); ++it) + { + xo << (*it).first << " -> " << (*it).second << endl; + } + return xo; +} + +ostream &operator<<(ostream &xo, const ClTableauColumnsMap & varmap) +{ return PrintTo(xo,varmap); } + +ostream & +PrintTo(ostream &xo, const ClTableauRowsMap & rows) +{ + ClTableauRowsMap::const_iterator it = rows.begin(); + for (; it != rows.end(); ++it) + { + ClVariable v = it->first; + const ClLinearExpression *pe = it->second; + xo << v << " <-=-> "; + if (pe) xo << *pe; else xo << "NilExpr"; + xo << endl; + } + return xo; +} + +ostream &operator<<(ostream &xo, const ClTableauRowsMap & rows) +{ return PrintTo(xo,rows); } + +ostream & +ClTableau::PrintOn(ostream &xo) const +{ + xo << "Tableau:\n" + << _rows << endl; + xo << "Columns:\n" + << _columns << endl; + xo << "Infeasible rows: " + << _infeasibleRows << endl; + xo << "External basic variables: " + << _externalRows << endl; + xo << "External parametric variables: " + << _externalParametricVars << endl; + return xo; +} + +ostream &operator<<(ostream &xo, const ClTableau &clt) +{ return clt.PrintOn(xo); } + +#endif diff --git a/libs/cassowary/ClTests.cc b/libs/cassowary/ClTests.cc new file mode 100644 index 0000000000..606d6f3e44 --- /dev/null +++ b/libs/cassowary/ClTests.cc @@ -0,0 +1,884 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClTests.cc + +#include <cassowary/Cl.h> +#include <stdlib.h> +#include <cassowary/timer.h> +#include <iostream> +#include <iomanip> + +inline +double UniformRandom() +{ return double(rand())/RAND_MAX; } + + +bool +simple1() +{ + try + { + bool fOkResult = true; + ClVariable x(167); + ClVariable y(2); + ClSimplexSolver solver; + + ClLinearEquation eq(x,y+0.0); + solver.AddStay(x); + solver.AddStay(y); + solver.AddConstraint(eq); + cout << "x = " << x.Value() << endl + << "y = " << y.Value() << endl; + fOkResult = (x.Value() == y.Value()); + return fOkResult; + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(false); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } +} + + +/* Add an edit variable to an empty solver */ +bool +simple2() +{ + try + { + ClVariable x(167); + ClSimplexSolver solver; + + solver.AddEditVar(x); + solver.BeginEdit(); + solver.SuggestValue(x,100); + solver.EndEdit(); + + cout << "x = " << x.Value() << endl; + } + catch (ExCLEditMisuse &error) + { + cout << "Success: got the exception" << endl; + return true; + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(false); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } + cerr << "Should have gotten an exception!" << endl; + return false; +} + + +bool +justStay1() +{ + try + { + bool fOkResult = true; + ClVariable x(5); + ClVariable y(10); + ClSimplexSolver solver; + +#if 0 + solver.AddPointStay(x,y,1); +#else + solver.AddStay(x); + solver.AddStay(y); +#endif + fOkResult = fOkResult && ClApprox(x,5); + fOkResult = fOkResult && ClApprox(y,10); + cout << "x == " << x.Value() << endl; + cout << "y == " << y.Value() << endl; + + return(fOkResult); + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(false); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } +} + + + +bool +addDelete1() +{ + try + { + bool fOkResult = true; + ClVariable x("x"); + ClSimplexSolver solver; + + solver.AddConstraint(new ClLinearEquation( x, 100, ClsWeak() )); + + ClLinearInequality c10(x,cnLEQ,10.0); + ClLinearInequality c20(x,cnLEQ,20.0); + solver + .AddConstraint(c10) + .AddConstraint(c20); + + fOkResult = fOkResult && ClApprox(x,10.0); + cout << "x == " << x.Value() << endl; + + cout << endl << solver << endl; + + solver.RemoveConstraint(c10); + + cout << endl << solver << endl; + + fOkResult = fOkResult && ClApprox(x,20.0); + cout << "x == " << x.Value() << endl; + + solver.RemoveConstraint(c20); + fOkResult = fOkResult && ClApprox(x,100.0); + cout << "x == " << x.Value() << endl; + + ClLinearInequality c10again(x,cnLEQ,10.0); + + solver + .AddConstraint(c10) + .AddConstraint(c10again); + + fOkResult = fOkResult && ClApprox(x,10.0); + cout << "x == " << x.Value() << endl; + + solver.RemoveConstraint(c10); + fOkResult = fOkResult && ClApprox(x,10.0); + cout << "x == " << x.Value() << endl; + + solver.RemoveConstraint(c10again); + fOkResult = fOkResult && ClApprox(x,100.0); + cout << "x == " << x.Value() << endl; + + return(fOkResult); + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(false); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } +} + +bool +addDelete2() +{ + try + { + bool fOkResult = true; + ClVariable x("x"); + ClVariable y("y"); + ClSimplexSolver solver; + + solver + .AddConstraint(new ClLinearEquation(x, 100.0, ClsWeak())) + .AddConstraint(new ClLinearEquation(y, 120.0, ClsStrong())); + + ClLinearInequality c10(x,cnLEQ,10.0); + ClLinearInequality c20(x,cnLEQ,20.0); + + solver + .AddConstraint(c10) + .AddConstraint(c20); + fOkResult = fOkResult && ClApprox(x,10.0) && ClApprox(y,120.0); + cout << "x == " << x.Value() << ", y == " << y.Value() << endl; + + solver.RemoveConstraint(c10); + fOkResult = fOkResult && ClApprox(x,20.0) && ClApprox(y,120.0); + cout << "x == " << x.Value() << ", y == " << y.Value() << endl; + + ClLinearEquation cxy( 2*x, y); + solver.AddConstraint(cxy); + fOkResult = fOkResult && ClApprox(x,20.0) && ClApprox(y,40.0); + cout << "x == " << x.Value() << ", y == " << y.Value() << endl; + + solver.RemoveConstraint(c20); + fOkResult = fOkResult && ClApprox(x,60.0) && ClApprox(y,120.0); + cout << "x == " << x.Value() << ", y == " << y.Value() << endl; + + solver.RemoveConstraint(cxy); + fOkResult = fOkResult && ClApprox(x,100.0) && ClApprox(y,120.0); + cout << "x == " << x.Value() << ", y == " << y.Value() << endl; + + + return(fOkResult); + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(false); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } +} + +bool +casso1() +{ + try + { + bool fOkResult = true; + ClVariable x("x"); + ClVariable y("y"); + ClSimplexSolver solver; + + solver + .AddConstraint(new ClLinearInequality(x,cnLEQ,y)) + .AddConstraint(new ClLinearEquation(y, x+3.0)) + .AddConstraint(new ClLinearEquation(x,10.0,ClsWeak())) + .AddConstraint(new ClLinearEquation(y,10.0,ClsWeak())) + ; + + fOkResult = fOkResult && + ( ClApprox(x,10.0) && ClApprox(y,13.0) || + ClApprox(x,7.0) && ClApprox(y,10.0) ); + + cout << "x == " << x.Value() << ", y == " << y.Value() << endl; + + return(fOkResult); + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(false); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } +} + +bool +inconsistent1() +{ + ClSimplexSolver solver; + ClVariable x("x"); + ClLinearEquation eq1(x,10.0); + ClLinearEquation eq2(x,5.0); + try + { + + solver.AddConstraint( eq1 ); + solver.AddConstraint( eq2 ); + + // no exception, we failed! + return(false); + } + catch (ExCLRequiredFailure) + { + // we want this exception to get thrown + cout << "Success -- got the exception" << endl; + // solver.RemoveConstraint(eq2); this would throw a constraint not found exception + // cout << solver << endl; + return(true); + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(false); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } +} + +bool +inconsistent2() +{ + try + { + ClVariable x("x"); + ClSimplexSolver solver; + + solver + .AddConstraint(new ClLinearInequality(x,cnGEQ,10.0)) + .AddConstraint(new ClLinearInequality(x,cnLEQ, 5.0)); + + // no exception, we failed! + return(false); + } + catch (ExCLRequiredFailure &) + { + // we want this exception to get thrown + cout << "Success -- got the exception" << endl; + // cout << solver << endl; + return(true); + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(false); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } +} + +bool +inconsistent3() +{ + try + { + ClVariable w("w"); + ClVariable x("x"); + ClVariable y("y"); + ClVariable z("z"); + ClSimplexSolver solver; + + solver + .AddConstraint(new ClLinearInequality(w,cnGEQ,10.0)) + .AddConstraint(new ClLinearInequality(x,cnGEQ,w)) + .AddConstraint(new ClLinearInequality(y,cnGEQ,x)) + .AddConstraint(new ClLinearInequality(z,cnGEQ,y)) + .AddConstraint(new ClLinearInequality(z,cnLEQ,4.0)); + + // no exception, we failed! + return(false); + } + catch (ExCLRequiredFailure &) + { + // we want this exception to get thrown + cout << "Success -- got the exception" << endl; + // cout << solver << endl; + return(true); + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(false); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } +} + + +bool +multiedit() +{ + try + { + bool fOkResult = true; + + ClVariable x("x",0); + ClVariable y("y",0); + ClVariable w("w",0); + ClVariable h("h",0); + ClSimplexSolver solver; + + solver + .AddStay(x) + .AddStay(y) + .AddStay(w) + .AddStay(h); + + solver + .AddEditVar(x) + .AddEditVar(y) + .BeginEdit(); + + solver + .SuggestValue(x,10) + .SuggestValue(y,20) + .Resolve(); + + cout << "x = " << x.Value() << "; y = " << y.Value() << endl + << "w = " << w.Value() << "; h = " << h.Value() << endl; + + fOkResult = fOkResult && + ClApprox(x,10) && ClApprox(y,20) && ClApprox(w,0) && ClApprox(h,0); + + solver + .AddEditVar(w) + .AddEditVar(h) + .BeginEdit(); + + solver + .SuggestValue(w,30) + .SuggestValue(h,40) + .EndEdit(); + + cout << "x = " << x.Value() << "; y = " << y.Value() << endl + << "w = " << w.Value() << "; h = " << h.Value() << endl; + + fOkResult = fOkResult && + ClApprox(x,10) && ClApprox(y,20) && ClApprox(w,30) && ClApprox(h,40); + + solver + .SuggestValue(x,50) + .SuggestValue(y,60) + .EndEdit(); + + cout << "x = " << x.Value() << "; y = " << y.Value() << endl + << "w = " << w.Value() << "; h = " << h.Value() << endl; + + fOkResult = fOkResult && + ClApprox(x,50) && ClApprox(y,60) && ClApprox(w,30) && ClApprox(h,40); + + return fOkResult; + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(false); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } + cerr << "Should have gotten an exception!" << endl; + return false; +} + + +bool +multiedit2() +{ + try + { + bool fOkResult = true; + + ClVariable x("x",0); + ClVariable y("y",0); + ClVariable w("w",0); + ClVariable h("h",0); + ClSimplexSolver solver; + + solver + .AddStay(x) + .AddStay(y) + .AddStay(w) + .AddStay(h); + + solver + .AddEditVar(x) + .AddEditVar(y) + .BeginEdit(); + + solver + .SuggestValue(x,10) + .SuggestValue(y,20) + .Resolve(); + + cout << "x = " << x.Value() << "; y = " << y.Value() << endl + << "w = " << w.Value() << "; h = " << h.Value() << endl; + + fOkResult = fOkResult && + ClApprox(x,10) && ClApprox(y,20) && ClApprox(w,0) && ClApprox(h,0); + + solver + .AddEditVar(x) + .AddEditVar(y) + .AddEditVar(w) + .AddEditVar(h) + .BeginEdit(); + + solver + .SuggestValue(w,30) + .SuggestValue(h,40) + .EndEdit(); + + cout << "x = " << x.Value() << "; y = " << y.Value() << endl + << "w = " << w.Value() << "; h = " << h.Value() << endl; + + fOkResult = fOkResult && + ClApprox(x,10) && ClApprox(y,20) && ClApprox(w,30) && ClApprox(h,40); + + solver + .SuggestValue(x,50) + .SuggestValue(y,60) + .EndEdit(); + + cout << "x = " << x.Value() << "; y = " << y.Value() << endl + << "w = " << w.Value() << "; h = " << h.Value() << endl; + + fOkResult = fOkResult && + ClApprox(x,50) && ClApprox(y,60) && ClApprox(w,30) && ClApprox(h,40); + + return fOkResult; + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(false); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } + cerr << "Should have gotten an exception!" << endl; + return false; +} + + +// From a bug report from Steve Wolfman on his +// SAT project using "blackbox" +bool +blackboxsat() +{ + try + { + ClSimplexSolver solver; + + ClVariable r1("r1"); + ClVariable r2("r2"); + ClVariable r3("r3"); + ClVariable r4("r4"); + ClVariable r5("r5"); + ClVariable r6("r6"); + ClVariable r7("r7"); + ClVariable r8("r8"); + + ClConstraint *rgpcn[30]; + for (int i=0; i<int(sizeof(rgpcn)/sizeof(rgpcn[0])); ++i) + rgpcn[i] = NULL; + + rgpcn[1] = new ClLinearEquation(r1,60); + rgpcn[2] = new ClLinearEquation(r2,30); + rgpcn[12] = new ClLinearEquation(r3,2.5); + rgpcn[13] = new ClLinearEquation(r6,0); + rgpcn[14] = new ClLinearInequality(r5, cnGEQ, 0); + rgpcn[15] = new ClLinearInequality(r8, cnLEQ, 2.5); + rgpcn[16] = new ClLinearInequality(r7, cnGEQ, r6); + rgpcn[17] = new ClLinearInequality(r8, cnGEQ, r7); + rgpcn[18] = new ClLinearEquation(r4, r3 - r2/60.0); + rgpcn[19] = new ClLinearEquation(r5, r4 - r1/60.0); + rgpcn[20] = new ClLinearInequality(r4, cnGEQ, 0); + rgpcn[21] = new ClLinearInequality(r5, cnGEQ, 0); + rgpcn[22] = new ClLinearEquation(r7, r6 + r2/20.0); + rgpcn[23] = new ClLinearEquation(r8, r7 + r1/20.0); + rgpcn[24] = new ClLinearEquation(r4, r3 - r2/30.0); + rgpcn[25] = new ClLinearEquation(r5, r4 - r1/30.0); + rgpcn[26] = new ClLinearInequality(r4, cnGEQ, 0); + rgpcn[27] = new ClLinearInequality(r5, cnGEQ, 0); + rgpcn[28] = new ClLinearEquation(r7, r6 + r2/60.0); + rgpcn[29] = new ClLinearEquation(r8, r7 + r1/60.0); + + while (true) + { + char szCmd[1000]; + int i; + cin >> szCmd; + if (!cin) + break; + if (szCmd[0] == '#') + { + cin.getline(szCmd,900); + continue; + } + if (strcasecmp(szCmd,"Add") == 0) + { + cin >> i; + cout << "eq" << i << ": " << solver.AddConstraintNoException(rgpcn[i]) + << "\t" << *(rgpcn[i]) << endl; + cout << r1 << " = " << r1.Value() << endl; + } + else if (strcasecmp(szCmd,"del") == 0) + { + cin >> i; + cout << "REMeq" << i << ": " << solver.RemoveConstraintNoException(rgpcn[i]) + << "\t" << *(rgpcn[i]) << endl; + cout << r1 << " = " << r1.Value() << endl; + } + else if (strcasecmp(szCmd,"dump") == 0) + { + cout << solver << endl; + } + else if (strcasecmp(szCmd,"val") == 0) + { + cout << r1 << " = " << r1.Value() << endl; + } + else if (strcasecmp(szCmd,"solve") == 0) + { + cout << solver.Solve() << endl; + } + else if (strcasecmp(szCmd,"autosolve") == 0) + { + solver.SetAutosolve(true); + } + else if (strcasecmp(szCmd,"noautosolve") == 0) + { + solver.SetAutosolve(true); + } + } + + cout << r1 << " = " << r1.Value() << endl + << r2 << " = " << r2.Value() << endl + << r3 << " = " << r3.Value() << endl + << r4 << " = " << r4.Value() << endl + << r5 << " = " << r5.Value() << endl + << r6 << " = " << r6.Value() << endl + << r7 << " = " << r7.Value() << endl + << r8 << " = " << r8.Value() << endl; + + return false; + } + catch (ExCLError &error) + { + cerr << "Exception! " << error.description() << endl; + return(true); + } + catch (...) + { + cerr << "Unknown exception" << endl; + return(false); + } +} + +typedef ClVariable *PClVariable; + +bool +addDel(const int nCns = 900, const int nVars = 900, const int nResolves = 10000) +//addDel(int nCns = 300, int nVars = 300, int nResolves = 1000) +//addDel(int nCns = 30, int nVars = 30, int nResolves = 100) +{ + Timer timer; + // FIXGJB: from where did .12 come? + static const double ineqProb = 0.12; + static const int maxVars = 3; + + cout << "starting timing test. nCns = " << nCns + << ", nVars = " << nVars << ", nResolves = " << nResolves << endl; + + timer.Start(); + ClSimplexSolver solver; + solver.SetAutosolve(false); + + ClVariable **rgpclv = new PClVariable[nVars]; + for (int i = 0; i < nVars; i++) + { + rgpclv[i] = new ClVariable(i,"x"); + solver.AddStay(*rgpclv[i]); + } + + ClConstraint **rgpcns = new PClConstraint[nCns]; + int nvs = 0; + int k; + int j; + double coeff; + for (j = 0; j < nCns; j++) + { + // number of variables in this constraint + nvs = int(UniformRandom()*maxVars) + 1; + ClLinearExpression expr = UniformRandom()*20.0 - 10.0; + for (k = 0; k < nvs; k++) + { + coeff = UniformRandom()*10 - 5; + expr.AddExpression(*(rgpclv[int(UniformRandom()*nVars)]) * coeff); + } + if (UniformRandom() < ineqProb) + { + rgpcns[j] = new ClLinearInequality(expr); + } + else + { + rgpcns[j] = new ClLinearEquation(expr); + } +#ifdef CL_SHOW_CNS_IN_BENCHMARK + cout << "Cn[" << j << "]: " << *rgpcns[j] << endl; +#endif + } + + cout << "done building data structures" << endl; + cout << "time = " << timer.ElapsedTime() << "\n" << endl; + timer.Start(); + int cExceptions = 0; +#ifdef CL_SHOW_CNS_IN_BENCHMARK + cout << "Exceptions on: "; +#endif + for (j = 0; j < nCns; j++) + { + // Add the constraint -- if it's incompatible, just ignore it + try + { + solver.AddConstraint(rgpcns[j]); + } + catch (ExCLRequiredFailure &) + { + cExceptions++; + rgpcns[j] = NULL; +#ifdef CL_SHOW_CNS_IN_BENCHMARK + cout << j << " "; +#endif + } + } +#ifdef CL_SHOW_CNS_IN_BENCHMARK + cout << "\n" << endl; +#endif + solver.Solve(); + cout << "done adding constraints [" << cExceptions << " exceptions]" << endl; + cout << "time = " << timer.ElapsedTime() << "\n" << endl; + cout << "time per cn = " << timer.ElapsedTime()/nCns << "\n" << endl; + cout << "time per actual cn = " << timer.ElapsedTime()/(nCns - cExceptions) << "\n" <<endl; + timer.Start(); + + int e1Index = int(UniformRandom()*nVars); + int e2Index = int(UniformRandom()*nVars); + + ClVariable e1 = *(rgpclv[e1Index]); + ClVariable e2 = *(rgpclv[e2Index]); + + solver + .AddEditVar(e1) + .AddEditVar(e2); + + cout << "done creating edit constraints -- about to start resolves" << endl; + cout << "time = " << timer.ElapsedTime() << "\n" << endl; + timer.Start(); + + solver.BeginEdit(); + // FIXGJB start = Timer.now(); + for (int m = 0; m < nResolves; ++m) + { + solver + .SuggestValue(e1,e1->Value()*1.001) + .SuggestValue(e2,e2->Value()*1.001) + .Resolve(); + } + solver.EndEdit(); + // cout << "run time: " << + + cout << "done resolves -- now removing constraints" << endl; + cout << "time = " << timer.ElapsedTime() << "\n" <<endl; + cout << "time per Resolve = " << timer.ElapsedTime()/nResolves << "\n" <<endl; + + timer.Start(); + + for (j = 0; j < nCns; j++) + { + if (rgpcns[j]) + { + solver.RemoveConstraint(rgpcns[j]); + } + } + + // FIXGJB end = Timer.now(); + // cout << "Total remove time: " + // << "remove time per cn" + cout << "done removing constraints and addDel timing test" << endl; + cout << "time = " << timer.ElapsedTime() << "\n" <<endl; + cout << "time per cn = " << timer.ElapsedTime()/nCns << "\n" <<endl; + cout << "time per actual cn = " << timer.ElapsedTime()/(nCns - cExceptions) << "\n" <<endl; + + for (int i = 0; i < nVars; i++) + { + delete rgpclv[i]; + } + + for (int j = 0; j < nCns; j++) + { + delete rgpcns[j]; + } + + return true; +} + + +int +main( int argc, char **argv ) +{ + try + { + bool fAllOkResult = true; + bool fResult; + + // seed the random number generator for reproducible results + srand(123456789); + + cout << "Cassowary version: " << szCassowaryVersion << endl; + +#define RUN_TEST(x) \ + cout << #x << ":" << endl; \ + fResult = x(); fAllOkResult &= fResult; \ + if (!fResult) cout << "Failed!" << endl; + + RUN_TEST(simple1); + RUN_TEST(simple2); + RUN_TEST(justStay1); + RUN_TEST(addDelete1); + RUN_TEST(addDelete2); + RUN_TEST(casso1); + RUN_TEST(inconsistent1); + RUN_TEST(inconsistent2); + RUN_TEST(inconsistent3); + RUN_TEST(multiedit); + RUN_TEST(multiedit2); + // RUN_TEST(blackboxsat); + + int cns = 90, vars = 90, resolves = 100; + + if (argc > 1) + cns = atoi(argv[1]); + + if (argc > 2) + vars = atoi(argv[2]); + + if (argc > 3) + resolves = atoi(argv[3]); + + if (cns > 0) + { + cout << "addDel" << ":" << endl; + fResult = addDel(cns,vars,resolves); fAllOkResult &= fResult; + if (!fResult) cout << "Failed!" << endl; + } + +#undef RUN_TEST + +#ifdef CL_FIND_LEAK + cout << "ClAbstractVariables: " << ClAbstractVariable::cAbstractVariables + << "\nClDummyVariables: " << ClDummyVariable::cDummyVariables + << "\nClSlackVariables: " << ClSlackVariable::cSlackVariables + << endl; +#endif + + + return (fAllOkResult? 0 : 255); + + } + catch (...) + { + cerr << "exception!" << endl; + } +} diff --git a/libs/cassowary/ClVariable.cc b/libs/cassowary/ClVariable.cc new file mode 100644 index 0000000000..2a136c1096 --- /dev/null +++ b/libs/cassowary/ClVariable.cc @@ -0,0 +1,21 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClVariable.cc + +#include <cassowary/ClVariable.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#define CONFIG_H_INCLUDED +#endif + +StringToVarMap *ClVariable::pmapStrPclv = NULL; +ClVariable clvNil(static_cast<ClAbstractVariable*>(0)); + diff --git a/libs/cassowary/IMPORTANT b/libs/cassowary/IMPORTANT new file mode 100644 index 0000000000..1edaabfa01 --- /dev/null +++ b/libs/cassowary/IMPORTANT @@ -0,0 +1,26 @@ +Cassowary/C++ needs to be compiled using a modern C++ compiler. +At one time or another, it has compiled using: + o egcs-1.0.1, egcs-1.0.3, egcs-1.1b, gcc-2.8.1, gcc-2.95.2 + o Visual C++ 5.0 + +Cassowary/Java was developed using Sun's JDK-1.1.3, ported to Linux +More recent versions should work fine, and it has been tested +with JDK-1.2pre2. + +The included Makefiles depend upon features of GNU Make. See: + +ftp://ftp.gnu.org/pub/gnu/ + +for a version that you can build. + + +To build the c++/qdemos/QuadDemo application, you'll need TrollTech's Qt +widget set for X11, available from: + +http://www.troll.no/dl/qtfree-dl.html + + +See also the Scwm (Scheme Constraints Window Manager) web page for a use +of Cassowary in a substantial application: + +http://scwm.mit.edu/scwm/ diff --git a/libs/cassowary/INSTALL b/libs/cassowary/INSTALL new file mode 100644 index 0000000000..b42a17ac46 --- /dev/null +++ b/libs/cassowary/INSTALL @@ -0,0 +1,182 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/libs/cassowary/LICENSE b/libs/cassowary/LICENSE new file mode 100644 index 0000000000..21ecedf70d --- /dev/null +++ b/libs/cassowary/LICENSE @@ -0,0 +1,18 @@ +Cassowary Constraint Solving Toolkit +Copyright (C) 1998-200 Greg J. Badros + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +See COPYING.LGPL diff --git a/libs/cassowary/Makefile.am b/libs/cassowary/Makefile.am new file mode 100644 index 0000000000..fb36aef47c --- /dev/null +++ b/libs/cassowary/Makefile.am @@ -0,0 +1,32 @@ +MAINTAINERCLEANFILES = autom4te.cache Makefile.in aclocal.m4 configure \ + config.h.in stamp-h.in config.guess mkinstalldirs \ + missing install-sh config.sub ltconfig \ + ltmain.sh acinclude.m4 config.log config.status \ + depcomp ClReader.cc ClReader.hh ClReader-lex.cc + +EXTRA_DIST = ClReader.l ClReader.y + +SUBDIRS = cassowary + +noinst_LIBRARIES = libcassowary.a + +libcassowary_a_SOURCES = \ + ClAbstractVariable.cc \ + ClConstraint.cc \ + ClLinearExpression.cc \ + ClSolver.cc \ + ClSimplexSolver.cc \ + ClStrength.cc \ + ClSymbolicWeight.cc \ + ClTableau.cc \ + ClVariable.cc \ + ClFloatVariable.cc \ + ClSlackVariable.cc \ + ClDummyVariable.cc \ + ClReader-lex.cc + +ClReader-lex.cc: ClReader.l cassowary/ClReader.h ClReader.cc + $(LEX) -Pcl -o$@ $< + +ClReader.cc: ClReader.y cassowary/ClReader.h + $(YACC) -d -pcl --output-file $@ $< diff --git a/libs/cassowary/NEWS b/libs/cassowary/NEWS new file mode 100644 index 0000000000..0f950dacef --- /dev/null +++ b/libs/cassowary/NEWS @@ -0,0 +1,229 @@ +Cassowary NEWS -- history of user-visible changes. -*- text -*- + +Cassowary Constraint Solving Toolkit was +Implemented by: + +Greg J. Badros <gjb@cs.washington.edu> and +Alan Borning <borning@cs.washington.edu> +University of Washington +Computer Science and Engineering +Seattle, WA 98195-2350 + +with Constraint Drawing Applet (CDA) by Michael Noth <noth@cs.washington.edu> + +12-March-2000: Version 0.60 released. +* Changed license to LGPL!!! +* Added SetAutoResetStayConstants(), FIsAutoResetStayConstants(), make ResetStayConstants() public + +29-Jan-2000: Version 0.55 released. +* Some bug fixes +* Added ClSimplexSolver::{ChangeStrength,ChangeStrengthAndWeight,ChangeWeight, + DisplayObjective,ExternalResetStayConstants} fns + From A. Beurivé. + +16-Dec-1999: Version 0.54a released. +* Include correct version of OTI Smalltalk .dat file + (the source in the *.app files was right, the .dat file was old) +* Fix java build bug + +15-Dec-1999: Version 0.54 released. +* Bug fixes +* auto-configuration improvements +* Support Java 2 (jdk-1.2) +* Improved ease of building Java demos +* Build guile wrapper as long as guile-config works, use new --disable-guile-build to force off +* Alpha-version of Java constraint parser contributed by Will Portnoy + +24-October-1999: Version 0.53 released. +* Bug fixes +* License exception for linking with Scwm. + +25-September-1999: Version 0.52 released. +* Bug fix for nested edits where a later edit includes an already-being-edited variable + +14-September-1999: Version 0.51 released. +* Minor bug fixes +* Much better packaging, RPMs, etc. more forced reliance on GTL + +26-August-1999: Version 0.51 pre-releases begin + +12-July-1999: Version 0.50 released. +* Made only C++ version build by default, --enable-java-build is needed to turn java on +* Added restricted finite domain solver +** needs --with-gtl configure option, and libGTL.{a,so*} to be installed +* Added ClSolver base class, and use its type for pointers in callbacks + +14-Apr-1999: Version 0.43 released. +* DEBUG_PARSE turned off by default +* Added cassowary.spec for RPM building + +31-Mar-1999: Version 0.42 released. +* Fixed autoconf bugs (.41 was a buggy release) +* Added --disable-cpp-build,--disable-java-build, and disable Python/Guile builds +automatically if directories cannot be found + +20-Mar-1999: Version 0.41 released. +* Fixed bug in autoconf support -- config.sub, config.guess to the +distribution so configure should actually work (they were symlinks +before, in error). + +18-Mar-1999: Version 0.4 released. + +18-Mar-1999: Changes since Cassowary v0.32 (for release v0.4) +* MUCH improved autoconf/automake support including numerous configure +options, added libtool support. +* Renamed many identifiers in the public API; this will break old code +using Cassowary. See the scripts/convert-ids script for help converting +your code (beware false positives; i.e., improper or unnecessary +changes). + + +10-Mar-1999: Changes since Cassowary v0.31 (for release v0.32) +* Added automake/autoconf support. Old Makefiles are now +Makefile.linux. This is not yet fully tested or correct, but I need to +make a release now for the bug fixes. Consider compiling with "make -f +Makefile.linux all" if you have problems running autoconf and/or +automake. + +* Changes to C++ +** Bug fix for problem Anthony Beurivé noticed regarding removing non-1 +weight stay constraints. +** Minor bug fix for parser. Also renamed the creader files to ClReader. + +* Changes to Java +** Bug fix for problem Emmanuel Pietriga reported regarding edit +constraints. +** Improved debugging support a bit by adding descriptions to +ExCLInternalError-s and assert()s + +* Changes to guile wrapper +** changed name of library to libcassowaryguile.a from libconstraints.a + + +1-Mar-1999: Changes since Cassowary v0.3 (for release v0.31) +* Changes to C++ +** Some bug fixes -- pass ClVariable-s around by value instead of const +& since they are now a handle class. +** Changed output format for ClEditConstraint, ClStayConstraint instances +** Use a function-object for controlling lookup/creation of variables in PcnParseConstraint +** Fix bugs in creader.y parser (did not accept parens or division +before). Introduced "==" as a a synonym for "=" +** Added szCassowaryVersion id string as a public char *. +** Added ChangeStrength, ChangeWeight to ClConstraint's public +interface, and have it valid only when the constraint is not in a solver +** Added ClConstraint::FIsInSolver() + +* Changes to Guile wrapper +** Fix bugs +** Wrap parsing functionality, including a lambda for lookup/creation of +variables +** Build a dynamically-loadable guile module, update cltests.scm to use it + + +23-Feb-1999: Version 0.3 released. + +19-Feb-1999, Changes since Cassowary v0.23 (for release v0.3) + +* Changes to Java and C++ +** Bug fix for Michael Kaufmann's report (see ChangeLog for details) +** resolve(Vector..) procedure is now depracated; preferred interface is +suggestValue(...) calls followed by resolve() (the one taking no +arguments). +** Added ClVariable::SetVarMap(..), ClVariable::VarMap() to permit +ClVariable ctr to save the mapping between given name and actual object +in a symbol table (used for parsing ascii expressions in C++ version) + +* Changes to just C++ implementation +** Use ClVariable as a handle class to a ClAbstractVariable-- old +ClVariable is now a ClFloatVariable. SetChangeClvCallback now takes a +function that takes a ClVariable handle, not a pointer. +** Passing ClConstraints's by const & is now deprecated -- pass by +pointer to the ClConstraint object +** Added creader.y, creader.l and function PcnParseConstraint(..) for +creating a constraint from an ASCII string. +** Added CL_NO_IO compile-time option to C++ version for preventing need +to link with the stream library (is not complete) +** Added CL_FIND_LEAK compile-time option for counting ctrs/dtr +invocations +** Added CL_USE_HASH_MAP compile-time option to permit using the GNU +hash_map class instead of the standard STL map (which is a sorted +associative container whose performance for lookups is logarithmic +rather than constant time). Still does not work for me --02/16/99 gjb. + +* Changes to just Java implementation (updated to match changes to C++ +version for .2) +** Added {get,set}AttachedObject for ClVariable, ClConstant +** Permit access to ClSimplexSolver.ConstraintMap() +** Permit nested beginEdit()s and handle them correctly + +* Miscellaneous changes +** Updated copyright to include 1999 +** Fixed wrappers/Makefile for building Python wrapper +** Reference Anthony Beurivé's STk wrapper +** Fix Scwm URL + + +30-Jan-1999, Changes since Cassowary v0.22 (for release v0.23) +* Bug fix (see ChangeLog for details) + + +23-Jan-1999, Changes since Cassowary v0.21 (for release v0.22) +* Minor code cleanup, additions of comments. + + +14-Sep-98, Changes since Cassowary v0.2 (for release v0.21) + +* Make compile cleanly using egcs-1.1b -- use typename, and drop + unused templated instantiation + +* Improved guile interface: add a void pointer to the solver objects, + and let the guile wrapper use it to keep a pointer to the scheme-level + object; also added clv-attach! and clv-attached-object for attaching + an object to a cl-variable (somewhat redundant with guile's + object properties) + +* Wrap ClStayConstraints so they can be managed explicitly + +* cl-add-stay, cl-add-editvar now take strength and factor arguments, + instead of a list of cl-vars + +* Added weight option to addEditVar + + +6-Aug-98, Changes since Cassowary v0.1 (for release v0.2): + +* Changes to the distribution for release v0.2 + +** added guile/scheme wrapper of C++ version + +** mention SCWM in README + +** mention non-maintenance of Smalltalk implementation unless we have users + +* Changes to the C++ and Java implementations + +** Fixed several bugs -- dummy variables were wrongly being pivoted into + the basis, and constraints that threw required failure exceptions + were mistakenly remaining in the tableau (now trying to remove an + exception that was not added because of a required-failure exception + will correctly throw a ConstraintNotFound exception); more -- see ChangeLog + +** Added a virtual change_value function to permit applications to watch + for changes made to external variables. + +* Changes to only the C++ version (Java version will catch up in 0.3) + +** Added new test cases to ClTests, fixed bugs in ClTestColumns + +** Added _pv (void *) field hanging off of ClConstraint and ClVariable + for associating arbitrary structs with those (needed by SCWM) + +** Permit nested beginEdit()s, and do the right thing upon calling + endEdit() -- i.e., not all the edit variables are removed, only the + nested ones + +** Permit access to ClSimplexSolver::ConstraintMap() (used by + guile-wrapper to efficiently get at a list of constraints in the + solver) + +** Added ExCLEditMisuse exception diff --git a/libs/cassowary/README b/libs/cassowary/README new file mode 100644 index 0000000000..16ed492b8e --- /dev/null +++ b/libs/cassowary/README @@ -0,0 +1,241 @@ +Cassowary Constraint Solving Toolkit for C++, Java, and Smalltalk +Version 0.60 + +Web Page: http://www.cs.washington.edu/research/constraints/cassowary +Contact: cassowary@cs.washington.edu + +Greg J. Badros <gjb@cs.washington.edu> and +Alan Borning <borning@cs.washington.edu> +University of Washington +Computer Science and Engineering +Seattle, WA 98195-2350 +12-March-2000 + +with Constraint Drawing Applet (CDA) by Michael Noth <noth@cs.washington.edu> + +See ANNOUNCE for a brief description and announcement of this distribution. +See NEWS for a history of user-visible changes. +See ChangeLog for a detailed listing of the changes to each source file. +See LICENSE for legalese regarding use of this distribution. + +The Smalltalk implementation is in the public domain -- see smalltalk/README. + +Please send bug reports to cassowary@cs.washington.edu + +Also, send mail to cassowary@cs.washington.edu if you would like to be +informed about bug fixes, feature enhancements, etc. Let us know what +implementation(s) you are using, too. + +------------------------------------------------------------------ + +HOW TO GET STARTED + +The Cassowary library uses GNU autoconf to permit easy building on +various platforms. You should be able to do: + +./configure +make + +and everything will work. A more complex, but realistic example is: + +./configure --with-prefix=/usr/contrib \ + --with-guile-prefix=/usr/contrib \ + --with-python-headers=/usr/include/python1.5 \ + --enable-java-build \ + --with-gtl=/usr/contrib \ + --with-java-class-path=/usr/contrib/share/java/site \ + --enable-warnings +make -k + +Be sure to give the extra --enable-permissive flag to configure if +you are building with gcc-2.95 or more recent. + +As yet another data point, I build Cassowary with: + +./configure --with-guile-exec-prefix=/uns/bin \ + --with-guile-prefix=/uns/share --prefix=/uns/share \ + --exec-prefix=/uns --enable-maintainer-mode + +See the file "INSTALL" for more details about +autoconf support and the options that the "configure" takes. You can +also do "./configure --help" for the list of the options that configure +accepts. + +If the make in any of the subdirectories fails, you can turn on the "-k" +option to make, or just do make in the subdirectories that you want +build. E.g., if you do not have the JDK installed, the Java version of +Cassowary might not compile; if you still want the guile version, just +"cd guile; make -k". + +Be sure that configure detects the validity of using the "-fpermissive" +flag of more recent g++/egcs compilers to work around some +const-discrepancies between the const-challenged guile header files and +Cassowary's more const-correct usage. You should get a message like: + + checking whether gcc understands -fpermissive option... yes + +when running configure if you're using, e.g., gcc-2.95 or later. + +You need to apply GTL.h.patch to the installed GTL.h header file for +Cassowary to compile with recent versions of egcs/gcc (e.g., gcc-2.95). + +Also, you may need to change libguile/gsubr.h from: + + extern SCM scm_make_gsubr SCM_P ((char *name, int req, int opt, + int rst, SCM (*fcn)())); + to + + extern SCM scm_make_gsubr SCM_P ((char *name, int req, int opt, + int rst, void*)); + +or patch guile's snarf.h to insert the appropriate case at each call to +SCM_PROC and SCM_PROC1. (Thanks to Alexandre Duret-Lutz for the above +information about more recent g++/egcs compilers). + +Note that the generated Makefiles depend upon features of GNU Make. See: + +ftp://ftp.gnu.org/pub/gnu/ + +for a version of make that you can build first to then build Cassowary. + +Example applications exist in subdirectories of the top-level +implementation subdirectories (e.g., c++/qdemos contains demos for C++ +that use the Qt Widget toolkit). + +Please send mail to cassowary@cs.washington.edu if you are using this +toolkit so we know how to reach you for bug fixes, updates, etc. + +------------------------------------------------------------------ + +WHAT THE DISTRIBUTION CONTAINS + +This distribution contains 3 implementations of the Cassowary constraint +solving toolkit: + +o C++ +o Java +o Smalltalk + +For each implementation language, there is at least one example program; +for some there are many. + +There is a wrapping of the C++ solver in Guile-Scheme -- see the guile/ +subdirectory. Also, Anthony Beurivé has wrapped Cassowary for +STk/Scheme. His code is available at: + + http://dept-info.labri.u-bordeaux.fr/~beurive/Code + +and the STk Scheme system is available at: + + http://kaolin.unice.fr/STk/ + +There is also a SWIG-generated wrapper of the C++ library making the +solver available from the Python language. + +A technical report describing the solver, its interface, and its +implementation is in cassowary-tr.ps (pdf version in cassowary-tr.pdf). +This paper is required reading if you intend to use the solver in your +own project(s). + +See also the Scwm (Scheme Constraints Window Manager) web page: + +http://scwm.mit.edu/scwm/ + +Scwm, also by Greg Badros (and Maciej Stachowiak), is the most +substantial application using this toolkit that we are aware of. + +------------------------------------------------------------------ + +VARIOUS IMPLEMENTATION NOTES + +Cassowary/C++ needs to be compiled using a modern C++ compiler. +At one time or another, it has compiled using: + o egcs-1.0.1 + o egcs-1.0.3a + o egcs-1.1b + o egcs-1.1.1 + o gcc-2.8.1 (needs libstdc++-2.8.x, too) + o Visual C++ 5.0 (not tried recently) + +In particular, Cassowary will *not* build with gcc-2.7.x.x! + +See c++/README for more details about building the C++ version. + +The C++ implementation of the toolkit also has an optional finite domain +subsolver. You need to build and install the GTL -- the Graph Template +Library -- and use the "--with-gtl=DIR" configure option for the finite +domain subsolver to be built. GTL is available from: + +http://www.fmi.uni-passau.de/Graphlet/GTL/ + +Cassowary was tested against GTL-0.3.1; it may work with later +versions, but I have not tried it. You need to apply GTL.h.patch to +the installed GTL.h header file for Cassowary to compile with recent +versions of egcs/gcc (e.g., gcc-2.95). + +Cassowary/Java was developed using Sun's JDK-1.1.x, ported to Linux +More recent versions should work fine. + +See java/README for more details about building the Java version. + + +Cassowary/Smalltalk was written under OTI Smalltalk-- other versions of +smalltalk will likely require (possibly significant) changes. + +See smalltalk/README for more details about the Smalltalk version. + +See guile/README for details about the Guile Scheme wrapper of the C++ +implementation, and for a pointer to SCWM, the Scheme Constraints Window +Manager which uses Cassowary. + +The Python bindings (by Tessa Lau) bindings for the Cassowary library +are in the wrappers/ subdirectory. SWIG was used in wrapping the +library. These bindings may no longer work, and are provided only for +your hacking pleasure (please send back useful patches if you do get the +code working). + +For more information about SWIG, see: + +http://www.swig.org/ + + +For more information about the Python language, see: + +http://www.python.org/ + + +For more information about the Guile-Scheme language, see: + +http://www.red-bean.com/guile/ +http://www.fsf.org/software/guile/guile.html + + +------------------------------------------------------------------ + +DEMONSTRATION APPLICATION + +A standard demonstration application is included for each implementation +of the Cassowary solver. The application builds a quadrilateral and +connects the neighboring midpoints of each of the outer edges to form an +interior quadrilateral which is provably a parallelogram. The +constraint solver manages the constraints to keep the outer +quadrilateral inside the window, keep the midpoints properly positioned, +and keep the outer quadrilateral from turning "inside out." + +The user is able to select points (draggable boxes) and move them around +within the window (both midpoints and endpoints can be selected, of +course). The solver updates the figure, and redraws. + + +------------------------------------------------------------------ + +FUNDING ACKNOWLEDGEMENTS + +This work has been funded in part by the National Science Foundation under +Grants IRI-9302249 and CCR-9402551, by Object Technology International, and +by a Fulbright Award from the Australian-American Educational +Foundation. + +Additionally, Greg Badros is supported by a National Science Foundation +Graduate Research Fellowship. Parts of this material are based upon +work supported under that fellowship. diff --git a/libs/cassowary/THANKS b/libs/cassowary/THANKS new file mode 100644 index 0000000000..11918b3d52 --- /dev/null +++ b/libs/cassowary/THANKS @@ -0,0 +1,30 @@ +Cassowary Constraint Solving Toolkit was +Implemented by: + +Greg J. Badros <gjb@cs.washington.edu> and +Alan Borning <borning@cs.washington.edu> +University of Washington +Computer Science and Engineering +Seattle, WA 98195-2350 + +with Constraint Drawing Applet (CDA) by Michael Noth <noth@cs.washington.edu> + +Please send bug reports to cassowary@cs.washington.edu + + +Bug reports, helpful testing, and/or code from: + +Spencer Allain +Anthony Beurivé +Robert Chassell +Alexandre 'Pollux' Duret-Lutz +Michael Kaufmann +Brian Grant +Pengling He +Tessa Lau +John MacPhail +Larry Melia +Michael Noth +Emmanuel Pietriga +Will Portnoy +Steve Wolfman diff --git a/libs/cassowary/autogen.sh b/libs/cassowary/autogen.sh new file mode 100644 index 0000000000..4d1bcb29e5 --- /dev/null +++ b/libs/cassowary/autogen.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +aclocal $ACLOCAL_FLAGS && autoheader && automake --add-missing && autoconf + diff --git a/libs/cassowary/cassowary-config b/libs/cassowary/cassowary-config new file mode 100755 index 0000000000..172237763e --- /dev/null +++ b/libs/cassowary/cassowary-config @@ -0,0 +1,102 @@ +#!/bin/sh +# Modified from gtk-config +# --09/07/99 gjb + +# gotten from LDADD in c++/Makefile.am +cassowary_gtllibs="" +cassowary_libs="-L/usr/local/lib $cassowary_gtllibs" +cassowary_cflags="-I/usr/local/include " + +prefix=/usr/local +exec_prefix=${prefix} +exec_prefix_set=no + +usage() +{ + cat <<EOF +Usage: cassowary-config [OPTIONS] +Options: + [--prefix[=DIR]] + [--exec-prefix[=DIR]] + [--version] + [--libs] + [--gtllibs] + [--cflags] +EOF + exit $1 +} + +if test $# -eq 0; then + usage 1 1>&2 +fi + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + if test $exec_prefix_set = no ; then + exec_prefix=$optarg + fi + ;; + --prefix) + echo_prefix=yes + ;; + --exec-prefix=*) + exec_prefix=$optarg + exec_prefix_set=yes + ;; + --exec-prefix) + echo_exec_prefix=yes + ;; + --version) + echo 0.60 + ;; + --cflags) + echo_cflags=yes + ;; + --libs) + echo_libs=yes + ;; + --gtllibs) + echo_gtllibs=yes + ;; + *) + usage 1 1>&2 + ;; + esac + shift +done + +if test "$echo_prefix" = "yes"; then + echo $prefix +fi + +if test "$echo_exec_prefix" = "yes"; then + echo $exec_prefix +fi + + +if test "$echo_cflags" = "yes"; then + if test ${prefix}/include != /usr/include ; then + includes=-I${prefix}/include + for i in $cassowary_cflags ; do + if test $i = -I${prefix}/include ; then + includes="" + fi + done + fi + echo $includes $cassowary_cflags +fi + +if test "$echo_libs" = "yes"; then + echo -L${exec_prefix}/lib -lcassowary -lstdc++ $cassowary_libs +fi + +if test "$echo_gtllibs" = "yes"; then + echo $cassowary_gtllibs +fi diff --git a/libs/cassowary/cassowary-config.in b/libs/cassowary/cassowary-config.in new file mode 100755 index 0000000000..ac1b3ac8ce --- /dev/null +++ b/libs/cassowary/cassowary-config.in @@ -0,0 +1,102 @@ +#!/bin/sh +# Modified from gtk-config +# --09/07/99 gjb + +# gotten from LDADD in c++/Makefile.am +cassowary_gtllibs="@GTL_LIB@" +cassowary_libs="-L@prefix@/lib $cassowary_gtllibs" +cassowary_cflags="@GUILE_INCLUDES@ @GTL_INCLUDES@" + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +exec_prefix_set=no + +usage() +{ + cat <<EOF +Usage: cassowary-config [OPTIONS] +Options: + [--prefix[=DIR]] + [--exec-prefix[=DIR]] + [--version] + [--libs] + [--gtllibs] + [--cflags] +EOF + exit $1 +} + +if test $# -eq 0; then + usage 1 1>&2 +fi + +while test $# -gt 0; do + case "$1" in + -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + case $1 in + --prefix=*) + prefix=$optarg + if test $exec_prefix_set = no ; then + exec_prefix=$optarg + fi + ;; + --prefix) + echo_prefix=yes + ;; + --exec-prefix=*) + exec_prefix=$optarg + exec_prefix_set=yes + ;; + --exec-prefix) + echo_exec_prefix=yes + ;; + --version) + echo @CASSOWARY_VERSION@ + ;; + --cflags) + echo_cflags=yes + ;; + --libs) + echo_libs=yes + ;; + --gtllibs) + echo_gtllibs=yes + ;; + *) + usage 1 1>&2 + ;; + esac + shift +done + +if test "$echo_prefix" = "yes"; then + echo $prefix +fi + +if test "$echo_exec_prefix" = "yes"; then + echo $exec_prefix +fi + + +if test "$echo_cflags" = "yes"; then + if test @includedir@ != /usr/include ; then + includes=-I@includedir@ + for i in $cassowary_cflags ; do + if test $i = -I@includedir@ ; then + includes="" + fi + done + fi + echo $includes $cassowary_cflags +fi + +if test "$echo_libs" = "yes"; then + echo -L@libdir@ -lcassowary -lstdc++ $cassowary_libs +fi + +if test "$echo_gtllibs" = "yes"; then + echo $cassowary_gtllibs +fi diff --git a/libs/cassowary/cassowary-nofd.spec2 b/libs/cassowary/cassowary-nofd.spec2 new file mode 100644 index 0000000000..d1abb93c5f --- /dev/null +++ b/libs/cassowary/cassowary-nofd.spec2 @@ -0,0 +1,84 @@ +# Note that this is NOT a relocatable package +%define ver 0.60 +%define rel 2 +%define prefix /usr + +Name: cassowary-nofd +Summary: A Linear Arithmetic Constraint Solving Library. +Version: %ver +Release: %rel +# This source just has a different top-level directory name +Source: http://www.cs.washington.edu/research/constraints/cassowary/cassowary-nofd-%ver.tar.gz +Group: Development/Libraries +BuildRoot: /tmp/cassowary-%ver-build +Copyright: Copyright (C) 1998,1999 Greg J. Badros +Packager: Greg J. Badros <gjb@cs.washington.edu> +URL: http://www.cs.washington.edu/research/constraints/cassowary +Requires: guile >= 1.3.2 +Provides: cassowary-constraint-solver + +%description + +Cassowary is an advanced incremental constraint solving toolkit that +efficiently solves systems of linear equalities and inequalities. +Constraints may be either requirements or preferences. Client code +specifies the constraints to be maintained, and the solver updates the +constrained variables to have values that satisfy the constraints. + +This package lacks the finite domain subsolver. The cassowary RPM +contains that solver as well, but also requires the GTL (Graph +Template Library) package. + + +%changelog +* Tue Sep 7 1999 Greg J. Badros <gjb@cs.washington.edu) +- Added cassowary-nofd package to remove GTL dependence, added provides + virtual package "cassowary-constraint-solver" so that both this .spec + and cassowary.spec can provide it + +* Sat Sep 4 1999 Greg J. Badros <gjb@cs.washington.edu) +- Use -fpermissive if it is available, fix --enable-warnings + +* Wed Aug 25 1999 Greg J. Badros <gjb@cs.washington.edu> +- Rework spec file. + +* Wed Apr 14 1999 Greg J. Badros <gjb@cs.washington.edu> + +- Initial release of this package. + +%prep + +%setup + +%build +ln -sf . ./c++/cassowary + +%ifarch alpha +./configure --host=alpha-linux --prefix=%prefix --enable-guile-build --enable-fsstd --enable-permissive +%else +./configure --prefix=%prefix --enable-guile-build --enable-fsstd --enable-permissive +%endif + +make + +%install +make prefix=$RPM_BUILD_ROOT%{prefix} install-strip + +%clean +rm -rf $RPM_BUILD_ROOT + +%post + +%postun + +%files +%defattr(-, root, root) + +%{prefix}/bin/* +%{prefix}/lib/* +%{prefix}/include/* + +%doc ANNOUNCE AUTHORS COPYING IMPORTANT INSTALL LICENSE NEWS README THANKS +%doc ChangeLog docs/cassowary-tr.pdf docs/cassowary-tr.ps.gz +%doc guile/cassowary_scm-procedures.txt guile/cassowary_scm-variables.txt +%doc guile/cassowary_scm.sgml diff --git a/libs/cassowary/cassowary-nofd.spec2.in b/libs/cassowary/cassowary-nofd.spec2.in new file mode 100644 index 0000000000..ee951bb446 --- /dev/null +++ b/libs/cassowary/cassowary-nofd.spec2.in @@ -0,0 +1,84 @@ +# Note that this is NOT a relocatable package +%define ver @VERSION@ +%define rel 2 +%define prefix /usr + +Name: cassowary-nofd +Summary: A Linear Arithmetic Constraint Solving Library. +Version: %ver +Release: %rel +# This source just has a different top-level directory name +Source: http://www.cs.washington.edu/research/constraints/cassowary/cassowary-nofd-%ver.tar.gz +Group: Development/Libraries +BuildRoot: /tmp/cassowary-%ver-build +Copyright: Copyright (C) 1998,1999 Greg J. Badros +Packager: Greg J. Badros <gjb@cs.washington.edu> +URL: http://www.cs.washington.edu/research/constraints/cassowary +Requires: guile >= 1.3.2 +Provides: cassowary-constraint-solver + +%description + +Cassowary is an advanced incremental constraint solving toolkit that +efficiently solves systems of linear equalities and inequalities. +Constraints may be either requirements or preferences. Client code +specifies the constraints to be maintained, and the solver updates the +constrained variables to have values that satisfy the constraints. + +This package lacks the finite domain subsolver. The cassowary RPM +contains that solver as well, but also requires the GTL (Graph +Template Library) package. + + +%changelog +* Tue Sep 7 1999 Greg J. Badros <gjb@cs.washington.edu) +- Added cassowary-nofd package to remove GTL dependence, added provides + virtual package "cassowary-constraint-solver" so that both this .spec + and cassowary.spec can provide it + +* Sat Sep 4 1999 Greg J. Badros <gjb@cs.washington.edu) +- Use -fpermissive if it is available, fix --enable-warnings + +* Wed Aug 25 1999 Greg J. Badros <gjb@cs.washington.edu> +- Rework spec file. + +* Wed Apr 14 1999 Greg J. Badros <gjb@cs.washington.edu> + +- Initial release of this package. + +%prep + +%setup + +%build +ln -sf . ./c++/cassowary + +%ifarch alpha +./configure --host=alpha-linux --prefix=%prefix --enable-guile-build --enable-fsstd --enable-permissive +%else +./configure --prefix=%prefix --enable-guile-build --enable-fsstd --enable-permissive +%endif + +make + +%install +make prefix=$RPM_BUILD_ROOT%{prefix} install-strip + +%clean +rm -rf $RPM_BUILD_ROOT + +%post + +%postun + +%files +%defattr(-, root, root) + +%{prefix}/bin/* +%{prefix}/lib/* +%{prefix}/include/* + +%doc ANNOUNCE AUTHORS COPYING IMPORTANT INSTALL LICENSE NEWS README THANKS +%doc ChangeLog docs/cassowary-tr.pdf docs/cassowary-tr.ps.gz +%doc guile/cassowary_scm-procedures.txt guile/cassowary_scm-variables.txt +%doc guile/cassowary_scm.sgml diff --git a/libs/cassowary/cassowary.spec b/libs/cassowary/cassowary.spec new file mode 100644 index 0000000000..bd30177048 --- /dev/null +++ b/libs/cassowary/cassowary.spec @@ -0,0 +1,78 @@ +# Note that this is NOT a relocatable package +%define ver 0.60 +%define rel 1 +%define prefix /usr + +Name: cassowary +Summary: A Linear Arithmetic Constraint Solving Library. +Version: %ver +Release: %rel +Source: http://www.cs.washington.edu/research/constraints/cassowary/cassowary-%ver.tar.gz +Group: Development/Libraries +BuildRoot: /tmp/cassowary-%ver-build +Copyright: Copyright (C) 1998,1999 Greg J. Badros +Packager: Greg J. Badros <gjb@cs.washington.edu> +URL: http://www.cs.washington.edu/research/constraints/cassowary +Requires: guile >= 1.3.4 +Requires: GTL >= 0.3.1 +Provides: cassowary-constraint-solver + +%description + +Cassowary is an advanced incremental constraint solving toolkit that +efficiently solves systems of linear equalities and inequalities. +Constraints may be either requirements or preferences. Client code +specifies the constraints to be maintained, and the solver updates the +constrained variables to have values that satisfy the constraints. + +%changelog +* Tue Sep 7 1999 Greg J. Badros <gjb@cs.washington.edu) +- added provides virtual package "cassowary-constraint-solver" so that + both this .spec and cassowary.spec can provide it + +* Sat Sep 4 1999 Greg J. Badros <gjb@cs.washington.edu) +- Use -fpermissive if it is available, fix --enable-warnings + +* Wed Aug 25 1999 Greg J. Badros <gjb@cs.washington.edu> +- Rework spec file. + +* Wed Apr 14 1999 Greg J. Badros <gjb@cs.washington.edu> + +- Initial release of this package. + +%prep + +%setup + +%build +ln -sf . ./c++/cassowary + +%ifarch alpha +fake_root_for_install=$RPM_BUILD_ROOT ./configure --host=alpha-linux --prefix=%prefix --with-gtl=%prefix --enable-fd-solver --enable-fsstd --enable-permissive +%else +fake_root_for_install=$RPM_BUILD_ROOT ./configure --prefix=%prefix --with-gtl=%prefix --enable-fd-solver --enable-fsstd --enable-permissive +%endif + +make + +%install +make prefix=$RPM_BUILD_ROOT%{prefix} fake_root_for_install=$RPM_BUILD_ROOT install-strip + +%clean +rm -rf $RPM_BUILD_ROOT + +%post + +%postun + +%files +%defattr(-, root, root) + +%{prefix}/bin/* +%{prefix}/lib/* +%{prefix}/include/* + +%doc ANNOUNCE AUTHORS COPYING IMPORTANT INSTALL LICENSE NEWS README THANKS +%doc ChangeLog docs/cassowary-tr.pdf docs/cassowary-tr.ps.gz +%doc guile/cassowary_scm-procedures.txt guile/cassowary_scm-variables.txt +%doc guile/cassowary_scm.sgml diff --git a/libs/cassowary/cassowary.spec.in b/libs/cassowary/cassowary.spec.in new file mode 100644 index 0000000000..2b7c23a8e5 --- /dev/null +++ b/libs/cassowary/cassowary.spec.in @@ -0,0 +1,78 @@ +# Note that this is NOT a relocatable package +%define ver @VERSION@ +%define rel 1 +%define prefix /usr + +Name: cassowary +Summary: A Linear Arithmetic Constraint Solving Library. +Version: %ver +Release: %rel +Source: http://www.cs.washington.edu/research/constraints/cassowary/cassowary-%ver.tar.gz +Group: Development/Libraries +BuildRoot: /tmp/cassowary-%ver-build +Copyright: Copyright (C) 1998,1999 Greg J. Badros +Packager: Greg J. Badros <gjb@cs.washington.edu> +URL: http://www.cs.washington.edu/research/constraints/cassowary +Requires: guile >= 1.3.4 +Requires: GTL >= 0.3.1 +Provides: cassowary-constraint-solver + +%description + +Cassowary is an advanced incremental constraint solving toolkit that +efficiently solves systems of linear equalities and inequalities. +Constraints may be either requirements or preferences. Client code +specifies the constraints to be maintained, and the solver updates the +constrained variables to have values that satisfy the constraints. + +%changelog +* Tue Sep 7 1999 Greg J. Badros <gjb@cs.washington.edu) +- added provides virtual package "cassowary-constraint-solver" so that + both this .spec and cassowary.spec can provide it + +* Sat Sep 4 1999 Greg J. Badros <gjb@cs.washington.edu) +- Use -fpermissive if it is available, fix --enable-warnings + +* Wed Aug 25 1999 Greg J. Badros <gjb@cs.washington.edu> +- Rework spec file. + +* Wed Apr 14 1999 Greg J. Badros <gjb@cs.washington.edu> + +- Initial release of this package. + +%prep + +%setup + +%build +ln -sf . ./c++/cassowary + +%ifarch alpha +fake_root_for_install=$RPM_BUILD_ROOT ./configure --host=alpha-linux --prefix=%prefix --with-gtl=%prefix --enable-fd-solver --enable-fsstd --enable-permissive +%else +fake_root_for_install=$RPM_BUILD_ROOT ./configure --prefix=%prefix --with-gtl=%prefix --enable-fd-solver --enable-fsstd --enable-permissive +%endif + +make + +%install +make prefix=$RPM_BUILD_ROOT%{prefix} fake_root_for_install=$RPM_BUILD_ROOT install-strip + +%clean +rm -rf $RPM_BUILD_ROOT + +%post + +%postun + +%files +%defattr(-, root, root) + +%{prefix}/bin/* +%{prefix}/lib/* +%{prefix}/include/* + +%doc ANNOUNCE AUTHORS COPYING IMPORTANT INSTALL LICENSE NEWS README THANKS +%doc ChangeLog docs/cassowary-tr.pdf docs/cassowary-tr.ps.gz +%doc guile/cassowary_scm-procedures.txt guile/cassowary_scm-variables.txt +%doc guile/cassowary_scm.sgml diff --git a/libs/cassowary/cassowary/.cvsignore b/libs/cassowary/cassowary/.cvsignore new file mode 100644 index 0000000000..282522db03 --- /dev/null +++ b/libs/cassowary/cassowary/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/libs/cassowary/cassowary/Cassowary.h b/libs/cassowary/cassowary/Cassowary.h new file mode 100644 index 0000000000..8413f321f9 --- /dev/null +++ b/libs/cassowary/cassowary/Cassowary.h @@ -0,0 +1,40 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// Cassowary.h + +#ifndef Cassowary_H +#define Cassowary_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) + #include <cassowary/config-inline.h> + #define CONFIG_INLINE_H_INCLUDED +#endif + +#ifndef CL_PTR_HASH_DIVISOR + #define CL_PTR_HASH_DIVISOR 4 +#endif + +#include "ClConstraintHash.h" +#include <climits> + +#include <string> +#include <cassert> +#include <iostream> + +typedef double Number; + +typedef long FDNumber; + +enum { FDN_NOTSET = LONG_MIN }; + +#define NEWVAR(x) do { cerr << "line " << __LINE__ << ": new " << x << endl; } while (0) +#define DELVAR(x) do { cerr << "line " << __LINE__ << ": del " << x << endl; } while (0) + +#endif // Cassowary_H diff --git a/libs/cassowary/cassowary/Cl.h b/libs/cassowary/cassowary/Cl.h new file mode 100644 index 0000000000..6c2604da6f --- /dev/null +++ b/libs/cassowary/cassowary/Cl.h @@ -0,0 +1,49 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// Cl.h +// This is the top level include file for external clients + +#ifndef CL_H +#define CL_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#ifdef CL_NO_IO +#undef CL_TRACE +#undef CL_SOLVER_STATS +#undef CL_DEBUG_FAILURES +#undef CL_TRACE_VERBOSE +#endif + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "cassowary/ClVariable.h" +#include "cassowary/ClSimplexSolver.h" +#include "cassowary/ClLinearEquation.h" +#include "cassowary/ClLinearInequality.h" +#include "cassowary/ClErrors.h" +#include "cassowary/ClEditConstraint.h" +#include "cassowary/ClStayConstraint.h" +#include "cassowary/ClReader.h" +#include "cassowary/ClConstraint.h" +#if defined(CL_HAVE_GTL) && defined(CL_BUILD_FD_SOLVER) +#include "cassowary/ClFDBinaryOneWayConstraint.h" +#include "cassowary/ClFDSolver.h" +#endif + +extern const char *szCassowaryVersion; + +#endif diff --git a/libs/cassowary/cassowary/ClAbstractVariable.h b/libs/cassowary/cassowary/ClAbstractVariable.h new file mode 100644 index 0000000000..08ade9ec98 --- /dev/null +++ b/libs/cassowary/cassowary/ClAbstractVariable.h @@ -0,0 +1,161 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClAbstractVariable.h + +#ifndef ClAbstractVariable_H +#define ClAbstractVariable_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include <cstdio> /* for sprintf */ +#include "Cassowary.h" +#include "ClErrors.h" +#include <memory> +#include <string> +#include <iostream> +#include "cl_auto_ptr.h" + +using std::string; +using std::ostream; + +class ClAbstractVariable { +public: + ClAbstractVariable(string Name = "") : + _name(Name), _pv(0) + { + ++iVariableNumber; +#ifdef CL_FIND_LEAK + ++cAbstractVariables; +#endif + if (Name.length() == 0) + { + char sz[16]; + sprintf(sz,"v%ld",iVariableNumber); + _name = string(sz); + } + } + + ClAbstractVariable(long varnumber, char *prefix) : + _pv(0) + { + cl_auto_ptr<char> pch (new char[16+strlen(prefix)]); + iVariableNumber++; +#ifdef CL_FIND_LEAK + ++cAbstractVariables; +#endif + sprintf(pch.get(),"%s%ld",prefix,varnumber); + _name = string(pch.get()); + } + + virtual ~ClAbstractVariable() +#ifdef CL_FIND_LEAK + { --cAbstractVariables; } + + static long cAbstractVariables; +#else + { } +#endif + + // Return the Name of the variable + string Name() const + { return _name; } + + // Set the Name of the variable + virtual void SetName(string const &Name) + { _name = Name; } + + // Return true iff this variable is a ClFloatVariable + virtual bool IsFloatVariable() const + { return false; } + + // Return true iff this variable is a ClFDVariable + virtual bool IsFDVariable() const + { return false; } + + // Return true if this a dummy variable (used as a marker variable + // for required equality constraints). Such variables aren't + // allowed to enter the basis when pivoting. + virtual bool IsDummy() const + { return false; } + + // Return true if this a variable known outside the solver. + // (We need to give such variables a Value after solving is complete.) + virtual bool IsExternal() const + { return false; } + + // Return true if we can Pivot on this variable. + virtual bool IsPivotable() const + { throw ExCLTooDifficultSpecial("Variable not usable inside SimplexSolver"); return false; } + + // Return true if this is a restricted (or slack) variable. Such + // variables are constrained to be non-negative and occur only + // internally to the simplex solver. + virtual bool IsRestricted() const + { throw ExCLTooDifficultSpecial("Variable not usable inside SimplexSolver"); return false; } + +#ifndef CL_NO_IO + // Prints a semi-descriptive representation to the stream, using the + // Name if there is one, and otherwise the hash number of this + // object. + // EXAMPLES + // x[10.0] -- w/ Name + // x[0.0,100] -- w/ Name, bounds but no Value yet + // CV#345(10.0) -- w/o Name + virtual ostream &PrintOn(ostream &xo) const = 0; + + friend ostream& operator<<(ostream &xos, const ClAbstractVariable &clv) + { clv.PrintOn(xos); return xos; } + +#endif // CL_NO_IO + + friend bool operator<(const ClAbstractVariable &cl1, const ClAbstractVariable &cl2) + { return &cl1 < &cl2; } + + friend bool operator==(const ClAbstractVariable &cl1, const ClAbstractVariable &cl2) + { + return &cl1 == &cl2; + } + + friend bool operator!=(const ClAbstractVariable &cl1, const ClAbstractVariable &cl2) + { + return !(cl1 == cl2); + } + + virtual Number Value() const { return 0; } + virtual int IntValue() const { return 0; } + + virtual void SetValue(Number) + { assert(false); } + + virtual void ChangeValue(Number) + { assert(false); } + + void SetPv(void *pv) + { _pv = pv; } + + void *Pv() const + { return _pv; } + +private: + string _name; + + static long iVariableNumber; + + // C-style extension mechanism so I + // don't have to wrap ScwmClVariables separately + void *_pv; +}; + +typedef ClAbstractVariable *PClAbstractVariable; + +#endif diff --git a/libs/cassowary/cassowary/ClConstraint.h b/libs/cassowary/cassowary/ClConstraint.h new file mode 100644 index 0000000000..0b670e6c07 --- /dev/null +++ b/libs/cassowary/cassowary/ClConstraint.h @@ -0,0 +1,198 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClConstraint.h + +#ifndef ClConstraint_H +#define ClConstraint_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "debug.h" + +#include "Cassowary.h" +#include "ClLinearExpression.h" +#include "ClStrength.h" +#include <string> + +using std::string; + +class ClSimplexSolver; +class ClFDSolver; +class ClBlueSolver; + +// enum setup so additive inverse flips the direction of the inequality +enum ClCnRelation {cnEQ = 0, cnNEQ = 100, cnLEQ = 2, cnGEQ = -2, cnLT = 3, cnGT = -3 }; + +inline enum ClCnRelation +ReverseInequality(enum ClCnRelation c) +{ + if (c != cnNEQ) + c = (enum ClCnRelation) (- int(c)); + return c; +} + +inline string +StrCnRelation(enum ClCnRelation rel) { + switch (rel) { + case cnEQ: return "="; + case cnNEQ: return "=/="; + case cnLEQ: return "<="; + case cnGEQ: return ">="; + case cnLT: return "<"; + case cnGT: return ">"; + default: assert(false); + } +} + + + +class ClConstraint { +public: + + ClConstraint(const ClStrength &strength = ClsRequired(), double weight = 1.0 ) : + _strength(strength), + _readOnlyVars(), + _weight(weight), + _pv(0), + _times_added(0) + { + CtrTracer(__FUNCTION__,this); + } + + virtual ~ClConstraint() + { + DtrTracer(__FUNCTION__,this); + } + + // Return my linear Expression. (For linear equations, this + // constraint represents Expression=0; for linear inequalities it + // represents Expression>=0.) + virtual ClLinearExpression Expression() const + { assert(false); } + + // Returns true if this is an edit constraint + virtual bool IsEditConstraint() const + { return false; } + + // Return true if this is an inequality constraint and + // false if it is an equality constraint. The default is + // that it is not. + virtual bool IsInequality() const + { return false; } + + virtual bool IsStrictInequality() const + { return false; } + + virtual bool IsRequired() const + { return _strength.IsRequired(); } + + virtual bool isStayConstraint() const + { return false; } + + virtual const ClStrength &strength() const + { return _strength; } + + virtual double weight() const + { return _weight; } + +#ifndef CL_NO_IO + virtual ostream &PrintOn(ostream &xo) const = 0; + + friend ostream& operator<<(ostream &xos, const ClConstraint &constraint) + { constraint.PrintOn(xos); return xos; } + +#endif + + + void SetPv(void *pv) + { _pv = pv; } + + void *Pv() const + { return _pv; } + + virtual bool FIsSatisfied() const { return false; } + + virtual bool FIsInSolver() const { return _times_added != 0; } + + virtual bool FIsOkayForSimplexSolver() const { return true; } + + void ChangeStrength( const ClStrength &strength) + { + if (_times_added == 0) { + setStrength(strength); + } else { + throw ExCLTooDifficult(); + } + } + + void ChangeWeight( double weight ) + { + if (_times_added == 0) { + setWeight(weight); + } else { + throw ExCLTooDifficult(); + } + } + + bool FIsReadOnlyVar(ClVariable v) const { + return !(_readOnlyVars.find(v) == _readOnlyVars.end()); + } + + const ClVarSet &ReadOnlyVars() const { + return _readOnlyVars; + } + + ClConstraint &AddROVars(const ClVarSet &setClv) { + for ( ClVarSet::const_iterator it = setClv.begin(); + it != setClv.end(); ++it) { + _readOnlyVars.insert(*it); + } + return *this; + } + + friend class ClSimplexSolver; + friend class ClFDSolver; + friend class ClBlueSolver; +private: + + ClSymbolicWeight symbolicWeight() const { + return _strength.symbolicWeight(); + } + + void addedTo(const ClSimplexSolver &) + { ++_times_added; } + + void removedFrom(const ClSimplexSolver &) + { --_times_added; } + + void setStrength( const ClStrength &strength ) + { _strength = strength; } + + void setWeight( double weight ) + { _weight = weight; } + + /// instance variables + ClStrength _strength; + + ClVarSet _readOnlyVars; + + double _weight; + + void *_pv; + + int _times_added; +}; + +typedef ClConstraint* PClConstraint; + +#endif diff --git a/libs/cassowary/cassowary/ClConstraintHash.h b/libs/cassowary/cassowary/ClConstraintHash.h new file mode 100644 index 0000000000..9d51fad311 --- /dev/null +++ b/libs/cassowary/cassowary/ClConstraintHash.h @@ -0,0 +1,39 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClHash.h + +#ifndef CL_HASH_H__ +#define CL_HASH_H__ + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#ifdef CL_USE_HASH_MAP_AND_SET + +#include <hash_map> + +class ClConstraint; + +struct hash<const ClConstraint *> { + size_t operator()(const ClConstraint * const p) const + { return size_t((unsigned long)p/CL_PTR_HASH_DIVISOR); } +}; + +struct hash<ClConstraint *> { + size_t operator()(ClConstraint * const p) const + { return size_t((unsigned long)p/CL_PTR_HASH_DIVISOR); } +}; + +#endif // CL_USE_HASH_MAP_AND_SET + + +#endif diff --git a/libs/cassowary/cassowary/ClDummyVariable.h b/libs/cassowary/cassowary/ClDummyVariable.h new file mode 100644 index 0000000000..ad959a6d20 --- /dev/null +++ b/libs/cassowary/cassowary/ClDummyVariable.h @@ -0,0 +1,88 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClDummyVariable.h + +#ifndef ClDummyVariable_H +#define ClDummyVariable_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClAbstractVariable.h" + +class ClTableau; +class ClSimplexSolver; + +class ClDummyVariable : public ClAbstractVariable { + +public: + +#ifdef CL_FIND_LEAK + ~ClDummyVariable() { --cDummyVariables; }; + + static long cDummyVariables; + +#endif + +protected: + friend class ClTableau; + friend class ClSimplexSolver; + + ClDummyVariable(string Name = "") : + ClAbstractVariable(Name) + { +#ifdef CL_FIND_LEAK + ++cDummyVariables; +#endif + } + + ClDummyVariable(long number, char *prefix) : + ClAbstractVariable(number,prefix) + { +#ifdef CL_FIND_LEAK + ++cDummyVariables; +#endif + } + +#ifndef CL_NO_IO + virtual ostream &PrintOn(ostream &xo) const + { + xo << "[" << Name() << ":dummy]"; + return xo; + } +#endif + + // Return true if this a dummy variable (used as a marker variable + // for required equality constraints). Such variables aren't + // allowed to enter the basis when pivoting. + virtual bool IsDummy() const + { return true; } + + // Return true if this a variable known outside the solver. + // (We need to give such variables a Value after solving is complete.) + virtual bool IsExternal() const + { return false; } + + // Return true if we can Pivot on this variable. + virtual bool IsPivotable() const + { return false; } + + // Return true if this is a restricted (or slack) variable. Such + // variables are constrained to be non-negative and occur only + // internally to the simplex solver. + virtual bool IsRestricted() const + { return true; } + +}; + +#endif diff --git a/libs/cassowary/cassowary/ClEditConstraint.h b/libs/cassowary/cassowary/ClEditConstraint.h new file mode 100644 index 0000000000..4bd91e2ca2 --- /dev/null +++ b/libs/cassowary/cassowary/ClEditConstraint.h @@ -0,0 +1,45 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClEditConstraint.h + +#ifndef ClEditConstraint_H +#define ClEditConstraint_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClEditOrStayConstraint.h" + +class ClEditConstraint : public ClEditOrStayConstraint { + typedef ClEditOrStayConstraint super; + public: + + ClEditConstraint(const ClVariable var, + const ClStrength &strength = ClsStrong(), double weight = 1.0 ) : + ClEditOrStayConstraint(var,strength,weight) + { } + + // Returns true if this is an edit constraint + virtual bool IsEditConstraint() const + { return true; } + +#ifndef CL_NO_IO + virtual ostream &PrintOn(ostream &xo) const + { super::PrintOn(xo); return xo << "= edit)"; } +#endif + + private: + +}; + +#endif diff --git a/libs/cassowary/cassowary/ClEditOrStayConstraint.h b/libs/cassowary/cassowary/ClEditOrStayConstraint.h new file mode 100644 index 0000000000..79b6761b69 --- /dev/null +++ b/libs/cassowary/cassowary/ClEditOrStayConstraint.h @@ -0,0 +1,51 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClEditOrStayConstraint.h + +#ifndef ClEditOrStayConstraint_H +#define ClEditOrStayConstraint_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "ClConstraint.h" +#include "ClLinearExpression.h" + +class ClVariable; + +class ClEditOrStayConstraint : public ClConstraint { + public: + + ClEditOrStayConstraint(const ClVariable var, + const ClStrength &strength = ClsRequired(), double weight = 1.0 ) : + ClConstraint(strength,weight), + _variable(var) + { } + + const ClVariable variable() const + { return _variable; } + + ClLinearExpression Expression() const + { return ClLinearExpression(_variable,-1,_variable.Value()); } + + private: + + void setVariable( const ClVariable v) + { _variable = v; } + + /// instance variables + ClVariable _variable; + + +}; + +#endif diff --git a/libs/cassowary/cassowary/ClErrors.h b/libs/cassowary/cassowary/ClErrors.h new file mode 100644 index 0000000000..867c578dbc --- /dev/null +++ b/libs/cassowary/cassowary/ClErrors.h @@ -0,0 +1,179 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClErrors.h + +#ifndef ClErrors_H +#define ClErrors_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClTypedefs.h" +#include <string> +#include <exception> + +using std::string; +using std::exception; + +class ExCLError : public exception { + public: + ExCLError() : _msg(0) { } + virtual ~ExCLError() throw() {} + virtual string description() const + { return "(ExCLError) An error has occured in CL"; } + protected: + char *_msg; +}; + +class ExCLInternalError : public ExCLError { + public: + ExCLInternalError(const char *sz) + { _msg = strdup(sz); } + virtual string description() const + { + if (_msg) return _msg; + else return "(ExCLInternalError) An internal error has occurred"; + } +}; + +class ExCLBadResolve : public ExCLError { + public: + ExCLBadResolve(const char *sz) + { _msg = strdup(sz); } + virtual string description() const + { + if (_msg) return _msg; + else return "(ExCLBadResolve) Number of resolve values did not match number of edit vars"; + } +}; + +class ExCLEditMisuse : public ExCLError { + public: + ExCLEditMisuse(const char *sz) + { _msg = strdup(sz); } + virtual string description() const + { + if (_msg) return _msg; + return "(ExCLEditMisuse) Edit protocol usage violation"; + } +}; + +class ExCLTooDifficult : public ExCLError { + public: + virtual string description() const + { return "(ExCLTooDifficult) The constraints are too difficult to solve"; } +}; + +class ExCLTooDifficultSpecial : public ExCLTooDifficult { + public: + ExCLTooDifficultSpecial(const char *sz) + { _msg = strdup(sz); } + virtual string description() const + { + if (_msg) return _msg; + else return "(ExCLTooDifficultSpecial) Solver requirements are not satisfied"; + } +}; + +class ExCLReadOnlyNotAllowed : public ExCLTooDifficult { + public: + virtual string description() const + { return "(ExCLReadOnlyNotAllowed) The read-only annotation is not permitted by the solver"; } +}; + +class ExCLCycleNotAllowed : public ExCLTooDifficult { + public: + virtual string description() const + { return "(ExCLCycleNotAllowed) A cyclic constraint graph is not permitted by the solver"; } +}; + +class ExCLStrictInequalityNotAllowed : public ExCLTooDifficult { + public: + virtual string description() const + { return "(ExCLStrictInequalityNotAllowed) The strict inequality is not permitted by the solver"; } +}; + +class ExCLRequiredFailure : public ExCLError { + public: + virtual ~ExCLRequiredFailure() throw() {} + virtual string description() const + { return "(ExCLRequiredFailure) A required constraint cannot be satisfied"; } +}; + +class ExCLNotEnoughStays : public ExCLError { + public: + virtual string description() const + { return "(ExCLNotEnoughStays) There are not enough stays to give specific values to every variable"; } +}; + +class ExCLNonlinearExpression : public ExCLError { + public: + virtual string description() const + { return "(ExCLNonlinearExpression) The resulting expression would be nonlinear"; } +}; + +class ExCLConstraintNotFound : public ExCLError { + public: + virtual string description() const + { return "(ExCLConstraintNotFound) Tried to remove a constraint that was never added"; } +}; + +class ExCLParseError : public ExCLError { + public: + virtual ~ExCLParseError() throw() {} + virtual string description() const + { return "(ExCLParseError)"; } +}; + +class ExCLParseErrorMisc : public ExCLParseError { + public: + ExCLParseErrorMisc(const string &s) + : _msg("(ExCLParseError) ") + { _msg += s; } + virtual ~ExCLParseErrorMisc() throw() {} + virtual string description() const + { return _msg; } + private: + string _msg; +}; + +class ExCLParseErrorBadIdentifier : public ExCLParseError { + public: + ExCLParseErrorBadIdentifier(const string &id) + : _msg("(ExCLParseErrorBadIdentifier) Did not recognize identifier '") + { + _msg += id; + _msg += "'"; + } + virtual ~ExCLParseErrorBadIdentifier() throw() {} + virtual string description() const + { return _msg; } + private: + string _msg; +}; + +class ExCLRequiredFailureWithExplanation : public ExCLRequiredFailure +{ +public: + virtual ~ExCLRequiredFailureWithExplanation() throw() {} + virtual string description() const + { return "(ExCLRequiredFailureWithExplanation) A required constraint cannot be satisfied"; } + virtual void AddConstraint(const ClConstraint *cnExpl) + { _explanation.insert(cnExpl); } + virtual const ClConstraintSet & explanation() const + { return _explanation; } +protected: + ClConstraintSet _explanation; +}; + +#endif // ClErrors_H diff --git a/libs/cassowary/cassowary/ClFDBinaryOneWayConstraint.h b/libs/cassowary/cassowary/ClFDBinaryOneWayConstraint.h new file mode 100644 index 0000000000..a779ec1f91 --- /dev/null +++ b/libs/cassowary/cassowary/ClFDBinaryOneWayConstraint.h @@ -0,0 +1,94 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClFDBinaryOneWayConstraint.h + +#ifndef ClFDBinaryOneWayConstraint_H +#define ClFDBinaryOneWayConstraint_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClFDConstraint.h" + +class ClLinearConstraint; + +// Just a node in the class hierarchy for now +class ClFDBinaryOneWayConstraint : public ClFDConstraint { + private: typedef ClFDConstraint super; + + public: + + ClFDBinaryOneWayConstraint(ClVariable vRW, enum ClCnRelation rel, ClVariable vRO, + double coefficient = 1.0, double constant = 0.0, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) + : ClFDConstraint(strength,weight), _vRW(vRW), _rel(rel), _vRO(vRO), + _coefficient(coefficient), _constant(constant) + { } + + ClFDBinaryOneWayConstraint(ClVariable vRW, enum ClCnRelation rel, double constant, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) + : ClFDConstraint(strength,weight), _vRW(vRW), _rel(rel), _vRO(clvNil), + _coefficient(0), _constant(constant) + { } + + ClFDBinaryOneWayConstraint(const ClConstraint &cn); + + static void EnsurePreconditionsForCn(const ClConstraint &cn); + + static bool FCanConvertCn(const ClConstraint &cn); + +#ifndef CL_NO_IO + virtual ostream &PrintOn(ostream &xo) const + { + xo << "FDCn: " << _vRW << " " << StrCnRelation(_rel) << " "; + if (_coefficient != 0) { + if (_coefficient != 1) xo << _coefficient << "*"; + if (_vRO != clvNil) xo << _vRO; + } + if (_constant != 0) xo << " + " << _constant; + return xo; + } + + friend ostream& operator<<(ostream &xos, const ClFDBinaryOneWayConstraint &constraint) + { return constraint.PrintOn(xos); } + +#endif + + ClVariable ClvRW() const + { return _vRW; } + ClVariable ClvRO() const + { return _vRO; } + enum ClCnRelation Relation() const + { return _rel; } + double Coefficient() const + { return _coefficient; } + double Constant() const + { return _constant; } + + bool IsInequality() const + { return (_rel != cnEQ && _rel != cnNEQ); } + + bool IsStrictInequality() const + { return (_rel == cnGT || _rel == cnLT); } + + protected: + ClVariable _vRW; + enum ClCnRelation _rel; + ClVariable _vRO; + double _coefficient; + double _constant; +}; + +#endif diff --git a/libs/cassowary/cassowary/ClFDConnectorVariable.h b/libs/cassowary/cassowary/ClFDConnectorVariable.h new file mode 100644 index 0000000000..4ae38ae42e --- /dev/null +++ b/libs/cassowary/cassowary/ClFDConnectorVariable.h @@ -0,0 +1,89 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClFDConnectorVariable.h + +#ifndef ClFDConnectorVariable_H +#define ClFDConnectorVariable_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include <stdio.h> +#include <map> +#include <string> +#include <list> +#include "Cassowary.h" +#include "ClVariable.h" +#include "ClFDVariable.h" +#include "ClLinearEquation.h" +#include "ClSimplexSolver.h" + +/* Creates a new variable in the FD region + that sets clvFloat in solver (simplex region) + when it changes */ +class ClFDConnectorVariable : public ClFDVariable { +public: + typedef ClFDVariable super; + + ClFDConnectorVariable(string name, FDNumber Value, const list<FDNumber> &initial_domain, + ClSimplexSolver &solver, ClVariable clvFloat) : + ClFDVariable(name,Value,initial_domain), + _solver(solver), + _clvFloat(clvFloat), + _pcnRequiredLink(new ClLinearEquation(clvFloat,Value)) + { solver.AddConstraint(_pcnRequiredLink); } + +#ifndef CL_NO_IO + // Prints a semi-descriptive representation to the stream, using the + // name if there is one, and otherwise the hash number of this + // object. + // EXAMPLE + // [x:10.0] -- name = "x", Value = 10.0 + virtual ostream &PrintOn(ostream &xo) const; +#endif + + // permit overriding in subclasses in case something needs to be + // done when the Value is changed by the solver + // may be called when the Value hasn't actually changed -- just + // means the solver is setting the external variable + virtual void ChangeValue(FDNumber Value) + { + if (_value != Value) { + _value = Value; + cerr << "Updating " << _clvFloat << " now!" << endl; + _solver.RemoveConstraint(_pcnRequiredLink); + _pcnRequiredLink->ChangeConstant(_value); + _solver.AddConstraint(_pcnRequiredLink); + } + } + +private: + + // similar to SetValue -- see caveat above -- made private for now + // since it's probably the wrong thing and is too easy to invoke + FDNumber operator=(FDNumber Value) + { _value = Value; return Value; } + + // Copy constructor left undefined since we want to + // outlaw passing by Value! Will get a link error if you + // try to use within ClFDConnectorVariable.c, compile-time error everywhere else + ClFDConnectorVariable(const ClFDConnectorVariable &); + + ClSimplexSolver &_solver; + + ClVariable _clvFloat; + + ClLinearEquation *_pcnRequiredLink; + +}; + +#endif diff --git a/libs/cassowary/cassowary/ClFDConstraint.h b/libs/cassowary/cassowary/ClFDConstraint.h new file mode 100644 index 0000000000..2cf9776449 --- /dev/null +++ b/libs/cassowary/cassowary/ClFDConstraint.h @@ -0,0 +1,40 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClFDConstraint.h + +#ifndef ClFDConstraint_H +#define ClFDConstraint_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClConstraint.h" + + +// Just a node in the class hierarchy for now +class ClFDConstraint : public ClConstraint { + private: typedef ClConstraint super; + + public: + // Constructor + ClFDConstraint(const ClStrength &strength = ClsRequired(), + double weight = 1.0) + : ClConstraint(strength, weight) { } + + virtual bool FIsOkayForSimplexSolver() const { return false; } + + protected: + +}; + +#endif diff --git a/libs/cassowary/cassowary/ClFDSolver.h b/libs/cassowary/cassowary/ClFDSolver.h new file mode 100644 index 0000000000..2fbb637764 --- /dev/null +++ b/libs/cassowary/cassowary/ClFDSolver.h @@ -0,0 +1,120 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClSolver.h + +#ifndef ClFDSolver_H +#define ClFDSolver_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClSolver.h" +#include "ClVariable.h" +#include "ClErrors.h" +#include "ClTypedefs.h" +#include "ClSymbolicWeight.h" +#include <GTL/graph.h> +#include <map> + +using std::map; + +class ClVariable; +class ClFDBinaryOneWayConstraint; + +// ClFDSolver is a concrete class +// implementing a very restricted (for now --04/23/99 gjb) +// finite-domain constraint solving algorithm +class ClFDSolver: public ClSolver { + public: + ClFDSolver() + : _setCns(), _mapClvToCns(), G(), nodeToVar(G) + { G.make_directed(); } + + virtual ~ClFDSolver() + { } + + virtual ClFDSolver &AddConstraint(ClConstraint *const pcn); + + virtual ClFDSolver &RemoveConstraint(ClConstraint *const pcn); + + virtual ClFDSolver &Solve(); + + virtual ClFDSolver &ShowSolve(); + + void ChangeClv(ClVariable clv, FDNumber n) { + clv.ChangeValue(n); + if (_pfnChangeClvCallback) { + _pfnChangeClvCallback(&clv,this); + } + } + + +#ifndef CL_NO_IO + ostream &PrintOn(ostream &xo) const; + + ostream &PrintInternalInfo(ostream &xo) const; + + ostream &PrintOnVerbose(ostream &xo) const + { PrintOn(xo); PrintInternalInfo(xo); xo << endl; return xo; } + + friend ostream &operator<<(ostream &xo, const ClFDSolver &solver); + +#endif + + protected: + + virtual ClFDSolver &AddConstraintInternal(ClConstraint *const pcn); + + virtual ClFDSolver &RemoveConstraintInternal(ClConstraint *const pcn); + + /* Create node for v in G, if necessary, + otherwise return the node we already created. */ + node GetVarNode(ClVariable v); + + /* return the best (lowest) incremental error and the value + at which that error occurs */ + pair<ClSymbolicWeight,FDNumber> ComputeBest(ClFDVariable *pcldv); + + ClSymbolicWeight ErrorForClvAtValSubjectToCn(ClFDVariable *pcldv, + FDNumber value,const ClConstraint &cn); + + /* Turn all FDVariable FIsSet() flags to false */ + void ResetSetFlagsOnVariables(); + + /* all the constraints in the solver */ + ClConstraintSet _setCns; + + /* _mapClvToCns maps variable to the constraints in which + it is rw (it omits where it is ro) */ + ClVarToConstraintSetMap _mapClvToCns; + + /* track what edges correspond to which constraints + so we can update the constraint graph when + removing a constraint */ + map<ClConstraint *, edge> _mapCnToEdge; + + /* track what nodes correspond to which variables */ + map<ClVariable, node> _mapVarToNode; + + /* directed graph that mirrors the structure of + the relations of the added constraints */ + graph G; + + node_map<ClVariable> nodeToVar; +}; + +#define FDN_EOL LONG_MIN + +void ListPushOnto(list<FDNumber> *pl, ...); + +#endif diff --git a/libs/cassowary/cassowary/ClFDVariable.h b/libs/cassowary/cassowary/ClFDVariable.h new file mode 100644 index 0000000000..326b339459 --- /dev/null +++ b/libs/cassowary/cassowary/ClFDVariable.h @@ -0,0 +1,126 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClFDVariable.h + +#ifndef ClFDVariable_H +#define ClFDVariable_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include <cstdio> +#include <map> +#include <string> +#include <list> +#include "Cassowary.h" +#include "ClAbstractVariable.h" + +using std::map; +using std::list; +using std::string; + +class ClFDVariable : public ClAbstractVariable { +public: + typedef ClAbstractVariable super; + +#if 0 /* GJB:FIXME:: */ + ClFDVariable(string name, FDNumber Value) : + ClAbstractVariable(name), + _value(Value), + _fSet(true), + _desired_value(Value), + _plfdnInitialDomain(0) + { } +#endif + + ClFDVariable(string name, FDNumber Value, const list<FDNumber> &initial_domain) : + ClAbstractVariable(name), + _value(Value), + _fSet(true), + _desired_value(Value), + _plfdnInitialDomain(new list<FDNumber>()) + { + *_plfdnInitialDomain = initial_domain; + } + + virtual bool IsFDVariable() const + { return true; } + + // Return true if this a variable known outside the solver. + // (We need to give such variables a Value after solving is complete.) + virtual bool IsExternal() const + { return true; } + +#ifndef CL_NO_IO + // Prints a semi-descriptive representation to the stream, using the + // name if there is one, and otherwise the hash number of this + // object. + // EXAMPLE + // [x:10.0] -- name = "x", Value = 10.0 + virtual ostream &PrintOn(ostream &xo) const; +#endif + + // Return the current Value I hold. + Number Value() const + { return _value; } + + // Round the Value to an integer and return it + int IntValue() const + { return _value; } + + // change the Value held -- should *not* use this if the variable is + // in a solver -- instead use AddEditVar() and SuggestValue() interface + void SetValue(FDNumber Value) + { _value = Value; } + + // permit overriding in subclasses in case something needs to be + // done when the Value is changed by the solver + // may be called when the Value hasn't actually changed -- just + // means the solver is setting the external variable + virtual void ChangeValue(FDNumber Value) + { _value = Value; } + + virtual bool FIsSet() + { return _fSet; } + + virtual void SetFIsSet(bool f) + { _fSet = f; } + + virtual FDNumber DesiredValue() const + { return _desired_value; } + + virtual const list<FDNumber> *PlfdnDomain() const + { return _plfdnInitialDomain; } + +protected: + + // similar to SetValue -- see caveat above -- made private for now + // since it's probably the wrong thing and is too easy to invoke + FDNumber operator=(FDNumber Value) + { _value = Value; return Value; } + + // Copy constructor left undefined since we want to + // outlaw passing by Value! Will get a link error if you + // try to use within ClFDVariable.c, compile-time error everywhere else + ClFDVariable(const ClFDVariable &); + + FDNumber _value; + + // has the _value been set? Used during solves. + bool _fSet; + + FDNumber _desired_value; + + list<FDNumber> *_plfdnInitialDomain; +}; + +#endif diff --git a/libs/cassowary/cassowary/ClFloatVariable.h b/libs/cassowary/cassowary/ClFloatVariable.h new file mode 100644 index 0000000000..4e58036ab7 --- /dev/null +++ b/libs/cassowary/cassowary/ClFloatVariable.h @@ -0,0 +1,119 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClFloatVariable.h + +#ifndef ClFloatVariable_H +#define ClFloatVariable_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include <cstdio> +#include <map> +#include <string> +#include "Cassowary.h" +#include "ClAbstractVariable.h" + +using std::map; +using std::string; + +class ClFloatVariable : public ClAbstractVariable { +public: + typedef ClAbstractVariable super; + + ClFloatVariable(string name, Number Value = 0.0) : + ClAbstractVariable(name), + _value(Value) + { } + + ClFloatVariable(Number Value = 0.0) : + ClAbstractVariable(""), + _value(Value) + { } + + ClFloatVariable(long number, char *prefix, Number Value = 0.0) : + ClAbstractVariable(number,prefix), + _value(Value) + { } + + virtual bool IsFloatVariable() const + { return true; } + + // Return true if this a dummy variable (used as a marker variable + // for required equality constraints). Such variables aren't + // allowed to enter the basis when pivoting. + virtual bool IsDummy() const + { return false; } + + // Return true if this a variable known outside the solver. + // (We need to give such variables a Value after solving is complete.) + virtual bool IsExternal() const + { return true; } + + // Return true if we can Pivot on this variable. + virtual bool IsPivotable() const + { return false; } + + // Return true if this is a restricted (or slack) variable. Such + // variables are constrained to be non-negative and occur only + // internally to the simplex solver. + virtual bool IsRestricted() const + { return false; } + +#ifndef CL_NO_IO + // Prints a semi-descriptive representation to the stream, using the + // name if there is one, and otherwise the hash number of this + // object. + // EXAMPLE + // [x:10.0] -- name = "x", Value = 10.0 + virtual ostream &PrintOn(ostream &xo) const; +#endif + + // Return the current Value I hold. + Number Value() const + { return _value; } + + // Round the Value to an integer and return it + int IntValue() const + { return int(_value + 0.5); } + + // change the Value held -- should *not* use this if the variable is + // in a solver -- instead use AddEditVar() and SuggestValue() interface + void SetValue(Number Value) + { _value = Value; } + + // permit overriding in subclasses in case something needs to be + // done when the Value is changed by the solver + // may be called when the Value hasn't actually changed -- just + // means the solver is setting the external variable + virtual void ChangeValue(Number Value) + { _value = Value; } + +private: + + // similar to SetValue -- see caveat above -- made private for now + // since it's probably the wrong thing and is too easy to invoke + Number operator=(Number Value) + { _value = Value; return Value; } + + // Copy constructor left undefined since we want to + // outlaw passing by Value! Will get a link error if you + // try to use within ClFloatVariable.c, compile-time error everywhere else + ClFloatVariable(const ClFloatVariable &); + + Number _value; + +}; + + + +#endif diff --git a/libs/cassowary/cassowary/ClLinearConstraint.h b/libs/cassowary/cassowary/ClLinearConstraint.h new file mode 100644 index 0000000000..d657d1d73e --- /dev/null +++ b/libs/cassowary/cassowary/ClLinearConstraint.h @@ -0,0 +1,61 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClLinearConstraint.h + +#ifndef ClLinearConstraint_H +#define ClLinearConstraint_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClConstraint.h" +#include "ClLinearExpression.h" + + +// Add the ClLinearExpression member variable needed for both +// ClLinearEquation and ClLinearInequality +class ClLinearConstraint : public ClConstraint { + private: typedef ClConstraint super; + + public: + + // Constructor + ClLinearConstraint(const ClLinearExpression &cle, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) : + ClConstraint(strength, weight), + _expression(cle) + { } + + virtual ~ClLinearConstraint() {} + + // Return my linear Expression. (For linear equations, this + // constraint represents Expression=0; for linear inequalities it + // represents Expression>=0.) + ClLinearExpression Expression() const + { return _expression; } + + // do not do this if *this is inside a solver + void ChangeConstant(Number constant) + { _expression.Set_constant(constant); } + + protected: + + ClLinearExpression _expression; + + virtual void setExpression( const ClLinearExpression &expr) + { _expression = expr; } + +}; + +#endif diff --git a/libs/cassowary/cassowary/ClLinearEquation.h b/libs/cassowary/cassowary/ClLinearEquation.h new file mode 100644 index 0000000000..a02b51d70b --- /dev/null +++ b/libs/cassowary/cassowary/ClLinearEquation.h @@ -0,0 +1,74 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClLinearEquation.h + +#ifndef ClLinearEquation_H +#define ClLinearEquation_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClLinearConstraint.h" +#include "ClLinearExpression.h" + +class ClStrength; +class ClVariable; + +class ClLinearEquation : public ClLinearConstraint { + private: typedef ClLinearConstraint super; + + public: + //// Constructors + + // ClLinearEquation(expr,...) is expr == 0 + ClLinearEquation(const ClLinearExpression &cle, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) : + ClLinearConstraint(cle,strength, weight) + { } + + // ClLinearEquation(var,expr,...) is var == expr + ClLinearEquation(ClVariable clv, + const ClLinearExpression &cle, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) : + ClLinearConstraint(cle,strength,weight) + { _expression.AddVariable(clv,-1.0); } + + // ClLinearEquation(expr,var,...) is var == expr + ClLinearEquation(const ClLinearExpression &cle, + ClVariable clv, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) : + ClLinearConstraint(cle,strength,weight) + { _expression.AddVariable(clv,-1.0); } + + // ClLinearEquation(expr,expr,...) is expr == expr + ClLinearEquation(const ClLinearExpression &cle1, + const ClLinearExpression &cle2, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) : + ClLinearConstraint(cle1,strength,weight) + { _expression.AddExpression(cle2,-1.0); } + +#ifndef CL_NO_IO + virtual ostream &PrintOn(ostream &xo) const + { super::PrintOn(xo); xo << " = 0 )"; return xo; } +#endif + + virtual bool FIsSatisfied() const + { return (_expression.Evaluate() == 0); } + +}; + +#endif diff --git a/libs/cassowary/cassowary/ClLinearExpression.h b/libs/cassowary/cassowary/ClLinearExpression.h new file mode 100644 index 0000000000..0a1df9c243 --- /dev/null +++ b/libs/cassowary/cassowary/ClLinearExpression.h @@ -0,0 +1,298 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClLinearExpression.h + +#ifndef ClLinearExpression_H +#define ClLinearExpression_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "debug.h" +#include "ClVariable.h" +#include "ClLinearExpression_fwd.h" + +class ClSimplexSolver; +class ClTableau; +class ClSymbolicWeight; + +ClLinearExpression &cleNil(); + +template <class T> +class ClGenericLinearExpression { + public: + typedef std::map<ClVariable,T> ClVarToCoeffMap; + + // convert Number-s into ClLinearExpression-s + ClGenericLinearExpression(T num = 0.0); + + // Convert from ClVariable to a ClLinearExpression + // this replaces ClVariable::asLinearExpression + ClGenericLinearExpression(ClVariable clv, T value = 1.0, T constant = 0.0); + + // copy ctr + ClGenericLinearExpression(const ClGenericLinearExpression<T> &expr) : + _constant(expr._constant), + _terms(expr._terms) + { } + + virtual ~ClGenericLinearExpression(); + + // Return a new linear expression formed by multiplying self by x. + // (Note that this result must be linear.) + ClGenericLinearExpression<T> Times(Number x) const; + + // Return a new linear expression formed by multiplying self by x. + // (Note that this result must be linear.) + ClGenericLinearExpression<T> Times(const ClGenericLinearExpression<T> &expr) const; + + // Return a new linear expression formed by adding x to self. + ClGenericLinearExpression<T> Plus(const ClGenericLinearExpression<T> &expr) const; + + // Return a new linear expression formed by subtracting x from self. + ClGenericLinearExpression<T> Minus(const ClGenericLinearExpression<T> &expr) const; + + // Return a new linear expression formed by dividing self by x. + // (Note that this result must be linear.) + ClGenericLinearExpression<T> Divide(Number x) const; + + + + // Return a new linear expression formed by multiplying self by x. + // (Note that this result must be linear.) + ClGenericLinearExpression<T> *P_times(Number x) const + { return new ClGenericLinearExpression<T>(Times(x)); } + + // Return a new linear expression formed by adding x to self. + ClGenericLinearExpression<T> *P_plus(const ClGenericLinearExpression<T> &expr) const + { return new ClGenericLinearExpression<T>(Plus(expr)); } + + // Return a new linear expression formed by subtracting x from self. + ClGenericLinearExpression<T> *P_minus(const ClGenericLinearExpression<T> &expr) const + { return new ClGenericLinearExpression<T>(Minus(expr)); } + + // Return a new linear expression formed by dividing self by x. + // (Note that this result must be linear.) + ClGenericLinearExpression<T> *P_divide(Number x) const + { return new ClGenericLinearExpression<T>(Divide(x)); } + + // Return a new linear expression formed by dividing self by x. + // (Note that this result must be linear.) + ClGenericLinearExpression<T> Divide(const ClGenericLinearExpression<T> &expr) const; + + // Return a new linear expression (aNumber/this). Since the result + // must be linear, this is permissible only if 'this' is a constant. + ClGenericLinearExpression<T> DivFrom(const ClGenericLinearExpression<T> &expr) const; + + // Return a new linear expression (aNumber-this). + ClGenericLinearExpression<T> SubtractFrom(const ClGenericLinearExpression<T> &expr) const + { return expr.Minus(*this); } + + // Add n*expr to this expression from another expression expr. + ClGenericLinearExpression<T> &AddExpression(const ClGenericLinearExpression<T> &expr, + Number n = 1.0); + + // Add n*expr to this expression from another expression expr. + // Notify the solver if a variable is added or deleted from this + // expression. + ClGenericLinearExpression<T> &AddExpression(const ClGenericLinearExpression<T> &expr, Number n, + ClVariable subject, + ClTableau &solver); + + // Add a term c*v to this expression. If the expression already + // contains a term involving v, Add c to the existing coefficient. + // If the new coefficient is approximately 0, delete v. + ClGenericLinearExpression<T> &AddVariable(ClVariable v, T c = 1.0); + + // Add a term c*v to this expression. If the expression already + // contains a term involving v, Add c to the existing coefficient. + // If the new coefficient is approximately 0, delete v. + ClGenericLinearExpression<T> &setVariable(ClVariable v, T c) + {assert(c != 0.0); _terms[v] = c; return *this; } + + // Add a term c*v to this expression. If the expression already + // contains a term involving v, Add c to the existing coefficient. + // If the new coefficient is approximately 0, delete v. Notify the + // solver if v appears or disappears from this expression. + ClGenericLinearExpression<T> &AddVariable(ClVariable v, T c, + ClVariable subject, + ClTableau &solver); + + // Return a pivotable variable in this expression. (It is an error + // if this expression is constant -- signal ExCLInternalError in + // that case). Return NULL if no pivotable variables + ClVariable AnyPivotableVariable() const; + + // Replace var with a symbolic expression expr that is equal to it. + // If a variable has been added to this expression that wasn't there + // before, or if a variable has been dropped from this expression + // because it now has a coefficient of 0, inform the solver. + // PRECONDITIONS: + // var occurs with a non-Zero coefficient in this expression. + void SubstituteOut(ClVariable v, + const ClGenericLinearExpression<T> &expr, + ClVariable subject, + ClTableau &solver); + + // This linear expression currently represents the equation + // oldSubject=self. Destructively modify it so that it represents + // the equation NewSubject=self. + // + // Precondition: NewSubject currently has a nonzero coefficient in + // this expression. + // + // NOTES + // Suppose this expression is c + a*NewSubject + a1*v1 + ... + an*vn. + // + // Then the current equation is + // oldSubject = c + a*NewSubject + a1*v1 + ... + an*vn. + // The new equation will be + // NewSubject = -c/a + oldSubject/a - (a1/a)*v1 - ... - (an/a)*vn. + // Note that the term involving NewSubject has been dropped. + void ChangeSubject(ClVariable old_subject, + ClVariable new_subject); + + // This linear expression currently represents the equation self=0. Destructively modify it so + // that subject=self represents an equivalent equation. + // + // Precondition: subject must be one of the variables in this expression. + // NOTES + // Suppose this expression is + // c + a*subject + a1*v1 + ... + an*vn + // representing + // c + a*subject + a1*v1 + ... + an*vn = 0 + // The modified expression will be + // subject = -c/a - (a1/a)*v1 - ... - (an/a)*vn + // representing + // subject = -c/a - (a1/a)*v1 - ... - (an/a)*vn + // + // Note that the term involving subject has been dropped. + // Returns the reciprocal, so ChangeSubject can use it, too + T NewSubject(ClVariable subject); + + // Return the value of the linear expression + // given the current assignments of values to contained variables + T Evaluate() const; + + // Return the coefficient corresponding to variable var, i.e., + // the 'ci' corresponding to the 'vi' that var is: + // v1*c1 + v2*c2 + .. + vn*cn + c + T CoefficientFor(ClVariable var) const + { + typename ClVarToCoeffMap::const_iterator it = _terms.find(var); + if (it != _terms.end()) + return (*it).second; + return 0.0; + } + + T Constant() const + { return _constant; } + + void Set_constant(T c) + { _constant = c; } + + const ClVarToCoeffMap &Terms() const + { return _terms; } + + ClVarToCoeffMap &Terms() + { return _terms; } + + void IncrementConstant(T c) + { _constant += c; } + + bool IsConstant() const + { return _terms.size() == 0; } + +#ifndef CL_NO_IO + virtual ostream &PrintOn(ostream &xo) const; + + friend ostream &operator<<(ostream &xo,const ClGenericLinearExpression<T> &cle) + { return cle.PrintOn(xo); } +#endif + + friend ClGenericLinearExpression<T> operator+(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return e1.Plus(e2); } + + friend ClGenericLinearExpression<T> operator-(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return e1.Minus(e2); } + + friend ClGenericLinearExpression<T> operator*(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return e1.Times(e2); } + + + friend ClGenericLinearExpression<T> operator/(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return e1.Divide(e2); } + + // FIXGJB -- this may be wrong -- should test underlying expression for equality + friend bool operator==(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return &e1 == &e2; } + + /// Named versions of the operator functions for ease of + /// wrapping, or expressing using prefix notation + + friend ClGenericLinearExpression<T> Plus(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return e1.Plus(e2); } + + friend ClGenericLinearExpression<T> Minus(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return e1.Minus(e2); } + + friend ClGenericLinearExpression<T> Times(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return e1.Times(e2); } + + + friend ClGenericLinearExpression<T> *Divide(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return new ClGenericLinearExpression<T>(e1.Divide(e2)); } + + friend ClGenericLinearExpression<T> *p_Plus(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return new ClGenericLinearExpression<T>(e1.Plus(e2)); } + + friend ClGenericLinearExpression<T> *p_Minus(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return new ClGenericLinearExpression<T>(e1.Minus(e2)); } + + friend ClGenericLinearExpression<T> *p_Times(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return new ClGenericLinearExpression<T>(e1.Times(e2)); } + + friend ClGenericLinearExpression<T> *p_Divide(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return new ClGenericLinearExpression<T>(e1.Divide(e2)); } + + + // FIXGJB -- this may be wrong -- should test underlying expression for equality + friend bool FEquals(const ClGenericLinearExpression<T> &e1, + const ClGenericLinearExpression<T> &e2) + { return &e1 == &e2; } + + ClGenericLinearExpression<T> &MultiplyMe(T x); + + private: + + T _constant; + ClVarToCoeffMap _terms; + +}; + +typedef ClGenericLinearExpression<Number>::ClVarToCoeffMap ClVarToNumberMap; + +#endif diff --git a/libs/cassowary/cassowary/ClLinearExpression_fwd.h b/libs/cassowary/cassowary/ClLinearExpression_fwd.h new file mode 100644 index 0000000000..99b48557ec --- /dev/null +++ b/libs/cassowary/cassowary/ClLinearExpression_fwd.h @@ -0,0 +1,26 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClLinearExpression.h + +#ifndef ClLinearExpression_fwd_H +#define ClLinearExpression_fwd_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" + +template <class T> class ClGenericLinearExpression; +typedef ClGenericLinearExpression<Number> ClLinearExpression; +typedef ClLinearExpression* PClLinearExpression; + +#endif diff --git a/libs/cassowary/cassowary/ClLinearInequality.h b/libs/cassowary/cassowary/ClLinearInequality.h new file mode 100644 index 0000000000..017c4b819e --- /dev/null +++ b/libs/cassowary/cassowary/ClLinearInequality.h @@ -0,0 +1,167 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClLinearInequality.h + +#ifndef ClLinearInequality_H +#define ClLinearInequality_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "ClConstraint.h" +#include "ClLinearConstraint.h" + +class ClVariable; + +class ClLinearInequality : public ClLinearConstraint { + private: typedef ClLinearConstraint super; + + public: + //// Constructors + // ClLinearInequality(expr,...) is expr >= 0 + ClLinearInequality(const ClLinearExpression &cle, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) : + ClLinearConstraint(cle,strength, weight), + _fStrictInequality(false) + { } + + // ClLinearInequality(var,OP,expr) is var >= expr + ClLinearInequality(const ClVariable clv, + enum ClCnRelation op, + const ClLinearExpression &cle, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) : + ClLinearConstraint( cle, strength, weight), + _fStrictInequality(false) + { + if (op == cnGEQ || op == cnGT) + { + _expression.MultiplyMe(-1.0); + _expression.AddVariable(clv,1.0); + } + else if (op == cnLEQ || op == cnGEQ) + { + _expression.AddVariable(clv,-1.0); + } + else + { + throw ExCLEditMisuse("Cannot use that operator for ClLinearInequality objects"); + } + if (op == cnLT || op == cnGT) { + _fStrictInequality = true; + } + } + +#ifdef FIXGJB_AMBIGUOUS + // ClLinearInequality(expr,OP,var) is var ?<>? expr + ClLinearInequality(const ClLinearExpression &cle, + enum ClCnRelation op, + const ClVariable clv, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) : + ClLinearConstraint( cle, strength, weight), + _fStrictInequality(false) + { + if (op == cnLEQ || op == cnLT) + { + _expression.MultiplyMe(-1.0); + _expression.AddVariable(clv,1.0); + } + else if (op == cnGEQ || op == cnGT) + { + _expression.AddVariable(clv,-1.0); + } + if (op == cnLT || op == cnGT) { + _fStrictInequality = true; + } + } +#endif + + // ClLinearInequality(expr,OP,expr) is expr >= expr + ClLinearInequality(const ClLinearExpression &cle1, + enum ClCnRelation op, + const ClLinearExpression &cle2, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) : + ClLinearConstraint( cle2, strength, weight), + _fStrictInequality(false) + { + if (op == cnGEQ || op == cnGT) + { + _expression.MultiplyMe(-1.0); + _expression.AddExpression(cle1); + } + else if (op == cnLEQ || op == cnLT) + { + _expression.AddExpression(cle1,-1.0); + } + if (op == cnLT || op == cnGT) { + _fStrictInequality = true; + } + } + +#ifdef FIXGJB_AMBIGUOUS + // ClLinearInequality(var,OP,var) is var ?<>? var + ClLinearInequality(const ClVariable clv1, + enum ClCnRelation op, + const ClVariable clv2, + const ClStrength &strength = ClsRequired(), + double weight = 1.0) : + ClLinearConstraint( clv2, strength, weight), + _fStrictInequality(false) + { + if (op == cnGEQ || op == cnGT) + { + _expression.MultiplyMe(-1.0); + _expression.AddVariable(clv1,1.0); + } + else if (op == cnLEQ || op == cnLT) + { + _expression.AddVariable(clv1,-1.0); + } + if (op == cnLT || op == cnGT) { + _fStrictInequality = true; + } + } +#endif + + + // Return true if this is an inequality constraint and + // false if it is an equality constraint. The default is + // that it is not. + virtual bool IsInequality() const + { return true; } + + virtual bool IsStrictInequality() const + { return _fStrictInequality; } + +#ifndef CL_NO_IO + virtual ostream &PrintOn(ostream &xo) const + { super::PrintOn(xo); xo << " >= 0 )"; return xo; } +#endif + + virtual bool FIsSatisfied() const + { + Number v = _expression.Evaluate(); + if (_fStrictInequality) + return (v > 0); + else + return (v >= 0); + } + + private: + + bool _fStrictInequality; +}; + +#endif diff --git a/libs/cassowary/cassowary/ClObjectiveVariable.h b/libs/cassowary/cassowary/ClObjectiveVariable.h new file mode 100644 index 0000000000..664e2d65a4 --- /dev/null +++ b/libs/cassowary/cassowary/ClObjectiveVariable.h @@ -0,0 +1,63 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClObjectiveVariable.h + +#ifndef ClObjectiveVariable_H +#define ClObjectiveVariable_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClAbstractVariable.h" + +class ClTableau; +class ClSimplexSolver; + +class ClObjectiveVariable : public ClAbstractVariable { +protected: + friend class ClTableau; + friend class ClSimplexSolver; + + ClObjectiveVariable(string name = "") : + ClAbstractVariable(name) + { } + + ClObjectiveVariable(long number, char *prefix) : + ClAbstractVariable(number,prefix) + { } + +#ifndef CL_NO_IO + virtual ostream &PrintOn(ostream &xo) const + { + xo << "[" << Name() << ":obj]"; + return xo; + } +#endif + + // We don't need to give such variables a Value after solving is complete. + virtual bool IsExternal() const + { return false; } + + // Return true if we can Pivot on this variable. + virtual bool IsPivotable() const + { return false; } + + // Return true if this is a restricted (or slack) variable. Such + // variables are constrained to be non-negative and occur only + // internally to the simplex solver. + virtual bool IsRestricted() const + { return false; } + +}; + +#endif diff --git a/libs/cassowary/cassowary/ClPoint.h b/libs/cassowary/cassowary/ClPoint.h new file mode 100644 index 0000000000..15139aa73b --- /dev/null +++ b/libs/cassowary/cassowary/ClPoint.h @@ -0,0 +1,74 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClPoint.h + +#ifndef ClPoint_H +#define ClPoint_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClVariable.h" + +// ClPoint is just a convenience class for pairs of +// ClVariables -- often useful for coordinate pairs in 2-space +class ClPoint { + public: + ClPoint(Number x, Number y) + : _clv_x(x), _clv_y(y) + { } + + ClPoint() + { } + + ClVariable X() + { return _clv_x; } + + ClVariable Y() + { return _clv_y; } + + const ClVariable X() const + { return _clv_x; } + + const ClVariable Y() const + { return _clv_y; } + + void SetXY(Number x, Number y) + { _clv_x.SetValue(x); _clv_y.SetValue(y); } + + Number Xvalue() const + { return X().Value(); } + + Number Yvalue() const + { return Y().Value(); } + + private: + ClVariable _clv_x; + ClVariable _clv_y; + +#ifndef CL_NO_IO + friend ostream &operator<<(ostream &xo, const ClPoint &clp); +#endif + +}; + +#ifndef CL_NO_IO +inline ostream & +operator<<(ostream &xo, const ClPoint &clp) +{ + xo << "(" << clp._clv_x << ", " << clp._clv_y << ")"; + return xo; +} +#endif + +#endif diff --git a/libs/cassowary/cassowary/ClReader.h b/libs/cassowary/cassowary/ClReader.h new file mode 100644 index 0000000000..59369d6ac2 --- /dev/null +++ b/libs/cassowary/cassowary/ClReader.h @@ -0,0 +1,117 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClReader.h +// Original implementation contributed by Steve Wolfman +// Subsequently largely revised by Greg J. Badros + +#ifndef CREADER_H +#define CREADER_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include <string> +#include <map> +#include <algorithm> +#include <iostream> +#include "ClErrors.h" +#include "ClVariable.h" +#include "ClStrength.h" +#include "ClLinearExpression_fwd.h" + +using std::string; +using std::istream; + +class ClConstraint; + +class ClVarLookupFunction : public std::unary_function<const string &,ClVariable *> { +public: + virtual ClVariable *operator()(const string &) const { return &clvNil; } +}; + + +// Attempts to read a constraint of input stream in +// Returns constraint (freshly allocated, client responsibility to deallocate) +// if succesful. Otherwise, returns 0. +ClConstraint *PcnParseConstraint(istream &xi, const ClVarLookupFunction &lookup_func, + const ClStrength &strength = ClsRequired()); + +class ClVarLookupInMap : public ClVarLookupFunction { +public: + ClVarLookupInMap(StringToVarMap *pmapVars, bool fAutoCreate) + : _pmapVars(pmapVars), _fAutoCreate(fAutoCreate) { } + + ClVariable *operator()(const string &str) const + { + if (!_pmapVars) + return &clvNil; + StringToVarMap &_mapVars = *_pmapVars; + StringToVarMap::iterator it = _mapVars.find(str); + if (it != _mapVars.end()) { + return &it->second; + } else if (_fAutoCreate) { + // save the old symbol table, if any + StringToVarMap *pmapOld = ClVariable::VarMap(); + // and set it to this one temporarily + ClVariable::SetVarMap(&_mapVars); + ClVariable *pclv = new ClVariable(str); + // now switch it back + ClVariable::SetVarMap(pmapOld); + return pclv; + } else { + return &clvNil; + } + } +private: + StringToVarMap *_pmapVars; + bool _fAutoCreate; +}; + + +/* the "yyerror" function */ +void clerror(const char *sz); + +struct ClParseData { + ClParseData(istream &xi, const ClVarLookupFunction &lookup_func) + : _xi(xi), _lookup_func(lookup_func) { } + + ClConstraint *Pcn() { return _pcn; } + + ClVarSet _readOnlyVarsSoFar; + + istream & _xi; + ClConstraint * _pcn; + const ClVarLookupFunction &_lookup_func; +}; + + +inline +const ClStrength +&ClsFromSz(const char *sz) +{ + const ClStrength *pcls = &ClsRequired(); + double n1, n2, n3; + if (strcmp("required",sz) == 0) + ; /* initialized to ClsRequired, above */ + else if (strcasecmp("strong",sz) == 0) { pcls = &ClsStrong(); } + else if (strcasecmp("medium",sz) == 0) { pcls = &ClsMedium(); } + else if (strcasecmp("weak",sz) == 0) { pcls = &ClsWeak(); } + else if (sscanf(sz,"(%lf,%lf,%lf)",&n1,&n2,&n3) == 3) { + pcls = new ClStrength("parsed",n1,n2,n3); + } else { + throw ExCLParseErrorMisc("Error parsing strength"); + } + return *pcls; +} + + +#endif diff --git a/libs/cassowary/cassowary/ClSimplexSolver.h b/libs/cassowary/cassowary/ClSimplexSolver.h new file mode 100644 index 0000000000..c187992728 --- /dev/null +++ b/libs/cassowary/cassowary/ClSimplexSolver.h @@ -0,0 +1,588 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClSimplexSolver.h + +#ifndef ClSimplexSolver_H +#define ClSimplexSolver_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include <stack> +#include <list> +#include <iostream> +#include "Cassowary.h" +#include "ClSolver.h" +#include "ClTableau.h" +#include "ClLinearInequality.h" +#include "ClStrength.h" +#include "ClStayConstraint.h" +#include "ClEditConstraint.h" +#include "ClSlackVariable.h" +#include "ClObjectiveVariable.h" +#include "ClErrors.h" +#include "ClTypedefs.h" + +using std::list; +using std::stack; +using std::ostream; + +class ClVariable; +class ClPoint; +class ExCLRequiredFailureWithExplanation; + + +// ClSimplexSolver encapsulates the solving behaviour +// of the cassowary algorithm +class ClSimplexSolver : public ClSolver, public ClTableau { + protected: + class ClEditInfo; + typedef list<ClEditInfo *> ClEditInfoList; + + ClEditInfo *PEditInfoFromClv(ClVariable clv) { + ClEditInfoList::iterator it = _editInfoList.begin(); + for (; it != _editInfoList.end(); ++it) { + ClEditInfo *pei = (*it); + if (pei->_clv == clv) + return pei; + } + return 0; + } + + public: + + // Constructor + ClSimplexSolver() : + ClSolver(), + _objective(ClVariable(new ClObjectiveVariable("Z"))), + _slackCounter(0), + _artificialCounter(0), +#ifdef CL_FIND_LEAK + _cArtificialVarsDeleted(0), +#endif + _dummyCounter(0), + _epsilon(1e-8), + _fResetStayConstantsAutomatically(true), + _fNeedsSolving(false), + _fExplainFailure(false), + _pfnResolveCallback(0), + _pfnCnSatCallback(0) + { + _rows[_objective] = new ClLinearExpression(); + // start out with no edit variables + _stkCedcns.push(0); +#ifdef CL_TRACE + std::cerr << "objective row new@ " << _rows[_objective] << std::endl; +#endif + } + + virtual ~ClSimplexSolver(); + + // Add constraints so that lower<=var<=upper. (nil means no bound.) + ClSimplexSolver &AddLowerBound(ClVariable v, Number lower) + { + ClLinearInequality *pcn = new ClLinearInequality(ClLinearExpression(v - lower)); + return AddConstraint(pcn); + } + ClSimplexSolver &AddUpperBound(ClVariable v, Number upper) + { + ClLinearInequality *pcn = new ClLinearInequality(ClLinearExpression(upper - v)); + return AddConstraint(pcn); + } + ClSimplexSolver &AddBounds(ClVariable v, Number lower, Number upper) + { AddLowerBound(v,lower); AddUpperBound(v,upper); return *this; } + + // Add the constraint cn to the tableau + ClSimplexSolver &AddConstraint(ClConstraint *const pcn); + +#ifndef CL_NO_DEPRECATED + // Deprecated! --02/19/99 gjb + ClSimplexSolver &AddConstraint(ClConstraint &cn) + { return AddConstraint(&cn); } +#endif + + // Add an edit constraint for "v" with given strength + ClSimplexSolver &AddEditVar(const ClVariable v, const ClStrength &strength = ClsStrong(), + double weight = 1.0 ) + { + ClEditConstraint *pedit = new ClEditConstraint(v, strength, weight); + return AddConstraint(pedit); + } + + ClSimplexSolver &RemoveEditVar(ClVariable v) + { + ClEditInfo *pcei = PEditInfoFromClv(v); + if (!pcei) { + throw ExCLEditMisuse("Removing edit variable that was not found"); + } + ClConstraint *pcnEdit = pcei->_pconstraint; + RemoveConstraint(pcnEdit); + delete pcnEdit; + return *this; + } + + // BeginEdit() should be called before sending + // Resolve() messages, after adding the appropriate edit variables + ClSimplexSolver &BeginEdit() + { + if (_editInfoList.size() == 0) { + throw ExCLEditMisuse("BeginEdit called, but no edit variable"); + } + // may later want to do more in here + _infeasibleRows.clear(); + ResetStayConstants(); + _stkCedcns.push(_editInfoList.size()); + return *this; + } + + // EndEdit should be called after editing has finished + // for now, it just removes edit variables added from before the last BeginEdit + ClSimplexSolver &EndEdit() + { + if (_editInfoList.size() == 0) + throw ExCLEditMisuse("EndEdit called but no edit variables"); + Resolve(); + _stkCedcns.pop(); + RemoveEditVarsTo(_stkCedcns.top()); + // may later want to do more in here + return *this; + } + + // RemoveAllEditVars() just eliminates all the edit constraints + // that were added + ClSimplexSolver &RemoveAllEditVars() { RemoveEditVarsTo(0); return *this; } + + // remove the last added edit vars to leave only n edit vars left + ClSimplexSolver &RemoveEditVarsTo(unsigned int n); + + int numEditVars() const + { return _editInfoList.size(); } + + // Add weak stays to the x and y parts of each point. These have + // increasing weights so that the solver will try to satisfy the x + // and y stays on the same point, rather than the x stay on one and + // the y stay on another. + ClSimplexSolver &AddPointStays(const vector<const ClPoint *> &listOfPoints, + const ClStrength &strength = ClsWeak()); + + ClSimplexSolver &AddPointStay(const ClVariable vx, const ClVariable vy, + const ClStrength &strength = ClsWeak(), + double weight = 1.0) + { AddStay(vx,strength,weight); AddStay(vy,strength,weight); return *this; } + + ClSimplexSolver &AddPointStay(const ClPoint &clp, + const ClStrength &strength = ClsWeak(), + double weight = 1.0); + + + // Add a stay of the given strength (default to weak) of v to the tableau + ClSimplexSolver &AddStay(const ClVariable v, + const ClStrength &strength = ClsWeak(), double weight = 1.0 ) + { + ClStayConstraint *pcn = new ClStayConstraint(v,strength,weight); + return AddConstraint(pcn); + } + + // Remove the constraint cn from the tableau + // Also remove any error variable associated with cn + ClSimplexSolver &RemoveConstraint(ClConstraint *const pcn) + { RemoveConstraintInternal(pcn); pcn->removedFrom(*this); return *this; } + +#ifndef CL_NO_DEPRECATED + // Deprecated! --02/19/99 gjb + ClSimplexSolver &RemoveConstraint(ClConstraint &cn) + { return RemoveConstraint(&cn); } +#endif + + + // Re-initialize this solver from the original constraints, thus + // getting rid of any accumulated numerical problems. (Actually, we + // haven't definitely observed any such problems yet) + void Reset(); + + // Re-solve the current collection of constraints, given the new + // values for the edit variables that have already been + // suggested (see SuggestValue() method) + // This is not guaranteed to work if you remove an edit constraint + // from the middle of the edit constraints you added + // (e.g., edit A, edit B, edit C, remove B -> this will fail!) + // DEPRECATED + void Resolve(); + + // Re-solve the current collection of constraints for new values for + // the constants of the edit variables. + // This is implemented in terms of SuggestValue-s, and is + // less efficient than that more natural interface + void Resolve(const vector<Number> &newEditConstants); + + // Convenience function for Resolve-s of two variables + void Resolve(Number x, Number y) + { + vector<Number> vals; + vals.push_back(x); + vals.push_back(y); + Resolve(vals); + } + + // Suggest a new value for an edit variable + // the variable needs to be added as an edit variable + // and BeginEdit() needs to be called before this is called. + // The tableau will not be solved completely until + // after Resolve() has been called + ClSimplexSolver &SuggestValue(ClVariable v, Number x); + + // Set and check whether or not the solver will attempt to compile + // an explanation of failure when a required constraint conflicts + // with another required constraint + ClSimplexSolver &SetExplaining(bool f) + { _fExplainFailure = f; return *this; } + + bool FIsExplaining() const + { return _fExplainFailure; } + + // If autosolving has been turned off, client code needs + // to explicitly call solve() before accessing variables + // values + ClSimplexSolver &Solve() + { +#ifdef CL_SOLVER_CHECK_INTEGRITY + AssertValid(); +#endif + if (_fNeedsSolving) + { + Optimize(_objective); + SetExternalVariables(); +#ifdef CL_TRACE_VERBOSE + std::cerr << "Manual solve actually solving." << std::endl; +#endif + } + return *this; + } + + ClSimplexSolver &SetEditedValue(ClVariable v, double n) + { + if (!FContainsVariable(v)) + { + ChangeClv(v,n); + return *this; + } + + if (!ClApprox(n, v.Value())) + { + AddEditVar(v); + BeginEdit(); + SuggestValue(v,n); + EndEdit(); + } + return *this; + } + + // Solver contains the variable if it's in either the columns + // list or the rows list + bool FContainsVariable(const ClVariable v) + { return ColumnsHasKey(v) || RowExpression(v); } + + ClSimplexSolver &AddVar(const ClVariable v) + { if (!FContainsVariable(v)) + { + AddStay(v); +#ifdef CL_TRACE + std::cerr << "added initial stay on " << v << std::endl; +#endif + } + return *this; } + + typedef void (*PfnResolveCallback)(ClSimplexSolver *psolver); + + void SetResolveCallback(PfnResolveCallback pfn) + { _pfnResolveCallback = pfn; } + + typedef void (*PfnCnSatCallback)(ClSimplexSolver *psolver, + ClConstraint *pcn, bool fSatisfied); + + void SetCnSatCallback(PfnCnSatCallback pfn) + { _pfnCnSatCallback = pfn; } + +#ifndef CL_NO_IO + friend ostream &operator<<(ostream &xo, const ClSimplexSolver &tableau); + + ostream &PrintOn(ostream &xo) const; + + ostream &PrintInternalInfo(ostream &xo) const; + + ostream &PrintOnVerbose(ostream &xo) const + { PrintOn(xo); PrintInternalInfo(xo); xo << std::endl; return xo; } + +#endif + + const ClConstraintToVarMap &ConstraintMap() const + { return _markerVars; } + + const ClVarToConstraintMap &MarkerMap() const + { return _constraintsMarked; } + + bool FIsConstraintSatisfied(const ClConstraint *const pcn) const; + + // DEPRECATED + bool FIsConstraintSatisfied(const ClConstraint &pcn) const + { return FIsConstraintSatisfied(&pcn); } + + // re-set all the external variables to their current values + // most importantly, this re-calls all the ChangeClv callbacks + // (which might be used to copy the ClVariable's value to another + // variable) + void UpdateExternalVariables() + { SetExternalVariables(); } + + // A. Beurive' Tue Jul 6 17:05:39 CEST 1999 + void ChangeStrengthAndWeight(ClConstraint *pcn, const ClStrength &strength, double weight); + void ChangeStrength(ClConstraint *pcn, const ClStrength &strength); + void ChangeWeight(ClConstraint *pcn, double weight); + // void DisplayObjective(); + + // Each of the non-required stays will be represented by an equation + // of the form + // v = c + eplus - eminus + // where v is the variable with the stay, c is the previous value of + // v, and eplus and eminus are slack variables that hold the error + // in satisfying the stay constraint. We are about to change + // something, and we want to fix the constants in the equations + // representing the stays. If both eplus and eminus are nonbasic + // they have value 0 in the current solution, meaning the previous + // stay was exactly satisfied. In this case nothing needs to be + // changed. Otherwise one of them is basic, and the other must + // occur only in the Expression for that basic error variable. + // Reset the Constant in this Expression to 0. + void ResetStayConstants(); + + ClSimplexSolver &SetAutoResetStayConstants(bool f) + { _fResetStayConstantsAutomatically = f; if (f) ResetStayConstants(); return *this; } + + bool FIsAutoResetStayConstants() const + { return _fResetStayConstantsAutomatically; } + + protected: + + // ClEditInfo is a privately-used class + // that just wraps a constraint, its positive and negative + // error variables, and its prior edit Constant. + // It is used as values in _editInfoList, and replaces + // the parallel vectors of error variables and previous edit + // constants from the smalltalk version of the code. + class ClEditInfo { + friend class ClSimplexSolver; + public: + + // These instances own none of the pointers; + // the tableau row (the Expression) owns the peplus, peminus, + // and AddEditVar/RemoveEditVar pair or the client code owns + // the constraint object + ClEditInfo(ClVariable clv, + ClEditConstraint *pconstraint, + ClVariable eplus, ClVariable eminus, + Number prevEditConstant) + :_clv(clv), + _pconstraint(pconstraint), + _clvEditPlus(eplus), _clvEditMinus(eminus), + _prevEditConstant(prevEditConstant) + { } + + ~ClEditInfo() + { } + + ostream &PrintOn(ostream &xo) const + { xo << _clv << " -> [" << _clvEditPlus << ", " << _clvEditMinus << "](" + << _prevEditConstant << ")@" << " -- " + << *_pconstraint; + return xo; } + + friend ostream &operator<<(ostream &xo, const ClEditInfo &cei) + { return cei.PrintOn(xo); } + + private: + ClVariable _clv; + ClConstraint *_pconstraint; + ClVariable _clvEditPlus; + ClVariable _clvEditMinus; + Number _prevEditConstant; + }; + + // Add the constraint expr=0 to the inequality tableau using an + // artificial variable. To do this, create an artificial variable + // av and Add av=expr to the inequality tableau, then make av be 0. + // (Raise an exception if we can't attain av=0.) + // (Raise an exception if we can't attain av=0.) If the Add fails, + // prepare an explanation in e that describes why it failed (note + // that an empty explanation is considered to mean the explanation + // encompasses all active constraints. + bool AddWithArtificialVariable(ClLinearExpression &pexpr, + ExCLRequiredFailureWithExplanation &e); + + // Using the given equation (av = cle) build an explanation which + // implicates all constraints used to construct the equation. That + // is, everything for which the variables in the equation are markers. + // Thanks to Steve Wolfman for the implementation of the explanation feature + void BuildExplanation(ExCLRequiredFailureWithExplanation & e, + ClVariable av, + const ClLinearExpression * pcle); + + // We are trying to Add the constraint expr=0 to the appropriate + // tableau. Try to Add expr directly to the tableax without + // creating an artificial variable. Return true if successful and + // false if not. + bool TryAddingDirectly(ClLinearExpression &pexpr); + + // We are trying to Add the constraint expr=0 to the tableaux. Try + // to choose a subject (a variable to become basic) from among the + // current variables in expr. If expr contains any unrestricted + // variables, then we must choose an unrestricted variable as the + // subject. Also, if the subject is new to the solver we won't have + // to do any substitutions, so we prefer new variables to ones that + // are currently noted as parametric. If expr contains only + // restricted variables, if there is a restricted variable with a + // negative coefficient that is new to the solver we can make that + // the subject. Otherwise we can't find a subject, so return nil. + // (In this last case we have to Add an artificial variable and use + // that variable as the subject -- this is done outside this method + // though.) + // + // Note: in checking for variables that are new to the solver, we + // ignore whether a variable occurs in the objective function, since + // new slack variables are added to the objective function by + // 'NewExpression:', which is called before this method. + ClVariable ChooseSubject(ClLinearExpression &pexpr); + + // Each of the non-required edits will be represented by an equation + // of the form + // v = c + eplus - eminus + // where v is the variable with the edit, c is the previous edit + // value, and eplus and eminus are slack variables that hold the + // error in satisfying the edit constraint. We are about to change + // something, and we want to fix the constants in the equations + // representing the edit constraints. If one of eplus and eminus is + // basic, the other must occur only in the Expression for that basic + // error variable. (They can't both be basic.) Fix the Constant in + // this Expression. Otherwise they are both nonbasic. Find all of + // the expressions in which they occur, and fix the constants in + // those. See the UIST paper for details. + // (This comment was for resetEditConstants(), but that is now + // gone since it was part of the screwey vector-based interface + // to resolveing. --02/15/99 gjb) + void DeltaEditConstant(Number delta, ClVariable pv1, ClVariable pv2); + + // We have set new values for the constants in the edit constraints. + // Re-Optimize using the dual simplex algorithm. + void DualOptimize(); + + // Make a new linear Expression representing the constraint cn, + // replacing any basic variables with their defining expressions. + // Normalize if necessary so that the Constant is non-negative. If + // the constraint is non-required give its error variables an + // appropriate weight in the objective function. + ClLinearExpression *NewExpression(const ClConstraint *pcn, + /* output to */ + ClVariable &clvEplus, + ClVariable &clvEminus, + Number &prevEConstant); + + // Minimize the value of the objective. (The tableau should already + // be feasible.) + void Optimize(ClVariable zVar); + + // Do a Pivot. Move entryVar into the basis (i.e. make it a basic variable), + // and move exitVar out of the basis (i.e., make it a parametric variable) + void Pivot(ClVariable entryVar, ClVariable exitVar); + + // Set the external variables known to this solver to their appropriate values. + // Set each external basic variable to its value, and set each + // external parametric variable to 0. (It isn't clear that we will + // ever have external parametric variables -- every external + // variable should either have a stay on it, or have an equation + // that defines it in terms of other external variables that do have + // stays. For the moment I'll put this in though.) Variables that + // are internal to the solver don't actually store values -- their + // values are just implicit in the tableu -- so we don't need to set + // them. + void SetExternalVariables(); + + // this gets called by RemoveConstraint and by AddConstraint when the + // contraint we're trying to Add is inconsistent + ClSimplexSolver &RemoveConstraintInternal(const ClConstraint *const pcn); + + void ChangeClv(ClVariable clv, Number n) { + clv.ChangeValue(n); + if (_pfnChangeClvCallback) + _pfnChangeClvCallback(&clv,this); + } + + /// instance variables + + // the arrays of positive and negative error vars for the stay constraints + // (need both positive and negative since they have only non-negative values) + ClVarVector _stayMinusErrorVars; + ClVarVector _stayPlusErrorVars; + + // give error variables for a non required constraint, + // maps to ClSlackVariable-s + ClConstraintToVarSetMap _errorVars; + + // Return a lookup table giving the marker variable for each + // constraint (used when deleting a constraint). + ClConstraintToVarMap _markerVars; + + // Reverse of the above-- a lookup table giving the constraint + // for each marker variable (used when building failure explanations) + ClVarToConstraintMap _constraintsMarked; + + ClVariable _objective; + + // Map edit variables to their constraints, errors, and prior + // values + ClEditInfoList _editInfoList; + + int _slackCounter; + int _artificialCounter; +#ifdef CL_FIND_LEAK + int _cArtificialVarsDeleted; +#endif + int _dummyCounter; + const double _epsilon; + + bool _fResetStayConstantsAutomatically; + bool _fNeedsSolving; + bool _fExplainFailure; + + PfnResolveCallback _pfnResolveCallback; + PfnCnSatCallback _pfnCnSatCallback; + + // C-style extension mechanism so I + // don't have to wrap ScwmClSolver separately + void *_pv; + + // a stack of the number of edit constraints + // that existed at the prior BeginEdit. + // an EndEdit needs to pop off the top value, + // then remove constraints to get down + // to the # of constraints as in _stkCedcns.top() + stack<int> _stkCedcns; + + +#ifndef CL_NO_IO + +friend ostream &PrintTo(ostream &xo, const ClSimplexSolver::ClEditInfoList &listPEditInfo); +friend ostream &operator<<(ostream &xo, const ClSimplexSolver::ClEditInfoList &listPEditInfo); + +#endif + +}; + +#endif // ClSimplexSolver_H diff --git a/libs/cassowary/cassowary/ClSlackVariable.h b/libs/cassowary/cassowary/ClSlackVariable.h new file mode 100644 index 0000000000..ca116702e9 --- /dev/null +++ b/libs/cassowary/cassowary/ClSlackVariable.h @@ -0,0 +1,75 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClSlackVariable.h + +#ifndef ClSlackVariable_H +#define ClSlackVariable_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClAbstractVariable.h" + +class ClTableau; +class ClSimplexSolver; + + +class ClSlackVariable : public ClAbstractVariable { +public: +#ifdef CL_FIND_LEAK + ~ClSlackVariable() { --cSlackVariables; }; + + static long cSlackVariables; +#endif + +protected: + friend class ClTableau; + friend class ClSimplexSolver; + + ClSlackVariable(string Name = "") : + ClAbstractVariable(Name) + { +#ifdef CL_FIND_LEAK + ++cSlackVariables; +#endif + } + + ClSlackVariable(long number, char *prefix) : + ClAbstractVariable(number,prefix) + { +#ifdef CL_FIND_LEAK + ++cSlackVariables; +#endif + } + +#ifndef CL_NO_IO + virtual ostream &PrintOn(ostream &xo) const + { + xo << "[" << Name() << ":slack]"; + return xo; + } +#endif + + virtual bool IsExternal() const + { return false; } + + virtual bool IsPivotable() const + { return true; } + + virtual bool IsRestricted() const + { return true; } + +}; + + +#endif diff --git a/libs/cassowary/cassowary/ClSolver.h b/libs/cassowary/cassowary/ClSolver.h new file mode 100644 index 0000000000..16e798d491 --- /dev/null +++ b/libs/cassowary/cassowary/ClSolver.h @@ -0,0 +1,167 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClSolver.h + +#ifndef ClSolver_H +#define ClSolver_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClErrors.h" +#include "ClTypedefs.h" +#include <list> +#include <iostream> + +using std::list; +using std::ostream; + +class ClVariable; + +// ClSolver is an abstract base class +class ClSolver { + public: + + ClSolver() : _pv(0), _fAutosolve(true), _pfnChangeClvCallback(0) { } + + virtual ~ClSolver() + { } + + // Add the constraint cn to the solver + virtual ClSolver &AddConstraint(ClConstraint *const pcn) = 0; + + // Remove the constraint cn from the solver + virtual ClSolver &RemoveConstraint(ClConstraint *const pcn) = 0; + + // Same as above, but returns false if the constraint cannot be solved + // (i.e., the resulting system would be unsatisfiable) + // The above function "AddConstraint" throws an exception in that case + // which may be inconvenient + virtual bool AddConstraintNoException(ClConstraint *const pcn) + { + try { + AddConstraint(pcn); + return true; + } + catch (const ExCLRequiredFailure &e) + { return false; } + catch (const ExCLTooDifficult &e) + { return false; } + } + +#ifndef CL_NO_DEPRECATED + // Deprecated --02/22/99 gjb + bool AddConstraintNoException(ClConstraint &cn) + { return AddConstraintNoException(&cn); } +#endif + + virtual bool RemoveConstraintNoException(ClConstraint *const pcn) + { + try { + RemoveConstraint(pcn); + return true; + } + catch (const ExCLConstraintNotFound &e) + { return false; } + } + +#ifndef CL_NO_DEPRECATED + // Deprecated --02/22/99 gjb + bool RemoveConstraintNoException(ClConstraint &cn) + { return RemoveConstraintNoException(&cn); } +#endif + + + virtual ClSolver &Solve() + { assert(false); return *this; } + + virtual bool SolveNoException() + { + try { + Solve(); + return true; + } + catch (const ExCLTooDifficult &e) + { return false; } + catch (const ExCLRequiredFailure &e) + { return false; } + } + + + virtual void Resolve() + { assert(false); } + + void SetPv(void *pv) + { _pv = pv; } + + void *Pv() const + { return _pv; } + + typedef void (*PfnChangeClvCallback)(ClVariable *pclv, ClSolver *psolver); + + void SetChangeClvCallback(PfnChangeClvCallback pfn) + { _pfnChangeClvCallback = pfn; } + + // Control whether optimization and setting of external variables + // is done automatically or not. By default it is done + // automatically and solve() never needs to be explicitly + // called by client code; if SetAutosolve is put to false, + // then solve() needs to be invoked explicitly before using + // variables' values + // (Turning off autosolve while adding lots and lots of + // constraints [ala the addDel test in ClTests] saved + // about 20% in runtime, from 68sec to 54sec for 900 constraints, + // with 126 failed adds) + ClSolver &SetAutosolve(bool f) + { _fAutosolve = f; if (f) Solve(); return *this; } + + // Tell whether we are autosolving + bool FIsAutosolving() const + { return _fAutosolve; } + + +#ifndef CL_NO_IO + friend ostream &operator<<(ostream &xo, const ClSolver &solver); + + virtual ostream &PrintOn(ostream &xo) const = 0; + +#endif + + protected: + + // C-style extension mechanism so I + // don't have to wrap ScwmClSolver separately + void *_pv; + + bool _fAutosolve; + + PfnChangeClvCallback _pfnChangeClvCallback; +}; + + +#ifndef CL_NO_IO +ostream &PrintTo(ostream &xo, const ClVarVector &varlist); +ostream &operator<<(ostream &xo, const ClVarVector &varlist); + +ostream &PrintTo(ostream &xo, const ClConstraintToVarSetMap &mapCnToVarSet); +ostream &operator<<(ostream &xo, const ClConstraintToVarSetMap &mapCnToVarSet); + +ostream &PrintTo(ostream &xo, const ClConstraintSet &setCn); +ostream &operator<<(ostream &xo, const ClConstraintSet &setCn); + +ostream &PrintTo(ostream &xo, const list<FDNumber> &listFDN); +ostream &operator<<(ostream &xo, const list<FDNumber> &listFDN); + +#endif + +#endif diff --git a/libs/cassowary/cassowary/ClStayConstraint.h b/libs/cassowary/cassowary/ClStayConstraint.h new file mode 100644 index 0000000000..f009731b09 --- /dev/null +++ b/libs/cassowary/cassowary/ClStayConstraint.h @@ -0,0 +1,43 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClStayConstraint.h + +#ifndef ClStayConstraint_H +#define ClStayConstraint_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClEditOrStayConstraint.h" + +class ClStayConstraint : public ClEditOrStayConstraint { + typedef ClEditOrStayConstraint super; + public: + + ClStayConstraint(const ClVariable var, + const ClStrength &strength = ClsWeak(), double weight = 1.0 ) : + ClEditOrStayConstraint(var,strength,weight) + { } + + virtual bool isStayConstraint() const + { return true; } + +#ifndef CL_NO_IO + virtual ostream &PrintOn(ostream &xo) const + { super::PrintOn(xo); return xo << " STAY)"; } +#endif + + private: +}; + +#endif diff --git a/libs/cassowary/cassowary/ClStrength.h b/libs/cassowary/cassowary/ClStrength.h new file mode 100644 index 0000000000..644c04cb5f --- /dev/null +++ b/libs/cassowary/cassowary/ClStrength.h @@ -0,0 +1,91 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClStrength.h + +#ifndef ClStrength_H +#define ClStrength_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include <string> + +#include "Cassowary.h" +#include "ClSymbolicWeight.h" + +using std::string; + +class ClStrength; + +const ClStrength &ClsRequired(); +const ClStrength &ClsStrong(); +const ClStrength &ClsMedium(); +const ClStrength &ClsWeak(); + +class ClStrength { + public: + + ClStrength(const string &Name, const ClSymbolicWeight &symbolicWeight) : + _name(Name), _symbolicWeight(symbolicWeight) + { } + + // special case for when nLevels = 3, should assert nLevels() == 3 + ClStrength(const string &Name, double w1, double w2, double w3); + + virtual ~ClStrength() + { } + + virtual bool IsRequired() const + { return (_symbolicWeight == ClsRequired()._symbolicWeight); } + +#ifndef CL_NO_IO + virtual ostream &PrintOn(ostream &xo) const + { + xo << Name(); + if (!IsRequired()) + xo << ":" << symbolicWeight(); + return xo; + } + + friend ostream& operator<<(ostream &xos, const ClStrength &Cls) + { Cls.PrintOn(xos); return xos; } + +#endif + + virtual const ClSymbolicWeight &symbolicWeight() const + { return _symbolicWeight; } + + void SetPv(void *pv) + { _pv = pv; } + + void *Pv() const + { return _pv; } + + private: + string Name() const + { return _name; } + + void SetName(string Name) + { _name = Name; } + + void SetSymbolicWeight(const ClSymbolicWeight &symbolicWeight) + { _symbolicWeight = symbolicWeight; } + + // instance variables + string _name; + ClSymbolicWeight _symbolicWeight; + + void *_pv; + +}; + +#endif diff --git a/libs/cassowary/cassowary/ClSymbolicWeight.h b/libs/cassowary/cassowary/ClSymbolicWeight.h new file mode 100644 index 0000000000..1c0339c887 --- /dev/null +++ b/libs/cassowary/cassowary/ClSymbolicWeight.h @@ -0,0 +1,197 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClSymbolicWeight.h + +#ifndef ClSymbolicWeight_H +#define ClSymbolicWeight_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClErrors.h" +#include <vector> +#include <iostream> + +using std::vector; +using std::ostream; + +class ClSymbolicWeight { + public: + ClSymbolicWeight(unsigned int CLevels = 3, Number value = 0.0); + + ClSymbolicWeight(Number w1, Number w2, Number w3); + + ClSymbolicWeight(const vector<Number> &weights); + + static ClSymbolicWeight &Zero(); + + ClSymbolicWeight &negated(); + + ClSymbolicWeight &MultiplyMe(Number n); + + ClSymbolicWeight Times(Number n) const + { ClSymbolicWeight cl = *this; cl.MultiplyMe(n); return cl; } + + ClSymbolicWeight DivideBy(Number n) const; + + ClSymbolicWeight &addtoMe(const ClSymbolicWeight &cl); + + ClSymbolicWeight Add(const ClSymbolicWeight &cl) const + { ClSymbolicWeight clRet = *this; clRet.addtoMe(cl); return clRet; } + + ClSymbolicWeight Subtract(const ClSymbolicWeight &cl) const; + + ClSymbolicWeight operator*(const Number &n) const + { return Times(n); } + + ClSymbolicWeight operator/(const Number &n) const + { return DivideBy(n); } + + // FIXGJB: can we express this statically? + ClSymbolicWeight operator*(ClSymbolicWeight &w) const + { throw ExCLInternalError("Multiplication of symbolic weights encountered"); + return w; } + ClSymbolicWeight &operator*=(ClSymbolicWeight &w) + { throw ExCLInternalError("Multiplicative assignment of symbolic weights encountered"); + return w; } + + // FIXGJB: can we express this statically? + ClSymbolicWeight operator-() const + { throw ExCLInternalError("Can not negate a symbolic weight"); + return ClSymbolicWeight::Zero(); } + + friend ClSymbolicWeight ReciprocalOf(const ClSymbolicWeight &); + + ClSymbolicWeight &operator*=(const Number &n) + { return MultiplyMe(n); } + + ClSymbolicWeight operator+(const ClSymbolicWeight &cl) const + { return Add(cl); } + + ClSymbolicWeight operator+=(const ClSymbolicWeight &cl) + { return addtoMe(cl); } + + ClSymbolicWeight operator*(const Number &n) + { ClSymbolicWeight answer(*this); + answer *= n; + return answer; } + + bool lessThan(const ClSymbolicWeight &cl) const; + bool lessThanOrEqual(const ClSymbolicWeight &cl) const; + bool equal(const ClSymbolicWeight &cl) const; + bool greaterThan(const ClSymbolicWeight &cl) const; + bool greaterThanOrEqual(const ClSymbolicWeight &cl) const; + bool isNegative() const; + + friend bool operator==(const ClSymbolicWeight &cl1, const ClSymbolicWeight &cl2) + { return cl1.equal(cl2); } + + friend bool operator!=(const ClSymbolicWeight &cl1, const ClSymbolicWeight &cl2) + { return !(cl1 == cl2); } + + friend bool operator<(const ClSymbolicWeight &cl1, const ClSymbolicWeight &cl2) + { return cl1.lessThan(cl2); } + + friend bool operator>(const ClSymbolicWeight &cl1, const ClSymbolicWeight &cl2) + { return (cl2 < cl1); } + + // function.h provides operator>, >=, <= from operator< + + double AsDouble() const + { + vector<Number>::const_reverse_iterator i = _values.rbegin(); + Number sum = 0; + Number factor = 1; + // A. Beurive' Wed Jul 7 11:07:47 CEST 1999 + Number multiplier = 1000000; + for ( ; i != _values.rend(); ++i) + { + sum += *i * factor; + factor *= multiplier; + } + return sum; + } + +#ifndef CL_NO_IO + ostream &PrintOn(ostream &xo) const + { + vector<Number>::const_iterator i = _values.begin(); + if (i == _values.end()) + return xo; + + xo << *i; + for (++i; i != _values.end(); ++i) + { + xo << "," << *i; + } + return xo; + } + + // FIXGJB: use a template function to generate these automatically + friend ostream& operator<<(ostream &xos, const ClSymbolicWeight &clsw) + { clsw.PrintOn(xos); return xos; } +#endif + + int CLevels() const + { return _values.size(); } + + friend bool ClApprox(const ClSymbolicWeight &cl, Number n); + friend bool ClApprox(const ClSymbolicWeight &cl1, const ClSymbolicWeight &cl2); + + private: + vector<Number> _values; + + void push_back(Number d) + { _values.push_back(d); } + +}; + +inline bool ClApprox(const ClSymbolicWeight &cl, Number n) +{ + vector<Number>::const_iterator it = cl._values.begin(); + if (!ClApprox(*it,n)) + return false; + + ++it; + for (; it != cl._values.end(); ++it) + { + if (!ClApprox(*it,0)) + return false; + } + + return true; +} + +inline bool ClApprox(const ClSymbolicWeight &cl1, const ClSymbolicWeight &cl2) +{ + vector<Number>::const_iterator it1 = cl1._values.begin(); + vector<Number>::const_iterator it2 = cl2._values.begin(); + + for (; it1 != cl1._values.end() && it2 != cl2._values.end(); + ++it1, ++it2) + { + if (!ClApprox(*it1,*it2)) + return false; + } + + if (it1 == cl1._values.end() && it2 == cl2._values.end()) + return true; + + return false; +} + +inline ClSymbolicWeight ReciprocalOf(const ClSymbolicWeight &) +{ throw(ExCLInternalError("Cannot take ReciprocalOf symbolic weight")); + return ClSymbolicWeight::Zero(); } + +#endif diff --git a/libs/cassowary/cassowary/ClTableau.h b/libs/cassowary/cassowary/ClTableau.h new file mode 100644 index 0000000000..117ed0fb9d --- /dev/null +++ b/libs/cassowary/cassowary/ClTableau.h @@ -0,0 +1,230 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClTableau.h + +#ifndef ClTableau_H +#define ClTableau_H + +#include <iostream> + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "Cassowary.h" +#include "ClLinearExpression.h" +#include "ClVariable.h" +#include "ClTypedefs.h" + + +#ifndef CL_NO_IO +class ClTableau; + +ostream &operator<<(ostream &xo, const ClTableau &clt); + +ostream &operator<<(ostream &xo, const ClVarSet &varset); + +ostream &operator<<(ostream &xo, const ClTableauColumnsMap &varmap); + +ostream &operator<<(ostream &xo, const ClTableauRowsMap &rows); + +ostream &operator<<(ostream &xo, const ClVarVector &varlist); +#endif // CL_NO_IO + +class ClTableau { + + public: + // No public constructor, since this does nothing but support + // an ADT for the ClSimplexSolver + + // Variable v has been removed from an Expression. If the + // Expression is in a tableau the corresponding basic variable is + // subject (or if subject is nil then it's in the objective function). + // Update the column cross-indices. + void NoteRemovedVariable(ClVariable v, ClVariable subject) + { +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + std::cerr << "(" << v << ", " << subject << ")" << std::endl; +#endif + ClVarSet &column = _columns[v]; + ClVarSet::const_iterator it = column.find(subject); + assert(it != column.end()); + column.erase(it); +#ifdef CL_TRACE_VERBOSE + std::cerr << "v = " << v << " and Columns[v].size() = " + << column.size() << std::endl; +#endif + if (column.size() == 0) + { + _columns.erase(v); + _externalRows.erase(v); + _externalParametricVars.erase(v); + } + } + + // v has been added to the linear Expression for subject + // update column cross indices + void NoteAddedVariable(ClVariable v, ClVariable subject) + { +#ifdef CL_TRACE + Tracer TRACER(__FUNCTION__); + std::cerr << "(" << v << ", " << subject << ")" << std::endl; +#endif + _columns[v].insert(subject); + if (v.IsExternal() && !FIsBasicVar(v)) + { + _externalParametricVars.insert(v); + } + } + +#ifndef CL_NO_IO + std::ostream &PrintOn(ostream &xo) const; + + ostream &PrintInternalInfo(ostream &xo) const; + + ostream &printExternalVariablesTo(ostream &xo) const; + +#endif + + // Check integrity of the tableau + // not complete, yet, but a start, at least + // Guard calls to AssertValid with CL_SOLVER_CHECK_INTEGRITY, + // since this is expensive + virtual void AssertValid() const { +#ifndef NDEBUG + // all external basic variables are in _externalRows + // and all external parametric variables are in _externalParametricVars + ClTableauRowsMap::const_iterator itRow = _rows.begin(); + for (; itRow != _rows.end(); ++itRow) + { + const ClVariable clv = (*itRow).first; + if (clv.IsExternal()) + { + if (_externalRows.find(clv) == _externalRows.end()) + { +#ifndef CL_NO_IO + std::cerr << "External basic variable " << clv + << " is not in _externalRows" << std::endl; +#endif + } + } + const ClLinearExpression *pcle = RowExpression(clv); + assert(pcle); + ClVarToNumberMap::const_iterator it = pcle->Terms().begin(); + for (; it != pcle->Terms().end(); ++it) + { + ClVariable clv = (*it).first; + if (clv.IsExternal()) + { + if (_externalParametricVars.find(clv) == _externalParametricVars.end()) + { +#ifndef CL_NO_IO + std::cerr << "External parametric variable " << clv + << " is not in _externalParametricVars" << std::endl; +#endif + } + } + } + } +#endif /* !NDEBUG */ + } + + + protected: + // Constructor -- want to start with empty objects so not much to do + ClTableau() + { } + + virtual ~ClTableau(); + + // Add v=expr to the tableau, update column cross indices + // v becomes a basic variable + // expr is now owned by ClTableau class, + // and ClTableauis responsible for deleting it + // (also, expr better be allocated on the heap!) + void addRow(ClVariable v, const ClLinearExpression &expr); + + // Remove v from the tableau -- remove the column cross indices for v + // and remove v from every Expression in rows in which v occurs + // returns a pointer to the variable (since we often want to delete + // the variable) + ClVariable RemoveColumn(ClVariable v); + + // Remove the basic variable v from the tableau row v=expr + // Then update column cross indices + // Probably want to call delete on the ClLinearExpression * returned + // unless you're adding that same Expression back into the + // tableau + ClLinearExpression *RemoveRow(ClVariable v); + + // Replace all occurrences of oldVar with expr, and update column cross indices + // oldVar should now be a basic variable + void SubstituteOut(ClVariable oldVar, const ClLinearExpression &expr); + + ClTableauColumnsMap Columns() + { return _columns; } + + ClTableauRowsMap Rows() + { return _rows; } + + // return true iff the variable subject is in the Columns keys + bool ColumnsHasKey(ClVariable subject) const + { + ClTableauColumnsMap::const_iterator i = _columns.find(subject); + return (i != _columns.end()); + } + + const ClLinearExpression *RowExpression(ClVariable v) const + { + ClTableauRowsMap::const_iterator i = _rows.find(v); + if (i != _rows.end()) + return (*i).second; + else + return 0; + } + + ClLinearExpression *RowExpression(ClVariable v) + { + const ClTableau *pthis = const_cast<const ClTableau *>(this); + return const_cast<ClLinearExpression *>(pthis->RowExpression(v)); + } + + + bool FIsBasicVar(ClVariable v) + { return RowExpression(v) != 0; } + + // private: FIXGJB: can I improve the encapsulation? + + // _columns is a mapping from variables which occur in expressions to the + // set of basic variables whose expressions contain them + // i.e., it's a mapping from variables in expressions (a column) to the + // set of rows that contain them + ClTableauColumnsMap _columns; + + // _rows maps basic variables to the expressions for that row in the tableau + ClTableauRowsMap _rows; + + // the collection of basic variables that have infeasible rows + // (used when reoptimizing) + ClVarSet _infeasibleRows; + + // the set of rows where the basic variable is external + // this was added to the C++ version to reduce time in SetExternalVariables() + ClVarSet _externalRows; + + // the set of external variables which are parametric + // this was added to the C++ version to reduce time in SetExternalVariables() + ClVarSet _externalParametricVars; + +}; + +#endif diff --git a/libs/cassowary/cassowary/ClTypedefs.h b/libs/cassowary/cassowary/ClTypedefs.h new file mode 100644 index 0000000000..74b625a72b --- /dev/null +++ b/libs/cassowary/cassowary/ClTypedefs.h @@ -0,0 +1,48 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClTypedefs.h + +#ifndef CL_TYPEDEFS_H__ +#define CL_TYPEDEFS_H__ + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include "ClLinearExpression_fwd.h" +#include <set> +#include <map> +#include <vector> + +using std::set; +using std::map; +using std::vector; + +class ClVariable; +class ClConstraint; +class ClEditInfo; + +typedef set<ClVariable> ClVarSet; +typedef map<ClVariable, ClVarSet > ClTableauColumnsMap; +typedef map<ClVariable, ClLinearExpression *> ClTableauRowsMap; + +// For Solver +typedef map<const ClConstraint *, ClVarSet> ClConstraintToVarSetMap; +typedef map<const ClConstraint *, ClVariable> ClConstraintToVarMap; +typedef map<ClVariable, const ClConstraint *> ClVarToConstraintMap; +typedef vector<ClVariable> ClVarVector; + +typedef set<const ClConstraint *> ClConstraintSet; + +// For FDSolver +typedef map<ClVariable, ClConstraintSet> ClVarToConstraintSetMap; + +#endif diff --git a/libs/cassowary/cassowary/ClVariable.h b/libs/cassowary/cassowary/ClVariable.h new file mode 100644 index 0000000000..03814e5ef2 --- /dev/null +++ b/libs/cassowary/cassowary/ClVariable.h @@ -0,0 +1,166 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// ClVariable.h +// A handle on ClAbstractVariable-s + +#ifndef ClVariable_H +#define ClVariable_H + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include <cstdio> +#include <map> +#include <string> +#include "Cassowary.h" +#include "ClFloatVariable.h" +#include "ClFDVariable.h" + +using std::map; +using std::string; + +class ClVariable; +typedef map<const string,ClVariable> StringToVarMap; + + +class ClVariable { + ClAbstractVariable *pclv; +public: + // converters from raw ClAbstractVariable + ClVariable(ClAbstractVariable *pclv_) : pclv(pclv_) { } + ClVariable(ClAbstractVariable &clv_) : pclv(&clv_) { } + + // Copy ctr + ClVariable(const ClVariable &clv_) : pclv(clv_.pclv) { } + + /// These ctrs build ClFloatVariable-s + ClVariable(string name, Number Value = 0.0) + : pclv(new ClFloatVariable(name,Value)) + { if (pmapStrPclv) { (*pmapStrPclv)[name] = *this; } } + ClVariable(Number Value = 0.0) + : pclv(new ClFloatVariable(Value)) { } + ClVariable(long number, char *prefix, Number Value = 0.0) + : pclv(new ClFloatVariable(number,prefix,Value)) { } + + // This one builds a ClFDVariable + ClVariable(ClFDVariable *pcfv) + : pclv(pcfv) + { if (pmapStrPclv) { (*pmapStrPclv)[pcfv->Name()] = *this; } } + + /// permit ClVariables to be used as pointers to pclvs + ClAbstractVariable *operator->() { return pclv; } + const ClAbstractVariable *operator->() const { return pclv; } + + /// and also forward the function calls along + + + bool IsFloatVariable() const { assert(pclv); return pclv->IsFloatVariable(); } + bool IsFDVariable() const { assert(pclv); return pclv->IsFDVariable(); } + bool IsDummy() const { assert(pclv); return pclv->IsDummy(); } + bool IsExternal() const { assert(pclv); return pclv->IsExternal(); } + bool IsPivotable() const { assert(pclv); return pclv->IsPivotable(); } + bool IsRestricted() const { assert(pclv); return pclv->IsRestricted(); } + + string Name() const { assert(pclv); return pclv->Name(); } + + Number Value() const { assert(pclv); return pclv->Value(); } + int IntValue() const { assert(pclv); return pclv->IntValue(); } + void SetValue(Number Value) + { assert(pclv); pclv->SetValue(Value); } + void ChangeValue(Number Value) + { assert(pclv); pclv->ChangeValue(Value); } + void SetPv(void *pv) + { assert(pclv); pclv->SetPv(pv); } + void *Pv() const + { assert(pclv); return pclv->Pv(); } + + void SetName(string const &nm) { + assert(pclv); + if (pmapStrPclv) { + pmapStrPclv->erase(Name()); + (*pmapStrPclv)[nm] = *this; + } + pclv->SetName(nm); + } + + ClAbstractVariable *get_pclv() const { return pclv; } + bool IsNil() const { return pclv == 0; } + + virtual FDNumber DesiredValue() const + { assert(false); } + + virtual list<FDNumber> *PlfdnDomain() + { assert(false); return 0; } + + static void SetVarMap(StringToVarMap *pmap) { pmapStrPclv = pmap; } + static StringToVarMap *VarMap() { return pmapStrPclv; } + static StringToVarMap *pmapStrPclv; +#ifndef CL_NO_IO + ostream &PrintOn(ostream &xo) const + { + if (pclv) return pclv->PrintOn(xo); /* return xo << "@" << pclv << endl; */ + return xo << "clvNil"; + } +#endif + + friend bool operator<(ClVariable cl1, ClVariable cl2) + { return cl1.pclv < cl2.pclv; } + + friend bool operator==(ClVariable cl1, ClVariable cl2) + { return cl1.pclv == cl2.pclv; } + + friend bool operator!=(ClVariable cl1, ClVariable cl2) + { return !(cl1 == cl2); } + +}; + +#ifndef CL_NO_IO +inline ostream &operator<<(ostream &xo, const ClVariable &clv) +{ return clv.PrintOn(xo); } +#endif + +#ifdef CL_USE_HASH_MAP_AND_SET +struct hash<ClVariable> { + size_t operator()(const ClVariable & v) const + { return size_t((unsigned long)v.get_pclv()/CL_PTR_HASH_DIVISOR); } +}; +#endif + + +#include <math.h> + +// Compare two double-s approximately, since equality is no good +inline bool ClApprox(double a, double b) +{ + const double epsilon = 1.0e-8; + if (a > b) { + return (a - b) < epsilon; + } else { + return (b - a) < epsilon; + } +} + +// Can remove these if I decide to +// autoconvert from ClVariable-s to double-s +inline bool ClApprox(ClVariable clv, double b) +{ + return ClApprox(clv->Value(),b); +} + +inline bool ClApprox(double a, ClVariable clv) +{ + return ClApprox(a,clv->Value()); +} + +extern ClVariable clvNil; + +#endif diff --git a/libs/cassowary/cassowary/Makefile.am b/libs/cassowary/cassowary/Makefile.am new file mode 100644 index 0000000000..cc581b80ff --- /dev/null +++ b/libs/cassowary/cassowary/Makefile.am @@ -0,0 +1,36 @@ +MAINTAINERCLEANFILES = autom4te.cache Makefile.in + +noinst_HEADERS = \ + Cassowary.h \ + ClAbstractVariable.h \ + ClDummyVariable.h \ + ClObjectiveVariable.h \ + ClSlackVariable.h \ + ClConstraint.h \ + ClConstraintHash.h \ + ClEditConstraint.h \ + ClEditOrStayConstraint.h \ + ClErrors.h \ + ClLinearConstraint.h \ + ClLinearEquation.h \ + ClLinearExpression.h \ + ClLinearExpression_fwd.h \ + ClLinearInequality.h \ + ClSolver.h \ + ClSimplexSolver.h \ + ClStayConstraint.h \ + ClStrength.h \ + ClSymbolicWeight.h \ + ClTableau.h \ + ClFDVariable.h \ + ClFDConnectorVariable.h \ + ClFloatVariable.h \ + ClVariable.h \ + ClReader.h \ + ClTypedefs.h \ + ClPoint.h \ + cl_auto_ptr.h \ + config-inline.h \ + debug.h \ + timer.h + diff --git a/libs/cassowary/cassowary/cl_auto_ptr.h b/libs/cassowary/cassowary/cl_auto_ptr.h new file mode 100644 index 0000000000..3c37429676 --- /dev/null +++ b/libs/cassowary/cassowary/cl_auto_ptr.h @@ -0,0 +1,69 @@ +// $Id$ +// See http://cseng.aw.com/bookdetail.qry?ISBN=0-201-63371-X&ptype=634 +// auto_ptr from More Effective C++ an earlier appendix (works w/ egcs) + + +#ifndef CL_AUTO_PTR_H +#define CL_AUTO_PTR_H + +#ifdef _MSC_VER +#include <memory> +template<class T> +void ReinitializeAutoPtr(auto_ptr<T> &apref, T *pt) +{ + auto_ptr<T> ap(pt); + apref = ap; +} +#define cl_auto_ptr auto_ptr +#else +// FIXGJB: This implementation for egcs is buggy -- be careful +// and replace ASAP +template<class T> +class cl_auto_ptr { + public: + explicit cl_auto_ptr(T *p = 0): pointee(p) {} + + template<class U> + cl_auto_ptr(cl_auto_ptr<U>& rhs): pointee(rhs.release()) {} + + ~cl_auto_ptr() { delete pointee; } + + template<class U> + cl_auto_ptr<T>& operator=(cl_auto_ptr<U>& rhs) + { + if (this != &rhs) reset(rhs.release()); + return *this; + } + + T& operator*() const { return *pointee; } + + T* operator->() const { return pointee; } + + T* get() const { return pointee; } + + T* release() + { + T *oldPointee = pointee; + pointee = 0; + return oldPointee; + } + + // protected: + // This is non-standard + void reset(T *p = 0) { delete pointee; pointee = p; } + + private: + T *pointee; +}; + +template<class T> +void ReinitializeAutoPtr(cl_auto_ptr<T> &apref, T *pt) +{ + apref.reset(pt); +} + + +#endif + + +#endif diff --git a/libs/cassowary/cassowary/config-inline.h b/libs/cassowary/cassowary/config-inline.h new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/libs/cassowary/cassowary/config-inline.h @@ -0,0 +1 @@ + diff --git a/libs/cassowary/cassowary/debug.h b/libs/cassowary/cassowary/debug.h new file mode 100644 index 0000000000..aa0499c641 --- /dev/null +++ b/libs/cassowary/cassowary/debug.h @@ -0,0 +1,48 @@ +// $Id$ +// +// Cassowary Incremental Constraint Solver +// Original Smalltalk Implementation by Alan Borning +// This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu> +// http://www.cs.washington.edu/homes/gjb +// (C) 1998, 1999 Greg J. Badros and Alan Borning +// See ../LICENSE for legal details regarding this software +// +// debug.h + +#ifndef CASSOWARY_DEBUG_H_ +#define CASSOWARY_DEBUG_H_ + +#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED) && !defined(CONFIG_INLINE_H_INCLUDED) +#include <cassowary/config-inline.h> +#define CONFIG_INLINE_H_INCLUDED +#endif + +#include <vector> +#include "Cassowary.h" + +#ifdef CL_TRACE +class Tracer { + public: + Tracer(const char *const sz) : sz_(sz) { cerr << "* " << sz; } + ~Tracer() { cerr << "x " << sz_ << " exited." << endl; } + private: + const char *const sz_; +}; + +inline void CtrTracer(const char *const sz, const void *pv) +{ cerr << "@+ " << sz << " ctrnew@ " << pv << endl; } + +inline void DtrTracer(const char *const sz, const void *pv) +{ cerr << "@- " << sz << " dtrnew@ " << pv << endl; } + +#else +class Tracer { + public: + Tracer(const char *const) { } +}; + +inline void CtrTracer(const char *const, const void *) { } +inline void DtrTracer(const char *const, const void *) { } +#endif // CL_TRACE + +#endif diff --git a/libs/cassowary/cassowary/timer.h b/libs/cassowary/cassowary/timer.h new file mode 100644 index 0000000000..6bad1a6fef --- /dev/null +++ b/libs/cassowary/cassowary/timer.h @@ -0,0 +1,176 @@ +/* $Id$ */ +#ifndef _TIMER_H_ +#define _TIMER_H_ + +// Programmer: John P. Russo +// -------------------------- +// John Russo has given permission to any of my students to use his +// "timer" class. +// +// Please give full credit to him any time you wish to use this class. +// Hossein Hakimzadeh 11/5/96 + +/************************** timer.cpp ********************************** + + A simple example that shows how C++ classes can be used to implement + a "Timer" object, which mimics the familiar actions of a stopwatch. + + The code relies heavily on the clock() function defined in the time + library. The clock() function returns the number of "ticks" that have + elapsed since a program starts. The size of a "tick" is compiler + dependent, but for PC compilers is about 1/18 second. + + The problem with the clock function is that it is not convenient to + use for typical timing operations. The timer class, defined below, by + contrast, shows that an object-oriented approach to modules can + provide tools that are natural and easy to use. + += = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ +#include <time.h> + +class Timer +{ + //==================== public section ================================ + + // The functions and/or data in the public section of a class are + // accessible to anyone who uses the Timer class. + +public: + Timer(); // Constructor, used to declare Timer objects + void Start(); // Starts a timer object + void Stop(); // Stop a timer object + void Reset(); // Reset timer object + int IsRunning(); // Is the timer object running? + double ElapsedTime(); // How much time has been recorded? + double Resolution(); // Shortest measurable amount of time + + //-------------------- private section ------------------------------- + + // The functions and/or data in the private section of a class are NOT + // accessible to those who use the Timer class. They are accessible by + // member functions of the class. This allows access to the data to be + // carefully controlled. + +private: + long StartReading; // Number of ticks when timer object last started. + long ElapsedTicks; // Number of ticks on timer object. + int TimerIsRunning; // 1 if and only if timer object is running. + double TicksPerSecond() // This inline function is used to convert +// {return 18.206481;} // "ticks" (returned by clock() ) to seconds. + {return CLOCKS_PER_SEC;} // "ticks" (returned by clock() ) to seconds. + // In most UNIX systems this is 1000000 +}; + +/**************************** Start ************************************ + + If the declaration "Timer StopWatch;" has been made, the the call, + "StopWatch.Start();" is like push the start button of a real stopwatch. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +void Timer::Start() +{ + TimerIsRunning = 1; // Stopwatch is now running + StartReading = clock(); // Look at internal clock and remember reading +} + +/**************************** Stop ************************************ + + Looks at the PC's internal clock and computes the number of ticks that + have elapsed since the timer was started. + + Note that if a timer is not reset, it can be used to time several events + and return the elapsed time for the enter set of events. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +void Timer::Stop() +{ + TimerIsRunning = 0; // Stop timer object. + ElapsedTicks += clock() - StartReading; // Add elapsed time to the +} // previous time. + +/**************************** Reset ************************************ + + Clears a Timer of previous elapsed times, so that a new event can be + timed. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +void Timer::Reset() +{ + TimerIsRunning = 0; // Start not yet called. + ElapsedTicks = 0; // No time on timer object yet. +} + +/************************** IsRunning ************************************ + + The data member, "TimerIsRunning" is used to keep track of whether a + timer is active, i.e. whether an event is being timed. While we want + those using the timer class to know when a timer is active, we do NOT + want them to directly access the TimerIsRunning variable. We solve this + problem, by making TimerIsRunning private and providing the public + "access function" below. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +int Timer::IsRunning() +{ + return TimerIsRunning; +} + +/************************* ElapsedTime *********************************** + + This function allows a client to determine the amount of time that has + elapsed on a timer object. Note that there are two possibilities: + + 1) A timer object has been started and stopped. We can detect this + case, because the variable "TimerIsRunning" is false. + + 2) A timer object is "running", i.e. is still in the process of timing + an event. It is not expected that this case will occur as frequently + as case 1). + + In either case, this function converts ticks to seconds. Note that + since the function TicksPerSecond() returns a value of type double, + an implicit type conversion takes place before doing the division + required in either case. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +double Timer::ElapsedTime() +{ + if ( !TimerIsRunning ) // Normal case + return ElapsedTicks/TicksPerSecond(); + + else + return (ElapsedTicks + clock() - StartReading)/TicksPerSecond(); +} + +/************************** Resolution *********************************** + + Althould we have no way of knowing how accurate the internal clock is, + we can predict its resolution, which is the shortest event that can be + measured by the clock. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +double Timer::Resolution() +{ + return 1/TicksPerSecond(); // Note 1 is coverted to 1.0 before division +} + +/******************** Timer (constructor) ******************************* + + A "constructor" is a special class member function, one which has the + same name as the class. The "default constructor" is a constructor that + has no parameters. A constructor is called automatically when an + instance of a class is declared. For example, the constructor defined + below is called when the declaration "Timer T;" is executed. + + If the programmer does not write a default constructor, then the + compiler will generate one automatically. However, by writing the + constructor below, we provide automatic initialization of timer objects. + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ +Timer::Timer() +{ + TimerIsRunning = 0; // Start not yet called. + ElapsedTicks = 0; // No time on timer object yet. +} + +#endif /* _TIMER_H_ */ diff --git a/libs/cassowary/configure.ac b/libs/cassowary/configure.ac new file mode 100644 index 0000000000..3e565d7709 --- /dev/null +++ b/libs/cassowary/configure.ac @@ -0,0 +1,64 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(cassowary) + +AC_CONFIG_AUX_DIR(.) +AC_CANONICAL_HOST +AC_CANONICAL_TARGET +AC_VALIDATE_CACHED_SYSTEM_TUPLE() + +LIBCASSOWARY_MAJOR_VERSION=0 +LIBCASSOWARY_MINOR_VERSION=60 +LIBCASSOWARY_MICRO_VERSION=3 + +AC_SUBST(LIBCASSOWARY_MAJOR_VERSION) +AC_SUBST(LIBCASSOWARY_MINOR_VERSION) +AC_SUBST(LIBCASSOWARY_MICRO_VERSION) + +BETA= + +LIBCASSOWARY_VERSION=$LIBCASSOWARY_MAJOR_VERSION.$LIBCASSOWARY_MINOR_VERSION.${LIBCASSOWARY_MICRO_VERSION}${BETA} +LIBCASSOWARY_RELEASE=$LIBCASSOWARY_MAJOR_VERSION-$LIBCASSOWARY_MINOR_VERSION-${LIBCASSOWARY_MICRO_VERSION}${BETA} + +AC_SUBST(LIBCASSOWARY_SO_VERSION) +AC_SUBST(LIBCASSOWARY_VERSION) +AC_SUBST(LIBCASSOWARY_RELEASE) + +AM_INIT_AUTOMAKE(libcassowary,${LIBCASSOWARY_VERSION}) + +AM_CONFIG_HEADER(config.h) + +dnl Checks for programs. + +AC_PROG_CC +AC_PROG_CXX +if test "$ac_cv_prog_cxx" = "no" ; then + AC_MSG_ERROR([*** libcassowary is C++. You don't appear to have a C++ compiler]) +fi + +CXXFLAGS="-g -D_REENTRANT" +OPT_CXXFLAGS="-D_REENTRANT -O6 -fomit-frame-pointer -ffast-math -fstrength-reduce -funroll-loops -fmove-all-movables" +if test x"$GXX" = xyes ; then + CXXFLAGS="$CXXFLAGS -Wall" +fi +if test x"$GXX" = xyes ; then + OPT_CXXFLAGS="$OPT_CXXFLAGS -Wall" +fi + +AC_ARG_ENABLE(optimize, + [ --enable-optimize ask the compiler for its best optimizations.], + [ if test "x$enable_optimize" != "xno" ; then CXXFLAGS="$OPT_CXXFLAGS" ; fi ]) + +AC_OBJEXT +AC_PROG_RANLIB +AM_PROG_LEX +AC_PROG_YACC + +AC_LANG_CPLUSPLUS + +CFLAGS="$CFLAGS $GLIB_CFLAGS" +CXXFLAGS="$CXXFLAGS $GLIB_CFLAGS" +LIBS="$LIBS $GLIB_LIBS $POSIX_RTSCHED_LIBS" + +AC_OUTPUT([Makefile + cassowary/Makefile +]) |