Browse Source

sde-create-iso: Introduced gaffitter tool

karasz/installer
Nagy Karoly Gabriel 15 years ago
committed by Alejandro Mery
parent
commit
4734a354e8
25 changed files with 6104 additions and 0 deletions
  1. +1
    -0
      src/gaffitter/AUTHORS
  2. +674
    -0
      src/gaffitter/COPYING
  3. +179
    -0
      src/gaffitter/DiskUsage.cc
  4. +108
    -0
      src/gaffitter/DiskUsage.h
  5. +37
    -0
      src/gaffitter/INSTALL
  6. +255
    -0
      src/gaffitter/Input.cc
  7. +188
    -0
      src/gaffitter/Input.h
  8. +78
    -0
      src/gaffitter/Makefile
  9. +179
    -0
      src/gaffitter/Optimizer.cc
  10. +413
    -0
      src/gaffitter/Optimizer.h
  11. +451
    -0
      src/gaffitter/Params.cc
  12. +215
    -0
      src/gaffitter/Params.h
  13. +78
    -0
      src/gaffitter/README
  14. +95
    -0
      src/gaffitter/gaffitter.cc
  15. +82
    -0
      src/gaffitter/optimizers/BestFit.cc
  16. +85
    -0
      src/gaffitter/optimizers/BestFit.h
  17. +724
    -0
      src/gaffitter/optimizers/GeneticAlgorithm.cc
  18. +379
    -0
      src/gaffitter/optimizers/GeneticAlgorithm.h
  19. +73
    -0
      src/gaffitter/optimizers/Split.cc
  20. +76
    -0
      src/gaffitter/optimizers/Split.h
  21. +211
    -0
      src/gaffitter/util/CmdLineException.h
  22. +396
    -0
      src/gaffitter/util/CmdLineParser.cc
  23. +889
    -0
      src/gaffitter/util/CmdLineParser.h
  24. +129
    -0
      src/gaffitter/util/Exception.h
  25. +109
    -0
      src/gaffitter/util/Random.h

+ 1
- 0
src/gaffitter/AUTHORS

@ -0,0 +1 @@
Douglas Adriano Augusto <daaugusto@gmail.com>

+ 674
- 0
src/gaffitter/COPYING

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

+ 179
- 0
src/gaffitter/DiskUsage.cc

@ -0,0 +1,179 @@
// ---------------------------------------------------------------------
// $Id: DiskUsage.cc 156 2008-06-08 07:13:49Z daaugusto $
//
// DiskUsage.cc (created on Tue Aug 23 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------
/**
* This macro determines which file system interface shall be used, one
* replacing the other. `_FILE_OFFSET_BITS' allows the 64 bit interface
* to replace the old interface.
*
* If `_FILE_OFFSET_BITS' is undefined, or if it is defined to the value
* `32', nothing changes. The 32 bit interface is used and types like
* `off_t' have a size of 32 bits on 32 bit systems.
*
* On 32bit systems 'stat -> stat64' and 'lstat -> lstat64'
* transparently.
*/
#define _FILE_OFFSET_BITS 64
#include "DiskUsage.h"
#include "util/Exception.h"
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <string>
#include <iostream>
using namespace std;
//----------------------------------------------------------------------
unsigned DiskUsage::m_block_size;
//----------------------------------------------------------------------
Params::UBigInt
DiskUsage::GetSize(const char* filename)
{
struct stat st;
if (lstat(filename, &st) != 0)
{
cerr << "> Could not read: " << filename << endl;
return 0;
}
if (S_ISDIR(st.st_mode))
{
char saved_path[m_max_path_name], tmp_path[m_max_path_name];
// saves current path before chdir to 'filename' directory
if (getcwd(saved_path, m_max_path_name-1) == NULL)
{
cerr << "> Path name too long; maximum " << m_max_path_name-1
<< " chars." << endl;
return 0;
}
if (chdir(filename) != 0)
{
cerr << "> Could not chdir to: " << filename << endl;
return 0;
}
if (getcwd(tmp_path, m_max_path_name-1) == NULL)
{
cerr << "> Path name too long; maximum " << m_max_path_name-1
<< " chars." << endl;
return 0;
}
if (lstat(tmp_path, &st) != 0)
{
cerr << "> Could not read dir: " << tmp_path << endl;
return 0;
}
Params::UBigInt total =
AllocationSize(static_cast<Params::UBigInt>(st.st_size))
+ DepthFirstTraversal(tmp_path);
// return to the original path (important!)
chdir(saved_path);
return total;
}
else // ISREG, ISLNK, ISFIFO, ISBLK, ...
return AllocationSize(static_cast<Params::UBigInt>(st.st_size));
}
//----------------------------------------------------------------------
Params::UBigInt
DiskUsage::AllocationSize(Params::UBigInt size)
{
Params::UBigInt remainder = size % m_block_size;
/* Test whether the filesize is smaller than the allocation block.
Also, 0-sized files occupy space equal to the allocation block size. */
if (remainder || size==0)
return size += m_block_size - remainder;
// the filesize matches perfectly the allocation block
return size;
}
//----------------------------------------------------------------------
Params::UBigInt
DiskUsage::DepthFirstTraversal(const char* currdir)
{
if (chdir(currdir) != 0)
{
cerr << "> Could not chdir to: " << currdir << endl;
return 0;
}
Params::UBigInt sum = 0;
// open the directory
DIR *dir = opendir(".");
if (dir == NULL)
{
cerr << "> Could not open dir: " << currdir << endl;
chdir("..");
return 0;
}
struct dirent *de;
while ((de = readdir(dir)))
{
struct stat st;
if (lstat(de->d_name, &st) != 0)
{
cerr << "> Could not read: " << de->d_name << endl;
continue;
}
if (S_ISDIR(st.st_mode)) // is a directory (= recursive)
{
string tmp_str = de->d_name;
if ((tmp_str != ".") && (tmp_str != ".."))
{
string filename = string(currdir) + "/" + tmp_str;
sum += AllocationSize(static_cast<Params::UBigInt>(st.st_size))
+ DepthFirstTraversal(filename.c_str());
}
}
else // ISREG, ISLNK, ISFIFO, ISBLK, ...
sum += AllocationSize(static_cast<Params::UBigInt>(st.st_size));
}
closedir(dir);
chdir("..");
return sum;
}
//----------------------------------------------------------------------

+ 108
- 0
src/gaffitter/DiskUsage.h

@ -0,0 +1,108 @@
/*
* --- SDE-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* Filename: src/gaffitter/DiskUsage.h
* Copyright (C) 2009 The OpenSDE Project
*
* More information can be found in the files COPYING and README.
*
* 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; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- SDE-COPYRIGHT-NOTE-END ---
*/
// ---------------------------------------------------------------------
// $Id: DiskUsage.h 214 2008-07-30 09:56:16Z daaugusto $
//
// DiskUsage.h (created on Tue Aug 23 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------
#ifndef disk_usage_hh
#define disk_usage_hh
#include "Params.h"
//----------------------------------------------------------------------
/** \class DiskUsage
*
* Provides a method to extract sizes of a given file or directory
* (recursively).
*
* This class uses POSIX functions (lstat, chdir, opendir, closedir,
* S_ISDIR) and POSIX structures (stat, dirent). So, this class
* requires a POSIX-compatible environment to work.
*/
class DiskUsage {
public:
/**
* Returns the size of the given file or directory.
*
* If the given file/directory could not be read then GetSize returns
* "0". Note: 0-sized files returns \ref m_block_size.
*/
static Params::UBigInt GetSize(const char*);
/**
* Set the block size used by \ref AllocationSize(Params::UBigInt).
*/
static void SetBlockSize(unsigned bs) { m_block_size = bs; }
/**
* This function returns the real size (allocated) of a given "size".
*
* When size=0 then it occupies exactly \ref m_block_size.
*/
static Params::UBigInt AllocationSize(Params::UBigInt);
/**
* Same as \ref AllocationSize(Params::UBigInt) but casts the given
* size to UBigInt datatype. */
static Params::Size_t AllocationSize(Params::Size_t size)
{
// instead of doing a cast to long long int (UBigInt), it is
// possible to use a floor, ceil or "round" function.
return AllocationSize(static_cast<Params::UBigInt>(size));
}
private:
/**
* This function travels a given directory recursively.
*
* \return Total size of the given directory.
*/
static Params::UBigInt DepthFirstTraversal(const char*);
private:
/**
* The smallest amount of bytes a file/directory can occupy.
*/
static unsigned m_block_size;
/**
* Maximum size of a path name. This variable is used by the getcwd
* function.
*/
static const int m_max_path_name = 4096;
};
//----------------------------------------------------------------------
#endif

+ 37
- 0
src/gaffitter/INSTALL

@ -0,0 +1,37 @@
$Id: INSTALL 193 2008-07-14 20:48:23Z daaugusto $
------------------------------------------
Genetic Algorithm File Fitter -- gaffitter
------------------------------------------
http://gaffitter.sourceforge.net/ (home page)
http://sourceforge.net/projects/gaffitter/ (project page)
2005-2008 - Douglas A. Augusto (daaugusto@gmail.com)
Released under the GNU General Public License (GPL) version 3 (or
later)
http://www.gnu.org/licenses/gpl.txt
== Installation Instructions ==
1) Prerequisites
- POSIX-compatible Operating System (required by DiskUsage class to get
the size of a file or directory)
- C++ compiler (recommended: GCC)
2) Compilation
cd gaffitter-X.Y.Z
make
3) Installation (may need administrator privileges):
make install DESTDIR=/usr/local
(will install gaffitter in /usr/local/bin/; change DESTDIR as
necessary)

+ 255
- 0
src/gaffitter/Input.cc

@ -0,0 +1,255 @@
// ---------------------------------------------------------------------
// $Id: Input.cc 230 2008-08-14 01:45:04Z daaugusto $
//
// Input.cc (created on Tue Aug 23 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------
#include "Input.h"
#include "DiskUsage.h"
#include "util/Exception.h"
using namespace std;
//----------------------------------------------------------------------
Input::Input( Params& params ): m_total_size( 0.0 ), m_params( params )
{
DiskUsage::SetBlockSize(m_params.m_block_size);
Initialize();
}
//----------------------------------------------------------------------
void
Input::Initialize()
{
if (m_params.m_verbose) cout <<
"> Reading from input... " << flush << endl;
// bypass file reading?
if (m_params.m_direct_input) { ReadInput(); } else { LoadFiles(); }
// Check whether there are still files/items to process or not.
if (m_files.size() == 0) throw E_NoInputFiles();
}
//----------------------------------------------------------------------
void
Input::ReadInput()
{
//--- read data from stdin (pipe)
if (m_params.m_pipe)
{
/* If the option --null-data (-z) was specified, then the end of a
* filename is determined by the NULL (\0) char; otherwise, the
* newline (\n) is used. This option is very useful, for intance,
* when dealing with output from 'find' using the 'print0' option.
*
* For input files given as args (command-line), this option has
* no effect. */
const char delim = m_params.m_null_data ? '\0' : '\n';
string s;
getline(cin, s, delim);
if (cin)
{
do
{
StringToSizeID(s); //try to add the item into m_files
getline(cin, s, delim);
} while (cin);
}
}
// --- read data from args too (if any)
while (m_params.m_cmdline_items.size()>0)
{
StringToSizeID(m_params.m_cmdline_items.front());
m_params.m_cmdline_items.pop_front(); // release memory
}
}
//----------------------------------------------------------------------
void
Input::StringToSizeID( const string& s )
{
// just a empty string, ignoring it
if (s == "") return;
/* Column separator (between 'size' and 'identifier'). Only *one* of
* these characters is allowed: whitespace (' ') or tabulation ('\t').
* If there is given more than one of the above, then the extra chars
* will be part of the ID string. This is particularly useful when
* dealing with filenames with unusual chars (like newline) and the
* option '-z' is specified; thus, it is known that any char after
* the separator (up to '\0') is part of the filename.
*/
const char* delimiters = "\t ";
// find the first digit of the 'size' column
string::size_type size_begin = s.find_first_not_of(delimiters);
if (size_begin == string::npos)
{
cerr << "> [Ignoring] Could not get size of: " << s << endl;
return;
}
// find the first 'tab' or 'space' after the 'size' column
string::size_type size_end = s.find_first_of(delimiters, size_begin);
Params::Size_t size;
// converts the 'size' column into 'size' variable
if( !Params::StringToDouble( size, string( s, size_begin, size_end ) ) )
{
cerr << "> [Ignoring] Could not get size of: " << s << endl;
return;
}
/* When an ID is not given, then 'size_end == string::npos'. In this case,
* the ID will be a string whose content = size. For example, given
* the entry <100>, the size will be 100 and the ID will be "100".
*
* If there was given a pair "x " (note the space/tab), then the ID will
* be a string of size 0 (null string). For intance, given <100 >,
* the size will be 100 and the ID will be "".
*
* If none of the above, the string ID will contain all chars from
* 'size_end + 1' position to the end of 's'. For example, given the
* pair <100 a hundred>, the size will be 100 while the ID will be
* "a hundred".
* */
string str_id( s, size_end == string::npos ? size_begin : size_end + 1,
string::npos );
// size calculation considering the allocation block
Params::Size_t total_size = (m_params.m_no_metric) ? size :
DiskUsage::AllocationSize( static_cast<Params::Size_t>( size *
m_params.DI_Factor() ) );
if (CheckRange(str_id, total_size))
{
m_files.push_back(new SizeName(str_id, total_size));
m_total_size += total_size;
}
}
//----------------------------------------------------------------------
void
Input::LoadFiles()
{
//--- read data from stdin (pipe)
if (m_params.m_pipe)
{
/* If the option --null-data (-z) was specified, then the end of a
* filename is determined by the NULL (\0) char; otherwise, the
* newline (\n) is used. This option is very useful, for intance,
* when dealing with output from 'find' using the 'print0' option.
*
* For input files given as args (command-line), this option has
* no effect. */
const char delim = m_params.m_null_data ? '\0' : '\n';
string s;
getline(cin, s, delim);
if (cin)
{
do
{
AddFile(s); //try to add the given file in m_files
getline(cin, s, delim);
} while (cin);
}
}
// --- read data from args too (if any)
while (m_params.m_cmdline_items.size()>0)
{
AddFile(m_params.m_cmdline_items.front());
m_params.m_cmdline_items.pop_front(); // release memory
}
}
//---------------------------------------------------------------------
void
Input::AddFile(const string& s)
{
Params::Size_t size = DiskUsage::GetSize(s.c_str());
if (size == 0) { cerr << "> [Ignoring] file/dir: " << s << endl; return; }
if (CheckRange(s,size))
{
m_files.push_back(new SizeName(s, size));
m_total_size += size;
}
}
//---------------------------------------------------------------------
bool
Input::CheckRange(const string& s, Params::Size_t size) const
{
if (size > m_params.m_target)
{
cerr << "> [Ignoring] bigger than 'target'("
<< m_params.PrettySize(m_params.m_target) << "): " << s
<< " (" << m_params.PrettySize(size) << ")" << endl;
return false;
}
if (size > m_params.m_max_size)
{
cerr << "> [Ignoring] bigger than '--max-size'("
<< m_params.PrettySize(m_params.m_max_size) << "): "
<< s << " (" << m_params.PrettySize(size) << ")" << endl;
return false;
}
if (size <= 0.0)
{
cerr << "> [Ignoring] 0-sized input: " << s << endl;
return false;
}
if (size < m_params.m_min_size)
{
cerr << "> [Ignoring] smaller than '--min-size'("
<< m_params.PrettySize(m_params.m_min_size) << "): " << s
<< " (" << m_params.PrettySize(size) << ")" << endl;
return false;
}
return true;
}
//---------------------------------------------------------------------

+ 188
- 0
src/gaffitter/Input.h

@ -0,0 +1,188 @@
/*
* --- SDE-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* Filename: src/gaffitter/Input.h
* Copyright (C) 2009 The OpenSDE Project
*
* More information can be found in the files COPYING and README.
*
* 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; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- SDE-COPYRIGHT-NOTE-END ---
*/
// ----------------------------------------------------------------------------
// $Id: Input.h 230 2008-08-14 01:45:04Z daaugusto $
//
// Input.h (created on Tue Aug 23 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
#ifndef input_hh
#define input_hh
#include <string>
#include <vector>
#include "Params.h"
// ----------------------------------------------------------------------------
/**
* @class SizeName
* @brief Contains the size and the name of a file/item.
*/
class SizeName {
public:
SizeName( const std::string id, const Params::Size_t size ):
m_name( id ), m_size( size ) {}
/**
* Returns the filesize.
*/
Params::Size_t Size() const { return m_size; }
/**
* Returns the filename.
*/
const std::string& Name() const { return m_name; }
public:
// Comparison functions (for sorting containers)
/**
* Comparison function for sorting by size (ascending).
*/
static bool CmpSize(const SizeName* a, const SizeName* b)
{
return a->Size() < b->Size();
}
/**
* Comparison function for sorting by size (descending).
*/
static bool CmpSizeRev(const SizeName* a, const SizeName* b)
{
return a->Size() > b->Size();
}
/**
* Comparison function for sorting by name (ascending).
*/
static bool CmpName(const SizeName* a, const SizeName* b)
{
return a->Name() < b->Name();
}
/**
* Comparison function for sorting by name (descending).
*/
static bool CmpNameRev(const SizeName* a, const SizeName* b)
{
return a->Name() > b->Name();
}
/**
* Comparison function for sorting by name (ascending and nocase).
*/
static bool CmpNameNocase(const SizeName* a, const SizeName* b)
{
std::string::const_iterator p = a->Name().begin(), q = b->Name().begin();
while (p != a->Name().end() && q != b->Name().end() && toupper(*p)
== toupper(*q))
{
++p; ++q;
}
if (p == a->Name().end()) return q != b->Name().end();
if (q == b->Name().end()) return false;
return toupper(*p) < toupper(*q);
}
/**
* Comparison function for sorting by name (descending and nocase).
*/
static bool CmpNameRevNocase(const SizeName* a, const SizeName* b)
{
return !CmpNameNocase(a,b);
}
private:
const std::string m_name; /**< Holds the file/item name */
const Params::Size_t m_size; /**< Holds the file/item size */
};
// ----------------------------------------------------------------------------
class Input {
public:
/**
* Input class constructor. Sets \ref DiskUsage::m_block_size (DiskUsage
* static data member).
*/
Input( Params& );
~Input() { for( unsigned i = 0; i < m_files.size(); ++i ) delete m_files[i]; }
private:
/**
* \brief Performs initial steps.
*
* Loads files from input, gets their sizes, filters and adds them.
*/
void Initialize();
/**
* Reads the input directly (--di) instead of files/dir. Reads from
* stdin and/or args.
*/
void ReadInput();
/**
* Loads files from input (stdin/args).
*/
void LoadFiles();
/**
* Tries to add a file into \ref m_files to be processed.
*/
void AddFile(const std::string&);
/**
* Converts a given string to "size ID" pair and puts it into \ref
* m_files.
*/
void StringToSizeID(const std::string&);
/**
* Check/filter files bigger than 'target'/'--max-size' and smaller
* than '--min-size'
*/
bool CheckRange(const std::string&, Params::Size_t) const;
public:
/**
* \var m_files
*
* Contains the size and name of input files (filtered)
* */
std::vector<const SizeName*> m_files;
Params::Size_t m_total_size; /**<Holds the total size of the items */
/**
* Global parameters.
*/
Params& m_params;
};
// ----------------------------------------------------------------------------
#endif

+ 78
- 0
src/gaffitter/Makefile

@ -0,0 +1,78 @@
# --- SDE-COPYRIGHT-NOTE-BEGIN ---
# This copyright note is auto-generated by ./scripts/Create-CopyPatch.
#
# Filename: src/gaffitter/Makefile
# Copyright (C) 2009 The OpenSDE Project
#
# More information can be found in the files COPYING and README.
#
# 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; version 2 of the License. A copy of the
# GNU General Public License can be found in the file COPYING.
# --- SDE-COPYRIGHT-NOTE-END ---
# $Id: Makefile 235 2008-08-15 20:10:08Z daaugusto $
# Copyright (C) 2005-2008 Douglas A. Augusto (daaugusto@gmail.com)
CPPFILES = Params.cc DiskUsage.cc Input.cc Optimizer.cc \
optimizers/GeneticAlgorithm.cc \
optimizers/BestFit.cc optimizers/Split.cc \
util/CmdLineParser.cc
INCLUDES = -I/usr/local/include -I.
CXX = g++
CXXFLAGS = -O3 -Wno-long-long $(INCLUDES)
LIBPATH =
LIBS =
LDFLAGS = $(LIBPATH) $(LIBS)
###########################################################################
OBJS = $(CPPFILES:.cc=.o)
.SUFFIXES: .o .cc
.cc.o:
@echo $<:
$(CXX) $(CXXFLAGS) -c $*.cc -o $*.o
default: gaffitter
gaffitter: $(OBJS) gaffitter.cc Params.h
$(CXX) $(CXXFLAGS) $@.cc $(OBJS) -o $@ $(LDFLAGS)
###########################################################################
objs: $(OBJS)
###########################################################################
install:
install -D -m 0755 gaffitter $(DESTDIR)$(prefix)/bin/gaffitter
uninstall:
rm $(DESTDIR)$(prefix)/bin/gaffitter
clean:
rm -f *.o gaffitter optimizers/*.o util/*.o
# rule for building dependency lists, and writing them to this Makefile
depend:
makedepend -Y -- $(CXXFLAGS) -- $(CPPFILES)
# DO NOT DELETE
Params.o: Params.h util/Exception.h util/CmdLineParser.h
Params.o: util/CmdLineException.h
DiskUsage.o: DiskUsage.h Params.h util/Exception.h
Input.o: Input.h Params.h DiskUsage.h util/Exception.h
Optimizer.o: Optimizer.h Input.h Params.h util/Exception.h
optimizers/GeneticAlgorithm.o: optimizers/GeneticAlgorithm.h Input.h Params.h
optimizers/GeneticAlgorithm.o: util/Random.h Optimizer.h Input.h
optimizers/GeneticAlgorithm.o: util/Exception.h
optimizers/BestFit.o: optimizers/BestFit.h Optimizer.h Input.h Params.h
optimizers/BestFit.o: util/Exception.h
optimizers/Split.o: optimizers/Split.h Optimizer.h Input.h Params.h
optimizers/Split.o: util/Exception.h
util/CmdLineParser.o: util/CmdLineParser.h util/CmdLineException.h

+ 179
- 0
src/gaffitter/Optimizer.cc

@ -0,0 +1,179 @@
// ---------------------------------------------------------------------------
// $Id: Optimizer.cc 227 2008-08-13 20:51:32Z daaugusto $
//
// Optimizer.cc (created on Thu Nov 17 18:25:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------------
#include "Optimizer.h"
#include <utility>
#include <iterator>
#include <algorithm>
#include <cmath>
using namespace std;
// ---------------------------------------------------------------------------
bool
Intersect( Bin& a, vector<Bin>::iterator g1, vector<Bin>::iterator g2,
vector<const SizeName*>& unassigned )
{
// TODO: Maintain all time sorted?!?
vector<const SizeName*> tmp, diff( a.Count() );
// Add all items of each bin in tmp vector
while( g1 != g2 )
{
tmp.insert( tmp.end(), g1->begin(), g1->end() );
++g1;
}
sort( a.begin(), a.end() );
sort( tmp.begin(), tmp.end() );
/* Diff is the difference of 'a' and 'tmp'. The difference of two sets is
* formed by the elements that are present in the first set, but not in the
* second one.
*
* Iterator it is the iterator to the end of the constructed range.
* */
vector<const SizeName*>::iterator it = set_difference(
a.begin(), a.end(), tmp.begin(), tmp.end(), diff.begin() );
if( it - diff.begin() == a.Count() )
return false; // No intersection!
else // Intersection! Some elements of 'a' are present in 'tmp'
return unassigned.insert( unassigned.end(), diff.begin(), it ), true;
}
// ---------------------------------------------------------------------------
Params::Size_t
Optimizer::Evaluate( const BinSet& bins ) const
{
/* According to Falkenauer, the 'f' cost function is given by:
* ___
* \ k
* /__ (F_i / C)
* f = ________________
*
* N
*
* where:
* N: the number of the bins used in the solution
* F_i: the sum of sizes of the items in the bin i (how much is
* used)
* C: the bin capacity
* k: a constant, k>1 (usually k=2)
*/
const int k = 2;
Params::Size_t f = 0.0;
for( unsigned i = 0; i < bins.Count(); ++i )
{
f += pow( bins[i].Used() / bins[i].Capacity(), k );
}
f /= bins.Count();
return f;
}
// ---------------------------------------------------------------------------
void
Optimizer::Output()
{
/* Sort the bins from more filled (lesser waste) to less filled
* (greater waste). This is particularly useful when a maximum number
* of volumes (bins) is specified, so only the better ones are
* selected. */
if( !m_params.m_split )
sort( m_solution->begin(), m_solution->end() );
// comparison function. Should be "by size" or "by name" (reverse or not)
bool ( *cmp_function ) ( const SizeName*, const SizeName* );
// sort by name or size, ascending or descending
if (m_params.m_sort_by_size)
if (m_params.m_sort_reverse)
cmp_function = SizeName::CmpSizeRev;
else
cmp_function = SizeName::CmpSize;
else // sort by name
if (m_params.m_sort_reverse)
if (m_params.m_no_case)
cmp_function = SizeName::CmpNameRevNocase;
else
cmp_function = SizeName::CmpNameRev;
else
if (m_params.m_no_case)
cmp_function = SizeName::CmpNameNocase;
else
cmp_function = SizeName::CmpName;
if( m_params.m_verbose ) cout << endl;
for( unsigned i = 0; i < m_solution->Count() && i < m_params.m_max_bins; ++i )
{
if( !m_params.m_hide_items )
{
// sort the output
sort((*m_solution)[i].begin(), (*m_solution)[i].end(), cmp_function);
for( unsigned int j=0; j<(*m_solution)[i].Count(); ++j )
{
if( m_params.m_enclose )
cout << m_params.m_enclose_chr << (*m_solution)[i][j]->Name()
<< m_params.m_enclose_chr;
else
cout << (*m_solution)[i][j]->Name();
if( m_params.m_show_size )
cout << '\t' << m_params.PrettySize((*m_solution)[i][j]->Size());
cout << m_params.m_delimit_chr;
}
}
// print the summary
if( !m_params.m_hide_summary )
{
if( !m_params.m_hide_items ) cout << endl;
cout << "[" << i + 1 << "] "
<< m_params.PrettySize( (*m_solution)[i].Used() ) << "/"
<< m_params.PrettySize( (*m_solution)[i].Capacity() ) << " of "
<< m_params.PrettySize( m_total_size )
<< ", Diff: " << m_params.PrettySize((*m_solution)[i].Free())
<< ", Items: "
<< (*m_solution)[i].Count()<< "/" << m_files.size() << endl;
}
// Print the bin separator
if( !m_params.m_hide_items && i != m_solution->Count() - 1
&& i != m_params.m_max_bins - 1 )
cout << m_params.m_bins_separator;
}
}
// ---------------------------------------------------------------------------

+ 413
- 0
src/gaffitter/Optimizer.h

@ -0,0 +1,413 @@
/*
* --- SDE-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* Filename: src/gaffitter/Optimizer.h
* Copyright (C) 2009 The OpenSDE Project
*
* More information can be found in the files COPYING and README.
*
* 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; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- SDE-COPYRIGHT-NOTE-END ---
*/
// ---------------------------------------------------------------------------
// $Id: Optimizer.h 232 2008-08-15 18:19:35Z daaugusto $
//
// Optimizer.h (created on Thu Nov 17 18:25:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------------
#ifndef Optimizer_hh
#define Optimizer_hh
#include "Input.h"
#include "Params.h"
#include "util/Exception.h"
#include <vector>
#include <iostream>
#include <cmath>
// ---------------------------------------------------------------------------
/**
* @def ROUND
* @brief Round a given float number
*/
#define ROUND( x ) (x < 0 ? std::ceil( (x) - 0.5 ) : std::floor( (x) + 0.5 ))
const Params::Size_t EPSILON = 0.000001;
// ---------------------------------------------------------------------------
class Optimizer;
class BinSet;
/**
* @brief Compare two double considering the not exact float point
* representation.
*/
static bool AlmostEqual( double u, double v )
{
return std::fabs( u - v ) <= EPSILON * std::fabs( u ) &&
std::fabs( u - v ) <= EPSILON * std::fabs( v );
}
// ---------------------------------------------------------------------------
/**
* @class Bin
* @brief A Bin is a collection of items/files (a "volume")
*/
class Bin {
public:
/**
* @brief Bin's constructor.
*/
Bin( Params::Size_t capacity ):
m_sum_sizes( 0.0 ), m_capacity( capacity ) {}
/**
* @brief Adds items from a given vector of SizeName and sets the
* capacity as the sum of the sizes. */
Bin( const std::vector<const SizeName*>& sn )
{
for( unsigned i = 0; i < sn.size(); ++i ) AddItem( sn[i] );
m_capacity = Used();
}
/**
* @brief Returns the number of items.
*/
unsigned Count() const { return m_items.size(); }
/**
* @brief Returns the ith item.
*/
const SizeName* Item( int i ) const { return m_items[i]; }
/**
* @brief Returns all items (vector of items).
*/
std::vector<const SizeName*>& Items() { return m_items; }
/**
* @brief Returns all items (vector of items); const version.
*/
const std::vector<const SizeName*>& Items() const { return m_items; }
/**
* @brief Returns the total space occupied by the items.
*/
Params::Size_t Used() const { return m_sum_sizes; }
/**
* @brief Returns the total space available.
*/
Params::Size_t Free() const { return Capacity() - Used(); }
/**
* @brief Returns the bin's capacity.
*
* Likely, the bin's capacity is the same as @ref m_params.m_target.
* However, gaffitter can be adapted to support variable bin capacity, and
* so different bins might report different capacity.
*/
Params::Size_t Capacity() const { return m_capacity; }
/**
* @brief Add an item to the current bin.
*/
void AddItem( const SizeName* i )
{
//Assert (i->Size() <= Free());
m_items.push_back(i);
m_sum_sizes += i->Size();
}
/**
* @brief Replace the ith item with a new item.
*/
void ReplaceItem( int i, const SizeName* item )
{
m_sum_sizes += ( item->Size() - m_items[i]->Size() );
m_items[i] = item;
}
/**
* @brief Remove the ith item.
*/
void DelItem( int i )
{
//Assert(m_items[i]->Size() <= Used());
m_sum_sizes -= m_items[i]->Size();
m_items.erase( m_items.begin() + i );
}
/**
* @brief Add all items of a given bin.
*/
void AddAllItems( Bin& b )
{
for( unsigned i = 0; i < b.Count(); ++i ) AddItem( b[i] );
}
/**
* @brief Remove all items of the current bin.
*/
void DelAllItems() { m_items.clear(); m_sum_sizes = 0.0; }
/**
* @brief Returns the ith item.
*/
const SizeName* operator[](int i) const { return m_items[i]; }
/**
* @brief Overloaded operator <
*
* It compares the bins regarding the free space; the most filled bin comes
* first. It they have the same amount of free space, then the bin having
* smaller number of items is considered the smaller one.
*/
bool operator<( const Bin& bin ) const
{
if ( Free() < bin.Free() ) return true;
if ( Free() == bin.Free() ) return Count() < bin.Count();
return false;
}
/**
* @brief Compares two bins in a relaxed fashion.
*
* To achieve better performance, this function only compares the <b>free
* space</b> (@ref Free()) and the <b>number of bins</b> (@ref Count()).
*
* For a complete comparison, this function should also verify if the two
* bins contain exactly the same items.
*/
bool operator==( const Bin& bin ) const
{
return ( AlmostEqual( bin.Free(), Free() ) && bin.Count() == Count() );
}
/**
* @brief Pointer (iterator) to the first item of m_items (begin())
*/
std::vector<const SizeName*>::iterator begin() { return m_items.begin(); }
/**
* @brief Pointer (iterator) to the last item plus one of m_items (end())
*/
std::vector<const SizeName*>::iterator end() { return m_items.end(); }
/**
* @brief Verify if a bin contains items in common with a @b set of bins,
* and fill @c unassigned with the non-duplicate (non-common) items.
*
* @param[in] a Bin to verify
* @param[in] g1 First bin of the set of bins
* @param[in] g2 Last bin of the set of bins
* @param[out] unassigned List where the non-common items will be put.
*/
friend bool Intersect( Bin& a, std::vector<Bin>::iterator g1,
std::vector<Bin>::iterator g2,
std::vector<const SizeName*>& unassigned );
private:
std::vector<const SizeName*> m_items; /**< Vector of items. */
Params::Size_t m_sum_sizes; /**< Total occupied size by the items. */
Params::Size_t m_capacity; /**< Bin's capacity. */
};
// ---------------------------------------------------------------------------
/**
* @class BinSet
* @brief A set of bins
*/
class BinSet {
public:
/**
* @brief Returns the ith bin.
*/
Bin& operator[]( int i ) { return m_bins[i]; }
/**
* @brief Returns the ith bin; const version.
*/
const Bin& operator[]( int i ) const { return m_bins[i]; }
/**
* @brief Add a bin of capacity @c capacity.
*/
Bin& AddBin( Params::Size_t capacity )
{
m_bins.push_back( Bin( capacity ) );
return m_bins.back();
}
/**
* @brief Add the bin @c b.
*/
Bin& AddBin(const Bin& b) { m_bins.push_back(b); return m_bins.back(); }
/**
* @brief Pointer (iterator) to the first bin of m_bins (begin())
*/
std::vector<Bin>::iterator begin() { return m_bins.begin(); }
/**
* @brief Pointer (iterator) to the last bin plus one of m_bins (end())
*/
std::vector<Bin>::iterator end() { return m_bins.end(); }
/**
* @brief Remove the ith bin.
*/
void DelBin( int i ) { m_bins.erase( m_bins.begin() + i ); }
/**
* @brief Remove all bins (clear).
*/
void DelAllBins() { m_bins.clear(); }
/**
* @brief Returns the number of bins.
*/
unsigned int Count() const { return m_bins.size(); }
/**
* @brief Verify if two bins are different.
*/
bool operator!=( const BinSet& bs ) const { return !( *this == bs ); }
/**
* @brief Verify if two bins are equal.
*/
bool operator==( const BinSet& bs ) const
{
if( Count() != bs.Count() ) return false;
std::vector<Bin>::const_iterator i = m_bins.begin(), j = bs.m_bins.begin();
while( i != m_bins.end() ) if( !(*i++ == *j++) ) return false;
return true;
}
private:
std::vector<Bin> m_bins; /**< Vector of bins. */
};
// ---------------------------------------------------------------------------
/**
* @class Optimizer
* @brief Base class for the search algorithms.
*/
class Optimizer {
public:
/**
* @brief Initialize some variables.
*/
Optimizer( Input& i ): m_files( i.m_files ), m_params( i.m_params ),
m_total_size( i.m_total_size ), m_solution( 0 )
{
/* The correct way to calculate m_bin_theo. A problematic scenario
* occurs, for instance, when the total size is 2000 and the bin
* capacity (target) is 100, and unfortunately the division
* 2000/100 is represented as 20.000001 rather than the exact
* 20.0; so, ceil( 20.000001) is 21 instead of giving 20 as the
* theoretical minimum number of bin. */
if( !m_params.m_bins_theo ) // if not given calculate it!
{
const Params::Size_t div = m_total_size / m_params.m_target;
if( div > ROUND( div ) && div - ROUND( div ) < EPSILON )
m_params.m_bins_theo = static_cast<unsigned>( ROUND( div ) );
else
m_params.m_bins_theo = static_cast<unsigned>( ceil( div ) );
}
if( m_params.m_verbose ) std::cout << "> Searching... "
<< std::flush << std::endl;
}
/**
* @brief Optimizer's destructor.
*/
virtual ~Optimizer() {};
private:
/**
* @brief Copies are not allowed.
*/
Optimizer( const Optimizer& );
/**
* @brief Attributions are not allowed.
*/
Optimizer& operator=( const Optimizer& );
public:
/**
* @brief Searches for a optimal solution (via Genetic Algorithm, Best Fit
* or Split)
*/
virtual void Evolve() = 0;
/**
* @brief Print the result to the standard output.
*
* Print the selected files, a brief summary (sum, diff and number of
* selected files).
*/
void Output();
/**
* @brief This overloaded operator prints the name and parameters of the
* search algorithms.
*/
friend std::ostream& operator<<( std::ostream&, const Optimizer& );
protected:
/**
* @brief Write to streams the name and parameters of the search algorithms
*/
virtual std::ostream& Write( std::ostream& s ) const
{
s << "> Target: " << m_params.PrettySize(m_params.m_target)
<< "\n> Input size: " << m_files.size()
<< "\n> Theoretical minimum number of bins: " << m_params.m_bins_theo
<< std::endl;
return s;
}
protected:
/**
* @brief Evaluate candidates.
*/
Params::Size_t Evaluate( const BinSet& bs ) const;
std::vector<const SizeName*>& m_files; /**< @brief Vector of input
files/sizes. */
Params& m_params; /**< @brief Global parameters. */
const Params::Size_t m_total_size; /**< Total size of the input items. */
protected:
BinSet* m_solution; /**< Pointer to the best solution found. */
};
// ----------------------------------------------------------------------------
inline std::ostream& operator<<( std::ostream& s, const Optimizer& optimizer )
{
return optimizer.Write( s );
}
// ----------------------------------------------------------------------------
#endif

+ 451
- 0
src/gaffitter/Params.cc

@ -0,0 +1,451 @@
// ---------------------------------------------------------------------
// $Id: Params.cc 235 2008-08-15 20:10:08Z daaugusto $
//
// Params.cc (created on Tue Aug 23 18:48:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------
#include "Params.h"
#include "util/Exception.h"
#include "util/CmdLineParser.h"
#include <sstream>
#include <cmath>
using namespace std;
//---------------------------------------------------------------------
void
Params::ShowVersion() const // --version
{
cout
<< "gaffitter 0.6.0 (Genetic Algorithm File Fitter) (C) 2005-2008\n"
<< "\n"
<< "This is free software. You may redistribute copies of it under the terms\n"
<< "of the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n"
<< "There is NO WARRANTY, to the extent permitted by law.\n"
<< "\n"
<< "Written by Douglas Adriano Augusto (daaugusto).\n";
}
//---------------------------------------------------------------------
void
Params::ShowUsage(const char* app = "gaffitter") const // -h or --help
{
cout
<< "Genetic Algorithm File Fitter (GAFFitter)\n"
<< "\n"
<< "Usage: " << app << " -t target[unit] [options...] <files>\n"
<< " ... | " << app << " - -t target[unit] [options...] [files]\n"
<< "\n"
<< " the unit suffixes 'k', 'm', 'g' or 't' can be used, where:\n"
<< " k = KB/KiB, m = MB/MiB, g = GB/GiB and t = TB/TiB [default = bytes]\n"
<< "\n"
<< "General options:\n"
<< " -t <f>[unit], --target <f>[unit]\n"
<< " target size (mandatory), f>0.0\n"
<< " --si\n"
<< " use powers of 1000 (not 1024) for target, min, max and output sizes\n"
<< " --bins <n>, --vols <n>\n"
<< " maximum number of bins (volumes) [default = \"unlimited\"]\n"
<< " -v, --verbose\n"
<< " verbose\n"
<< " --min <f>[unit], --min-size <f>[unit]\n"
<< " minimum file size [default = none]\n"
<< " --max <f>[unit], --max-size <f>[unit]\n"
<< " maximum file size [default = none]\n"
<< " -B <n>, --block-size <n>\n"
<< " the smallest amount of bytes a file can occupy [default = 1]\n"
<< " --ss, --show-size\n"
<< " print the size of each file\n"
<< " --sb, --show-bytes\n"
<< " also print the sizes in bytes\n"
<< " --hi, --hide-items\n"
<< " don't print the selected items\n"
<< " --hs, --hide-summary\n"
<< " hide summary line containing sum, difference and number of\n"
<< " selected items\n"
<< " -s, --sort-by-size\n"
<< " sort the output by size, not by name\n"
<< " -n, --no-case\n"
<< " use case-insensitive sorting\n"
<< " -r, --sort-reverse\n"
<< " sort the output in reverse order\n"
<< " -z, --null-data\n"
<< " assume NULL (\\0) as the delimiter of input files via stdin (pipe)\n"
<< " -Z, --null\n"
<< " same as --dw '\\0'. See also the -0 and --hs options\n"
<< " -0, --null-bins\n"
<< " same as --bs '\\0'. See also the -Z and --hs options\n"
<< " --bs <char>, --bins-separator <char>\n"
<< " separate bins (vols) with \"char\" [default = newline]\n"
<< " --ew <char>, --enclose-with <char>\n"
<< " enclose file names with \"char\" [default = none]\n"
<< " --dw <char>, --delimit-with <char>\n"
<< " delimit file names (lines) with \"char\" [default = newline]\n"
<< " --version\n"
<< " print GAFFitter version and exit\n"
<< " -h, --help\n"
<< " print this help and exit\n"
<< "\n"
<< "Direct Input options:\n"
<< " --di, --direct-input\n"
<< " switch to direct input mode, i.e., read directly \"size identifier\"\n"
<< " pairs instead of file names\n"
<< " --di-b, --di-bytes\n"
<< " assume input sizes as bytes\n"
<< " --di-k, --di-kb\n"
<< " assume input sizes as kibi bytes (KiB); KB if --di-si\n"
<< " --di-m, --di-mb\n"
<< " assume input sizes as mebi bytes (MiB); MB if --di-si\n"
<< " --di-g, --di-gb\n"
<< " assume input sizes as gibi bytes (GiB); GB if --di-si\n"
<< " --di-t, --di-tb\n"
<< " assume input sizes as tebi bytes (TiB); TB if --di-si\n"
<< " --di-si\n"
<< " use powers of 1000 (not 1024) for input sizes\n"
<< "\n"
<< "Genetic Algorithm options:\n"
<< " --ga-s <n>, --ga-seed <n>\n"
<< " GA initialization seed, n>=0 [default = 1]; 0 = random\n"
<< " --ga-rs, --ga-random-seed\n"
<< " use random GA seed (same as --ga-seed 0)\n"
<< " --ga-ng <n>, --ga-num-generations <n>\n"
<< " maximum number of generations, n>0 [default = auto]\n"
<< " --ga-ps <n>, --ga-pop-size <n>\n"
<< " number of individuals, n>tournament_size [default = auto]\n"
<< " --ga-cp <f>, --ga-cross-prob <f>\n"
<< " crossover probability, 0.0<=f<=1.0 [default = 0.95]\n"
<< " --ga-mp <f>, --ga-mutation-prob <f>\n"
<< " mutation probability, 0.0<=f<=1.0 [default = 0.10]\n"
<< " --ga-sp <n>, --ga-sel-pressure <n>\n"
<< " selection pressure (tournament size), 2<=n<pop_size [default = 2]\n"
<< " --ga-theo [n], --ga-theoretical [n]\n"
<< " stop if the theoretical minimum number of bins is reached. If n is\n"
<< " given, it is assumed to be the theoretical minimum number of bins.\n"
<< "\n"
<< "Other search methods\n"
<< " --ap, --approximate\n"
<< " local approximation using Best Fit search (non-optimal but\n"
<< " very fast)\n"
<< " --sp, --split\n"
<< " just split the input when target size is reached (preserves\n"
<< " original order while splitting)\n";
#if 0
<< " --bf, --brute-force\n"
<< " tries all possible combinations (use carefully!)\n"
#endif
}
//----------------------------------------------------------------------
bool
Params::Initialize()
{
// The 'O' object holds and processes user's input arguments
CmdLine::Parser O( m_argc, m_argv,
CmdLine::SILENT | CmdLine::OUT_OF_RANGE | CmdLine::NO_VALUE );
// Let's declare all possible command-line options
O.Bool.Add("-h","--help");
O.Bool.Add("--version");
O.Bool.Add("-");
O.Bool.Add("--si");
O.Bool.Add("--di","--direct-input");
O.Bool.Add("--di-b","--di-bytes");
O.Bool.Add("--di-k","--di-kb");
O.Bool.Add("--di-m","--di-mb");
O.Bool.Add("--di-g","--di-gb");
O.Bool.Add("--di-t","--di-tb");
O.Bool.Add("--di-si");
O.String.Add( "-t","--target" );
O.Int.Add("--vols","--bins",numeric_limits<int>::max(),1,
numeric_limits<int>::max());
O.String.Add( "--min", "--min-size", "" );
O.String.Add( "--max", "--max-size", "" );
O.Int.Add("-B","--block-size",1,1,numeric_limits<int>::max());
O.Bool.Add("-v","--verbose");
O.Bool.Add("--hi","--hide-items");
O.Bool.Add("--hs","--hide-summary");
O.Bool.Add("--ss","--show-size");
O.Bool.Add("--sb","--show-bytes");
O.Bool.Add("-s","--sort-by-size");
O.Bool.Add("-r","--sort-reverse");
O.Bool.Add("-n","--no-case");
O.Int.Add("--ga-ng","--ga-num-generations",0,0,numeric_limits<int>::max());
O.Int.Add("--ga-ps","--ga-pop-size",0,0,numeric_limits<int>::max());
O.Float.Add("--ga-cp","--ga-cross-prob",0.95,0.0,1.0);
O.Float.Add("--ga-mp","--ga-mutation-prob",0.10,0.0,1.0);
O.Int.Add("--ga-sp","--ga-sel-pressure",0,0,numeric_limits<int>::max());
O.Bool.Add("--ga-rs","--ga-random-seed");
O.Int.Add("--ga-s","--ga-seed",1,0,numeric_limits<long>::max());
O.Bool.Add( "--ga-theo","--ga-theoretical" );
O.Int.Add( "--ga-theo","--ga-theoretical", 0, 1,
numeric_limits<int>::max() ).UnSet( CmdLine::NO_VALUE );
#if 0
O.Bool.Add("--bf","--brute-force");
#endif
O.Bool.Add("--ap","--approximate");
O.Bool.Add("--sp","--split");
O.Bool.Add("-z","--null-data");
O.Bool.Add("-Z","--null");
O.Bool.Add("-0","--null-bins");
O.Char.Add("--dw","--delimit-with",'\n');
O.Char.Add("--ew","--enclose-with",'\0');
O.Char.Add("--bs","--bins-separator",'\n');
// -- Get the options! ----------------
/* Right now, the 'O' object will process the command-line, i.e.,
* it will try to recognize the options and their respective arguments. */
O.Process( m_cmdline_items );
// ------------------------------------
if (O.Bool.Get("-h")) { ShowUsage(); return false; /* exit */ }
if (O.Bool.Get("--version")) { ShowVersion(); return false; /* exit */ }
// input via PIPE: ... | gaffitter - ...
m_pipe = O.Bool.Get("-");
// ---- units
if (O.Bool.Get("--si"))
{
m_unit_symbol='\0';
m_unit_power=1000.0;
}
else
{
m_unit_symbol='i';
m_unit_power=1024.0;
}
// --- manual input (no files)
m_direct_input = O.Bool.Get("--di");
if (m_direct_input)
{
double di_power = O.Bool.Get("--di-si") ? 1000.0 : 1024.0;
// assume input sizes Bytes, KB, MB or GB
if (O.Bool.Get("--di-b")) m_di_factor = 1.0;
else if (O.Bool.Get("--di-k")) m_di_factor = KB(di_power);
else if (O.Bool.Get("--di-m")) m_di_factor = MB(di_power);
else if (O.Bool.Get("--di-g")) m_di_factor = GB(di_power);
else if (O.Bool.Get("--di-t")) m_di_factor = TB(di_power);
else m_no_metric = true; // default to no metric!
}
// ---- Target size (default = none) [mandatory option]
// Bytes, KB, MB or GB for target, min and max size
if( !GetSize( O.String.Get( "-t" ), m_target ) || m_target <= 0.0 )
throw E_NoTarget();
// --- min and max file size
if( !GetSize( O.String.Get( "--min" ), m_min_size ) || m_min_size <= 0.0 )
m_min_size = 0.0;
if( !GetSize( O.String.Get( "--max" ), m_max_size ) || m_max_size <= 0.0 )
m_max_size = numeric_limits<Size_t>::max();
/* if there is a metric (B, KB, etc.) then 'target' needs to be
rounded, because it actually represents bytes. */
if( !m_no_metric )
{
m_target = floor( m_target );
m_min_size = ceil( m_min_size );
m_max_size = floor( m_max_size );
}
// ---- Iterations (default = as much as possible)
m_max_bins = O.Int.Get( "--bins" );
// --- block size
m_block_size = O.Int.Get("-B");
// --- verbose
m_verbose = O.Bool.Get("-v");
// --- hide items (the list of items/files)?
m_hide_items = O.Bool.Get("--hi");
// --- hide summary (last line)?
m_hide_summary = O.Bool.Get("--hs");
// --- show sizes?
m_show_size = O.Bool.Get("--ss");
// --- show bytes?
// showing bytes in direct input mode (with no metric) is no sense.
m_show_bytes = O.Bool.Get("--sb") && !m_no_metric;
// --- sort by size?
m_sort_by_size = O.Bool.Get("-s");
// --- reverse order while sorting?
m_sort_reverse = O.Bool.Get("-r");
// --- case-sensitive or insensitive? (only for "sort by name")
m_no_case = O.Bool.Get("-n");
// ---- Genetic Algorithm ------------------------------------------
/* m_ga_pop_size and m_ga_num_gens are (auto)adjusted in
* Optimizer::Initialize */
// -- Number of generations
m_ga_num_gens = O.Int.Get("--ga-ng"); // check range: done in
// Optimizer::Initialize
// -- Population size
m_ga_pop_size = O.Int.Get("--ga-ps"); // check range: done in
// Optimizer::Initialize
// -- Crossover probability
m_ga_cross_prob = O.Float.Get("--ga-cp");
// -- Mutation probability
m_ga_mut_prob = O.Float.Get("--ga-mp"); // automatic value adjusted
// by GeneticAlgorithm (~1/L)
// -- Selection pressure (currently "tournament size")
m_ga_sel_pressure = O.Int.Get("--ga-sp"); // check range: done in
// Optimizer::Initialize
// -- Initialization seed
if (O.Bool.Get("--ga-rs")) m_ga_seed = 0;
else m_ga_seed = O.Int.Get("--ga-s");
// -- stop the search when the theorical minimum number of bins is
// reached?
m_bins_theo = O.Int.Get( "--ga-theo" );
m_theoretical = O.Bool.Get( "--ga-theo" ) || m_bins_theo > 0;
// ---- Search ----------------------------------------------
#if 0
// --- Brute Force Search. May be very slow ( O(2^|input|) )
m_brute_force = O.Bool.Get("--bf");
#endif
// --- Best First Search (very fast but just approximate)
m_approximate = O.Bool.Get("--ap");
// --- Split "Search"
m_split = O.Bool.Get("--sp");
// --------------------
// Delimit and Enclose options
m_null_data = O.Bool.Get( "-z" );
if( O.Bool.Get( "-Z" ) )
m_delimit_chr = '\0';
else
m_delimit_chr = O.Char.Get( "--dw" ); // default = "\n" (new line)
m_enclose = O.Char.Get( "--ew", m_enclose_chr );
if( O.Bool.Get( "-0" ) )
m_bins_separator = '\0';
else
m_bins_separator = O.Char.Get( "--bs" );
// ---------------
return true;
}
//---------------------------------------------------------------------
std::string
Params::PrettySize(Size_t size) const
{
std::ostringstream o;
if (m_no_metric) // = (m_direct_input && m_no_metric)
{
// just print the size without units
o.precision(16); o << size; return o.str();
}
// format adjust
o << std::fixed;
// module
Size_t positive_bytes = (size < 0.0) ? -size : size;
o.precision(2);
if (positive_bytes >= TB())
o << size/GB() << 'T'<<m_unit_symbol<<'B';
else if (positive_bytes >= GB())
o << size/GB() << 'G'<<m_unit_symbol<<'B';
else if (positive_bytes >= MB())
o << size/MB() << 'M'<<m_unit_symbol<<'B';
else if (positive_bytes >= KB())
o << size/KB() << 'K'<<m_unit_symbol<<'B';
else { o.precision(0); o << size << "Bytes"; }
// print bytes together?
if (m_show_bytes) { o.precision(0); o << " (" << size << ")"; }
return o.str();
}
//---------------------------------------------------------------------
bool
Params::GetSize( const std::string& size_unit, Params::Size_t& value ) const
{
if( size_unit.length() == 0 || !StringToDouble( value, size_unit ) )
return false;
int pos = size_unit.length() - 1;
char unit = size_unit[pos];
// Find the first alphabetic letter, so it is possible to write
// -t 10m or -t 10mb (or -t 10M or -t 10MB)
while( --pos > 0 && isalpha( size_unit[pos] ) ) { unit = size_unit[pos]; }
if( isalpha( unit ) )
switch( tolower( unit ) )
{
case 'k':
return (value *= KB(), true);
case 'm':
return (value *= MB(), true);
case 'g':
return (value *= GB(), true);
case 't':
return (value *= TB(), true);
}
return true;
}
//---------------------------------------------------------------------

+ 215
- 0
src/gaffitter/Params.h

@ -0,0 +1,215 @@
/*
* --- SDE-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* Filename: src/gaffitter/Params.h
* Copyright (C) 2009 The OpenSDE Project
*
* More information can be found in the files COPYING and README.
*
* 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; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- SDE-COPYRIGHT-NOTE-END ---
*/
// ---------------------------------------------------------------------
// $Id: Params.h 229 2008-08-14 00:44:06Z daaugusto $
//
// Params.h (created on Tue Aug 23 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------
#ifndef params_hh
#define params_hh
#include <iostream>
#include <string>
#include <sstream>
#include <list>
#include <limits>
//----------------------------------------------------------------------
/**
* @class Params
*
* @brief This class gets and processes parameters (general and GA-related)
* specified by the user.
*/
class Params {
public:
/**
* @typedef Size_t
*
* @brief For file/item sizes and Score/Evaluate functions.
*
* - double can hold usually a max integer of 2^53 = 8192TiB
* - long double can hold usually a max integer of 2^64 = 16777216TiB :)
* - long int = 2^32 = 4GiB :(
* - long long int = 2^64 = 16777216TiB :), but isn't ANSI C++ :(
*/
typedef double Size_t;
typedef long double BigFloat; /**< big float datatype. */
typedef long long BigInt; /**< big signed int. */
typedef unsigned long long UBigInt; /**< big unsigned int. Must have
at least off_t (from stat.h) bits. */
public:
/**
* @brief Params' constructor.
*/
Params(int& argc, char** argv): m_argc(argc), m_argv(argv),
m_no_metric(false) {}
/**
* Print gaffitter version and exit
*/
void ShowVersion() const;
/**
* Show a brief help text and exit.
*/
void ShowUsage(const char*) const;
/**
* Set gaffitter options from user args.
*/
bool Initialize();
/**
* Print filesizes using Bytes, KiB, MiB or GiB units ("human"
* readable form); KB, MB or GB if '--si' option is set. Also, if
* Gaffitter is using direct input without units then PrettySize will
* just print the raw size (no suffixes).
*
* If --show-bytes is set then PrettySize prints output sizes in
* bytes too (except for direct input without a metric).
*/
std::string PrettySize(Size_t) const;
public:
int& m_argc;
char** m_argv;
/** A list of pointers to characters ("list of strings"). This list
* holds the arguments that could not be identified from the
* command-line (argv). Its values are probably files or item names.
*/
std::list<const char*> m_cmdline_items;
public:
// General options.
Size_t m_target; /**< target in bytes (or just a number if "no metric"). */
Size_t m_min_size, m_max_size; /**< min and max size for the input
files/items. */
unsigned m_max_bins; /**< max number of desired bins (volumes). After the
process finishes, the m_max_bins better filled
bins are printed. */
int m_block_size; /**< the smallest amount of bytes a file can occupy. */
bool m_verbose; /**< switch to verbose mode. */
bool m_pipe; /**< accept input from pipe. */
bool m_hide_items; /**< don't print the selected items. */
bool m_hide_summary; /**< don't print footer summary. */
bool m_show_size; /**< print file size.*/
bool m_show_bytes; /**< also print size in bytes. */
bool m_direct_input; /**< accept "by hand" input (files not required). */
bool m_no_metric; /**< direct input does not require a metric (KB, MB...). */
// Sorting options
bool m_sort_by_size; /**< sort output by size instead of by name. */
bool m_sort_reverse; /**< reverse order while sorting. */
bool m_no_case; /**< ignore case distinctions when sorting. */
bool m_null_data; /**< assumes NULL (\\0) as the delimiter of input files */
char m_bins_separator; /**< char to separate the bins (default = newline) */
char m_enclose_chr; /**< char to enclose the filenames (default = none) */
bool m_enclose; /**< don't print anything if "--ew" was not used */
char m_delimit_chr; /**< char to delimit lines (default = newline) */
// Genetic Algorithm options.
unsigned m_ga_pop_size; /**< Population size */
int m_ga_num_gens; /**< Number of generations */
long m_ga_seed; /**< GA seed */
int m_ga_sel_pressure; /**< Selection pressure */
float m_ga_cross_prob; /**< Crossover probability */
float m_ga_mut_prob; /**< Mutation probability */
bool m_theoretical; /**< stop if the theoretical minimum number
of bins is reached */
unsigned m_bins_theo; /**< holds the theoretical minimum number of bins (can be
entered by the user). It differs from m_max_bins in the
sense that if m_bins_theo is reached, then the process
stops immediately and does not try to optimize (fill
better) the bins. */
// Search options
bool m_approximate; /**< Local approximation using Best First search
(non-optimal but very fast). */
bool m_split; /**< Split "Search" (very fast, but just
split sequentially the input according to target.*/
#if 0
bool m_brute_force; /**< Try all combinations, may be very slow. Not
recommended when |input| > 10. Use carefully! */
#endif
private:
/** XiB ou XB (if SI), where X is K, M or G. */
char m_unit_symbol;
/** power equal 1000 if --si is set; 1024 otherwise. */
float m_unit_power;
// constants
double KB(double power) const { return power; }
double KB() const { return KB(m_unit_power); }
double MB(double power) const { return power*power; }
double MB() const { return MB(m_unit_power); }
/* 1024^3 = 2^30, but 'float' usually supports only 2^24 integer
* numbers without loss (mantissa). However 'double' supports 2^53. */
double GB(double power) const { return power*power*power; }
double GB() const { return GB(m_unit_power); }
double TB(double power) const { return power*power*power*power; }
double TB() const { return TB(m_unit_power); }
public:
/**
* Converts a given string to \ref Size_t, checking for errors.
*/
static bool StringToDouble(Size_t& d, const std::string& s)
{
std::istringstream iss(s); return !(iss >> std::dec >> d).fail();
}
/** Get the correct size for target, min and max values. This
* function already applies the correct factor.
*/
bool GetSize( const std::string&, Size_t& ) const;
double DI_Factor() const { return m_di_factor; }
private:
double m_di_factor; /**< Factor to convert in bytes a size in KB, MB or GB.
(for direct input). */
};
//----------------------------------------------------------------------
#endif

+ 78
- 0
src/gaffitter/README

@ -0,0 +1,78 @@
$Id: README 192 2008-07-14 20:24:37Z daaugusto $
------------------------------------------
Genetic Algorithm File Fitter -- gaffitter
------------------------------------------
http://gaffitter.sourceforge.net/ (home page)
http://sourceforge.net/projects/gaffitter/ (project page)
2005-2008 - Douglas A. Augusto (daaugusto@gmail.com)
== About ==
Genetic Algorithm File Fitter, GAFFitter for short, is a tool based on a
genetic algorithm (GA) that tries to fit a collection of items into as
few as possible volumes of a specific size. For example, the items might
be files and the volumes might be CDs or DVDs. This is called the Bin
Packing Problem, a NP-hard combinatorial problem for which no
deterministic polynomial-time algorithm is known. Using heuristics, such
as GAs, it is usually possible to approximate---and often reach---the
best solution for the problem within a reasonable time.
GAFFitter was created with the intent to minimize the number of CDs or
DVDs used to store a set of files whose total size is greater than the
medium capacity. It was further extended to work directly with any set
of items, whether it is composed of files/directories or not.
GAFFitter is written in C++ and is currently available as a command-line
program for POSIX-compliant systems (GNU/Linux, BSD derivatives and so
on).
== Features ==
GAFFitter is characterized by five main features, namely:
- The global search based on a genetic algorithm.
- The filter-oriented design, that is, a versatile interface suitable
for integration with other tools and front-ends.
- The possibility to bypass filenames as the input and to directly
read a list of items and their sizes.
- The great flexibility provided by the input arguments, which
controls the behaviour of GAFFitter, including many genetic
algorithm parameters.
- The fact that it is a Free Software, which ensures the freedom for
the users to study, change and redistribute GAFFitter.
=== Usage ===
The simplest way to run GAFFitter is as follows:
gaffitter -t 700m *
This command will arrange the files and subdirectories of the current
directory into sets of at most 700 megabytes (a typical CD), in such a
way that the number of sets is minimized. In other words, GAFFitter will
try to fit the given files and directories into as few as possible
volumes of 700MB.
=== More information ===
A comprehensive description of GAFFitter's options and parameters,
several usage examples, and instructions on how to get its source code
can be found on GAFFitter's website at http://gaffitter.sf.net
== License ==
GNU General Public License (GPL) version 3 (or later)
http://www.gnu.org/licenses/gpl.txt

+ 95
- 0
src/gaffitter/gaffitter.cc

@ -0,0 +1,95 @@
// ---------------------------------------------------------------------
// $Id: gaffitter.cc 230 2008-08-14 01:45:04Z daaugusto $
//
// gaffitter.cc (created on Tue Aug 23 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------
#include "Optimizer.h"
#include "optimizers/GeneticAlgorithm.h"
#include "optimizers/BestFit.h"
#include "optimizers/Split.h"
#include "Params.h"
#include "Input.h"
#include "util/Exception.h"
#include "util/CmdLineException.h"
//----------------------------------------------------------------------
int main( int argc, char** argv )
{
try {
// read the options
Params parameters( argc, argv );
// just ShowUsage()?
if( !parameters.Initialize() ) return 0;
// read the filenames
Input input( parameters );
Optimizer* gaffitter = 0;
try {
// create the GA optimizer
if( parameters.m_approximate )
gaffitter = new BestFit( input );
else if( parameters.m_split )
gaffitter = new Split( input );
else
gaffitter = new GeneticAlgorithm( input );
// evolve
gaffitter->Evolve();
// print the results
gaffitter->Output();
}
catch( ... ) {
delete gaffitter;
throw;
}
delete gaffitter;
}
catch( const CmdLine::E_Exception& e ) {
std::cerr << e;
return 1;
}
catch( const E_Exception& e )
{
std::cerr << e;
return 2;
}
catch( const std::exception& e )
{
std::cerr << '\n' << "> Error: " << e.what() << std::endl;
return 3;
}
catch( ... ) {
std::cerr << '\n' << "> Error: " << "An unknown error occurred."
<< std::endl;
return 4;
}
return 0; // ok, no errors
}

+ 82
- 0
src/gaffitter/optimizers/BestFit.cc

@ -0,0 +1,82 @@
// ---------------------------------------------------------------------------
// $Id: BestFit.cc 227 2008-08-13 20:51:32Z daaugusto $
//
// BestFit.cc (created on Sat Nov 19 18:00:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------------
#include "BestFit.h"
#include <vector>
using namespace std;
// ---------------------------------------------------------------------------
void
BestFit::Evolve()
{
if( m_params.m_verbose ) cout << *this;
m_solution = new BinSet();
/* Best Fit Decreasing */
for( unsigned i = 0; i < m_files.size(); ++i )
{
// find the best free bin; insert another bin if necessary
int best_bin = -1;
Params::Size_t best_fit = numeric_limits<Params::Size_t>::max();
for( unsigned j = 0; j < m_solution->Count(); ++j )
{
if( (*m_solution)[j].Free() >= m_files[i]->Size() )
{
if( (*m_solution)[j].Free() - m_files[i]->Size() < best_fit )
{
best_bin = j;
best_fit = (*m_solution)[j].Free() - m_files[i]->Size();
}
}
}
if( best_bin == -1 )
m_solution->AddBin( m_params.m_target ).AddItem( m_files[i] );
else (*m_solution)[best_bin].AddItem( m_files[i] );
}
}
// --------------------------------------------------------------------
ostream&
BestFit::Write( ostream& s ) const
{
s << endl;
s << "> -----------------------------------" << endl;
s << "> Best Fit search (approximate) " << endl;
s << "> -----------------------------------" << endl;
Optimizer::Write( s );
s << endl << flush;
return s;
}
// --------------------------------------------------------------------

+ 85
- 0
src/gaffitter/optimizers/BestFit.h

@ -0,0 +1,85 @@
/*
* --- SDE-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* Filename: src/gaffitter/optimizers/BestFit.h
* Copyright (C) 2009 The OpenSDE Project
*
* More information can be found in the files COPYING and README.
*
* 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; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- SDE-COPYRIGHT-NOTE-END ---
*/
// ---------------------------------------------------------------------
// $Id: BestFit.h 230 2008-08-14 01:45:04Z daaugusto $
//
// BestFit.h (created on Sat Nov 19 18:00:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------
#ifndef BestFit_hh
#define BestFit_hh
#include "../Optimizer.h"
#include <algorithm>
// ---------------------------------------------------------------------
/**
* Optimization via the Best Fit search.
*/
class BestFit: public Optimizer {
public:
/**
* Calls the base constructor and print some information if needed.
*/
BestFit( Input& i ): Optimizer( i )
{
// sorts files by size (reverse order)
std::sort( m_files.begin(), m_files.end(), SizeName::CmpSizeRev );
}
~BestFit() { delete m_solution; }
/**
* Create a reasonable solution via "Best Fit Search", i.e., select
* files from bigger to smaller until no more space left (less than
* target size). This algorithm usually produces locally optimal
* solutions, however, it is very fast!
*/
void Evolve();
protected:
/**
* Writes some information (like algorithm name and parameters) in
* ostream object (usually cout).
*/
std::ostream& Write( std::ostream& ) const;
};
// ---------------------------------------------------------------------
#endif

+ 724
- 0
src/gaffitter/optimizers/GeneticAlgorithm.cc

@ -0,0 +1,724 @@
// ---------------------------------------------------------------------------
// $Id: GeneticAlgorithm.cc 231 2008-08-14 04:51:19Z daaugusto $
//
// GeneticAlgorithm.cc (created on Tue Nov 08 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------------
#include "GeneticAlgorithm.h"
#include <utility>
#include <algorithm>
// ---------------------------------------------------------------------------
/**
* @def RELAXED
* @brief Don't try to optimize each possible permutation of items.
*
* When in RELAXED mode, the DominanceOptimizer will try a single replacement
* from one, two or three random points (items). Currently, defining RELAXED
* gives better score (performance and better optimization) in the benchmarks
* than without defining it.
**/
#define RELAXED
/**
* @def STOP_LOSS_DIVERSITY
* @brief Stop the evolutionary process when the diversity is lost.
*/
// #define STOP_LOSS_DIVERSITY
using namespace std;
// ---------------------------------------------------------------------------
GeneticAlgorithm::GeneticAlgorithm( Input& i ): Optimizer( i ), m_cur_gen( 0 )
{
// Selection pressure [default = 2]
if( m_params.m_ga_sel_pressure <= 2 )
{
m_tournament_size = 2;
Tournament = &GeneticAlgorithm::Tournament2;
}
else // maximum = pop size
{
m_tournament_size = m_params.m_ga_sel_pressure;
Tournament = &GeneticAlgorithm::TournamentN;
}
// Population size and generations are proportionally to ln (natural
// logarithmic) of input size (number of files).
if( m_params.m_ga_pop_size <= m_tournament_size )
m_params.m_ga_pop_size =
max( m_tournament_size + 1,
static_cast<unsigned>( 20 * log( (float) m_files.size() + 1 ) ) );
if( m_params.m_ga_num_gens <= 0 )
m_params.m_ga_num_gens =
static_cast<unsigned>( 50 * log( (float) m_files.size() + 1 ) );
// reserve the correct size of the population
m_individuals.reserve( m_params.m_ga_pop_size );
m_params.m_ga_seed = Random::Seed( m_params.m_ga_seed );
}
// ---------------------------------------------------------------------------
bool
GeneticAlgorithm::Evaluate( Individual& ind )
{
ind.m_fitness = Optimizer::Evaluate( ind.m_genome );
if( ind > m_best_individual )
{
m_best_individual = ind;
if( m_params.m_verbose )
cout << " [Gen " << m_cur_gen << ", bins: " <<
m_best_individual.m_genome.Count() << ", fitness: " <<
m_best_individual.Fitness() << "] " << flush;
}
/* If an individual reached the maximum fitness of 1.0 or if just a
* bin is sufficient to pack all items/files, then returns "true";
* i.e., the termination criterion was satisfied. Also, if "stopping
* when the theoretical minimum number of bins is reached" is specified,
* then stop if this is the case. */
if( ind.m_fitness >= BEST_FITNESS || ind.m_genome.Count() == 1 ||
(m_params.m_theoretical && ind.m_genome.Count() <= m_params.m_bins_theo) )
return m_best_individual = ind, true;
return false;
}
// ---------------------------------------------------------------------------
void
GeneticAlgorithm::FirstFit( BinSet& bins, const vector<const SizeName*>& sn ) const
{
for( unsigned u = 0; u < sn.size(); ++u )
{
// find the first sufficiently free bin; insert another bin if necessary
unsigned i = 0;
for( ; i < bins.Count(); ++i )
{
if( bins[i].Free() >= sn[u]->Size() )
{
bins[i].AddItem( sn[u] );
break;
}
}
// Hmmm, it is necessary to add a new bin
if( i == bins.Count() ) bins.AddBin( m_params.m_target ).AddItem( sn[u] );
}
}
// ---------------------------------------------------------------------------
void
GeneticAlgorithm::FirstFitDecreasing( BinSet& bins, vector<const SizeName*>
&unassigned ) const
{
if( unassigned.empty() ) return;
// sort (descending order) the bin of unused items
sort( unassigned.begin(), unassigned.end(), SizeName::CmpSizeRev );
FirstFit( bins, unassigned );
}
// ---------------------------------------------------------------------------
void
GeneticAlgorithm::Evolve()
{
// print the header
if( m_params.m_verbose ) cout << *this;
// ---- Evolving...
// Initialize the GA population
if( m_params.m_verbose ) cout << "> ";
bool optimum_found = InitPopulation();
while( !optimum_found && m_cur_gen < m_params.m_ga_num_gens )
{
if( m_params.m_verbose ) cout << "." << flush;
optimum_found = Generation();
}
if( m_params.m_verbose ) cout << " <" << endl << flush;
// pick the best and put it in m_solution as a BinSet datatype
m_solution = &m_best_individual.m_genome;
}
// ---------------------------------------------------------------------------
bool
GeneticAlgorithm::InitPopulation()
/* create the individuals by generating permutations and using the
First Fit algorithm. */
{
++m_cur_gen; // the initial population is the first generation
for( unsigned j = 0; j < m_params.m_ga_pop_size; ++j )
{
// Insert a new individual in population (m_individuals)
m_individuals.push_back( Individual() );
// Generate a random permutation of the input items/files
for( unsigned i = 0; i < m_files.size(); ++i )
swap( m_files[i], m_files[Random::Int( 0, m_files.size() - 1 )] );
// Add the above permutation via FirstFit algorithm
FirstFit( m_individuals.back().m_genome, m_files );
// Evaluate (store the fitness) the newly created individual
if( Evaluate( m_individuals.back() ) ) return true;
}
// No optimum solution found yet
return false;
}
// ---------------------------------------------------------------------------
bool
GeneticAlgorithm::Generation()
{
const int MAX_TRIES = 10;
// increment the generation counter
++m_cur_gen;
unsigned i = 0;
while( i < m_individuals.size() )
{
if( Random::Probability( m_params.m_ga_cross_prob ) )
{
// select daddy and mommy and the losers (will be replaced by the children)
int tries = MAX_TRIES;
pair<int,int> dad, mom;
do
{
dad = (this->*Tournament)( 0, m_individuals.size() / 2 - 1 );
mom = (this->*Tournament)( m_individuals.size() / 2, m_individuals.size() - 1 );
}
while( Individuals(dad.first) == Individuals(mom.first) && tries-- > 0 );
// Crossover dad.first and mom.first and put the offspring into
// dad.second and mom.second
if( Crossover( dad.first, mom.first, dad.second, mom.second ) ) return true;
// Mutate the recently generated offspring with probability
// m_params.m_ga_mut_prob
if( Random::Probability( m_params.m_ga_mut_prob ) ) Mutate( dad.second );
if( Random::Probability( m_params.m_ga_mut_prob ) ) Mutate( mom.second );
if( Evaluate( dad.second ) || Evaluate( mom.second ) ) return true;
// Mutate identical children/brothers
tries = MAX_TRIES;
while( tries-- > 0 )
{
if( Individuals(dad.second) == Individuals(dad.first) )
{
if( Mutate(dad.second), Evaluate(dad.second) ) return true;
continue;
}
if( Individuals(mom.second) == Individuals(mom.first) )
{
if( Mutate(mom.second), Evaluate(mom.second) ) return true;
continue;
}
if( Individuals(dad.second) == Individuals(mom.second) )
{
if( Random::Probability( 0.5 ) )
{
if( Mutate( dad.second ), Evaluate( dad.second ) ) return true;
}
else
if( Mutate( mom.second ), Evaluate( mom.second ) ) return true;
continue;
}
break;
}
++++i;
}
else // Reproduction (cloning)
{
// Select a relatively good individual
pair<int,int> sel = (this->*Tournament)( 0, m_individuals.size() - 1 );
// Replace the worst of the tournament by a clone of the winner
m_individuals[sel.second] = m_individuals[sel.first];
// Mutate the clone with probability m_params.m_ga_mut_prob
if( Random::Probability( m_params.m_ga_mut_prob ) )
{
if( Mutate( sel.second ), Evaluate( sel.second ) ) return true;
}
++i;
}
}
return false;
}
// ---------------------------------------------------------------------------
pair<int,int>
GeneticAlgorithm::Tournament2( int from, int to ) const
{
int sel1 = Select( from, to );
int sel2 = Select( from, to, sel1 );
// best and worse index, respectively
if( Fitness(sel1) > Fitness(sel2) )
return make_pair( sel1, sel2 );
else
return make_pair( sel2, sel1 );
}
// ---------------------------------------------------------------------------
pair<int,int>
GeneticAlgorithm::TournamentN( int from, int to ) const
{
vector<pair<Params::Size_t,int> > candidates;
int sel = Select( from, to );
candidates.push_back( make_pair( Fitness( sel ), sel ) );
for( unsigned i = 1; i < m_tournament_size; ++i )
{
sel = Select( from, to, sel );
candidates.push_back( make_pair( Fitness(sel), sel ) );
}
// sort by fitness (more is better)
sort( candidates.begin(), candidates.end() );
// best and worse index, respectively
return make_pair( candidates.back().second, candidates.front().second );
}
// ---------------------------------------------------------------------------
bool
GeneticAlgorithm::Crossover( unsigned dad, unsigned mom,
unsigned child1, unsigned child2 )
{
#ifdef STOP_LOSS_DIVERSITY
static int diversity = m_params.m_ga_pop_size;
#endif
/* 1) Select a crossover region (two points) for each parent */
// Dad's crossover points
pair<unsigned, unsigned> points[] =
{ pair<unsigned, unsigned>( 0, 0 ), pair<unsigned, unsigned>( 0, 0 ) };
unsigned parents[] = { dad, mom };
unsigned children[] = { child1, child2 };
points[0].first = Select( 0, m_individuals[dad].m_genome.Count() - 1 );
points[0].second = Select( 0, m_individuals[dad].m_genome.Count() - 1,
points[0].first );
if( points[0].second < points[0].first )
swap( points[0].first, points[0].second );
// Mom's crossover points
points[1].first = Select( 0, m_individuals[mom].m_genome.Count() - 1 );
points[1].second = Select( 0, m_individuals[mom].m_genome.Count() - 1,
points[1].first );
if( points[1].second < points[1].first )
swap( points[1].first, points[1].second );
for( short unsigned i = 0; i <= 1; ++i ) // 0 = dad, 1 = mom
{
/* 2) Insert dad's genes into the crossover segment of mom
(actually the mom's clone) and vice-versa. The old bins having
elements also belonging to the new bins will be removed and
their elements will be considered 'unassigned'. */
// The temporary bin of unassigned items of unlimited capacity
vector<const SizeName*> unassigned;
// Reset the losers. They will be replaced by the children
m_individuals[children[i]].m_genome.DelAllBins();
// Create the children by cloning Dad and injecting the crossover
// region of Mom--and vice-versa.
for( unsigned j = 0; j < points[i].first; ++j ) // 'j' is the gene index
{
if( !Intersect( m_individuals[parents[i]].m_genome[j],
m_individuals[parents[1 - i]].m_genome.begin() +
points[1 - i].first,
m_individuals[parents[1 - i]].m_genome.begin() +
points[1 - i].second + 1,
unassigned ) )
{
m_individuals[children[i]].m_genome.AddBin(
m_individuals[parents[i]].m_genome[j] );
}
}
// The crossover region of Mom
for( unsigned j = points[1 - i].first; j <= points[1 - i].second; ++j )
// 'j' is the gene index
{
m_individuals[children[i]].m_genome.AddBin(
m_individuals[parents[1 - i]].m_genome[j] );
}
// Cloning the tail of Dad
for( unsigned j = points[i].first;
j < m_individuals[parents[i]].m_genome.Count(); ++j )
{
if( !Intersect( m_individuals[parents[i]].m_genome[j],
m_individuals[parents[1 - i]].m_genome.begin() +
points[1 - i].first,
m_individuals[parents[1 - i]].m_genome.begin() +
points[1 - i].second + 1,
unassigned ) )
{
m_individuals[children[i]].m_genome.AddBin(
m_individuals[parents[i]].m_genome[j] );
}
}
#ifdef STOP_LOSS_DIVERSITY
if( unassigned.empty() )
{
if( --diversity <= 0 ) return true;
}
else diversity = m_params.m_ga_pop_size;
#endif
/* 3) Apply Dominance Optimization */
DominanceOptimizer( m_individuals[children[i]].m_genome, unassigned );
/* 4) Apply First Fit Decreasing */
FirstFitDecreasing( m_individuals[children[i]].m_genome, unassigned );
}
return false; // no stop yet
}
// ---------------------------------------------------------------------------
void
GeneticAlgorithm::Mutate( int ind )
{
#ifdef INVERSION
int p1 = Select( 0, Individuals(ind).Genome().Count() - 1 );
int p2 = Select( 0, Individuals(ind).Genome().Count() - 1, p1 );
swap( Individuals(ind).Genome(p1), Individuals(ind).Genome(p2) );
#endif
// Select a random bin
int bin = Random::Int( 0, Individuals(ind).Genome().Count() - 1 );
// Mark its items as "unassigned"
vector<const SizeName*> unassigned( Individuals(ind).Genome(bin).begin(),
Individuals(ind).Genome(bin).end() );
// Remove the selected bin
Individuals(ind).Genome().DelBin( bin );
// Calls Dominance Optimizer (tries better reallocation)
DominanceOptimizer( Individuals(ind).Genome(), unassigned );
// Apply First Fit Decreasing (reallocate the remaining items)
FirstFitDecreasing( Individuals(ind).Genome(), unassigned );
}
// ---------------------------------------------------------------------------
void
GeneticAlgorithm::DominanceOptimizer( BinSet& bs, vector<const SizeName*>&
unassigned ) const
{
if( unassigned.empty() ) return;
sort( unassigned.begin(), unassigned.end(), SizeName::CmpSizeRev );
bool improved;
do {
improved = false;
for( unsigned i = 0; i < bs.Count(); ++i )
{
if ( bs[i].Count() >= 3 )
improved |= DominanceForThree( bs[i], unassigned );
if ( bs[i].Count() >= 2 )
improved |= DominanceForTwo( bs[i], unassigned );
if ( bs[i].Count() >= 1 )
improved |= DominanceForOne( bs[i], unassigned );
}
} while( improved ); // stop the loop if there is no improvement
}
// ---------------------------------------------------------------------------
int
GeneticAlgorithm::DominanceForOne( Bin& bin,
vector<const SizeName*>& unassigned ) const
{
if( unassigned.empty() ) return 0;
#ifndef RELAXED
int improved = 0;
for( int one = 0; one < bin.Count(); ++one )
{
#else
int one = Select( 0, bin.Count() - 1 );
#endif
for( unsigned j = 0; j < unassigned.size(); ++j )
{
if( unassigned[j]->Size() > bin[one]->Size() )
{
if( unassigned[j]->Size() - bin[one]->Size() <= bin.Free() )
{
const SizeName* tmp_item = unassigned[j];
// remove unassigned[j] item from the vector of unassigned
unassigned.erase( unassigned.begin() + j );
// insert bs[i][0] into unassigned maintaining the sorting order
vector<const SizeName*>::iterator it = lower_bound(
unassigned.begin(), unassigned.end(), bin[one],
SizeName::CmpSizeRev );
unassigned.insert( it, bin[one] );
bin.ReplaceItem( one, tmp_item );
#ifndef RELAXED
++improved;
break;
#else
return 1;
#endif
}
}
else break; // unassigned is sorted
}
#ifndef RELAXED
}
return improved;
#else
return 0;
#endif
}
// ---------------------------------------------------------------------------
int
GeneticAlgorithm::DominanceForTwo( Bin& bin,
vector<const SizeName*>& unassigned ) const
{
if( unassigned.empty() ) return 0;
#ifndef RELAXED
int improved = 0;
for( int one = 0; one < bin.Count() - 1; ++one )
{
for( int two = one + 1; two < bin.Count(); ++two )
{
#else
int one = Select( 0, bin.Count() - 1 );
int two = Select( 0, bin.Count() - 1, one );
if( one > two ) swap( one, two );
#endif
Params::Size_t sum = bin[one]->Size() + bin[two]->Size();
for( unsigned j = 0; j < unassigned.size(); ++j )
{
if( unassigned[j]->Size() >= sum )
{
if( unassigned[j]->Size() - sum <= bin.Free() )
{
const SizeName* tmp_item = unassigned[j];
// remove unassigned[j] item from the vector of unassigned
unassigned.erase( unassigned.begin() + j );
// insert one and two into unassigned maintaining the
// sorting order
vector<const SizeName*>::iterator it = lower_bound(
unassigned.begin(), unassigned.end(), bin[one],
SizeName::CmpSizeRev );
unassigned.insert( it, bin[one] );
it = lower_bound( unassigned.begin(), unassigned.end(), bin[two],
SizeName::CmpSizeRev );
unassigned.insert( it, bin[two] );
// remove one and two from bs
bin.DelItem( two );
bin.DelItem( one );
// assign the fitter item
bin.AddItem( tmp_item );
#ifndef RELAXED
// reset one and two
one = 0; two = 1;
++improved; // it may be very expensive!!!
break;
#else
return 1;
#endif
}
}
else break; // unassigned is sorted
}
#ifndef RELAXED
}
}
return improved;
#else
return 0;
#endif
}
// ---------------------------------------------------------------------------
int
GeneticAlgorithm::DominanceForThree( Bin& bin,
vector<const SizeName*>& unassigned ) const
{
if( unassigned.size() < 2 ) return 0;
#ifndef RELAXED
int improved = 0;
for( int one = 0; one < bin.Count() - 2; ++one )
{
for( int two = one + 1; two < bin.Count() - 1; ++two )
{
for( int three = two + 1; three < bin.Count(); ++three )
{
#else
int one = Select( 0, bin.Count() - 1 );
int two = Select( 0, bin.Count() - 1, one );
int three = Select( 0, bin.Count() - 1, one, two );
if( one > two ) swap( one, two );
if( two > three) swap( two, three );
if( one > two ) swap( one, two );
#endif
Params::Size_t sum = bin[one]->Size() + bin[two]->Size() + bin[three]->Size();
for( unsigned j = 0; j < unassigned.size() - 1; ++j )
{
for( unsigned k = j + 1; k < unassigned.size(); ++k )
{
Params::Size_t sum_u = unassigned[j]->Size() + unassigned[k]->Size();
if( sum_u >= sum )
{
if( sum_u - sum <= bin.Free() )
{
const SizeName* tmp_item_j = unassigned[j];
const SizeName* tmp_item_k = unassigned[k];
// remove items from the vector unassigned
unassigned.erase( unassigned.begin() + k );
unassigned.erase( unassigned.begin() + j );
// insert one, two and three into unassigned maintaining the
// sorting order
vector<const SizeName*>::iterator it = lower_bound(
unassigned.begin(), unassigned.end(), bin[one],
SizeName::CmpSizeRev );
unassigned.insert( it, bin[one] );
it = lower_bound( unassigned.begin(), unassigned.end(), bin[two],
SizeName::CmpSizeRev );
unassigned.insert( it, bin[two] );
it = lower_bound( unassigned.begin(), unassigned.end(), bin[three],
SizeName::CmpSizeRev );
unassigned.insert( it, bin[three] );
// remove one and two from bs
bin.DelItem( three );
bin.DelItem( two );
bin.DelItem( one );
// assign the fitter item
bin.AddItem( tmp_item_j );
bin.AddItem( tmp_item_k );
#ifndef RELAXED
// reset the variables
one = 0; two = 1; three = 2;
++improved;
break;
#else
return 1; // juste one improvement
#endif
}
} else break; // unassigned is sorted
}
break;
}
#ifndef RELAXED
}
}
}
return improved;
#else
return 0;
#endif
}
// ---------------------------------------------------------------------------
ostream&
GeneticAlgorithm::Write( ostream& s ) const
{
s << "\n> -----------------------------------"
<< "\n> Genetic Algorithm (steady-state)"
<< "\n> -----------------------------------"
<< "\n> Max number of generations: " << m_params.m_ga_num_gens
<< "\n> Population size: " << m_params.m_ga_pop_size
<< "\n> Crossover probability: " << m_params.m_ga_cross_prob
<< "\n> Mutation probability: " << m_params.m_ga_mut_prob
<< "\n> Tournament size: " << m_tournament_size
<< "\n> Seed: " << m_params.m_ga_seed
<< endl;
Optimizer::Write( s );
s << flush << endl;
return s;
}
// ---------------------------------------------------------------------------

+ 379
- 0
src/gaffitter/optimizers/GeneticAlgorithm.h

@ -0,0 +1,379 @@
/*
* --- SDE-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* Filename: src/gaffitter/optimizers/GeneticAlgorithm.h
* Copyright (C) 2009 The OpenSDE Project
*
* More information can be found in the files COPYING and README.
*
* 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; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- SDE-COPYRIGHT-NOTE-END ---
*/
// ---------------------------------------------------------------------------
// $Id: GeneticAlgorithm.h 230 2008-08-14 01:45:04Z daaugusto $
//
// GeneticAlgorithm.h (created on Tue Nov 08 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------------
#ifndef GeneticAlgorithm_hh
#define GeneticAlgorithm_hh
#include "../Input.h"
#include "../util/Random.h"
#include "../Optimizer.h"
#include <vector>
#include <iterator>
static const Params::Size_t WORST_FITNESS = 0.0;
static const Params::Size_t BEST_FITNESS = 1.0;
// ---------------------------------------------------------------------------
/**
* @class Individual
*
* @brief This class represents an Individual, i.e., an entity representing a
* candidate solution.
*
* Basically, an Individual holds a particular set of bins, where each bin is
* a collection of items.
*/
class Individual {
public:
/**
* @brief Create the individual with the worst possible fitness. */
Individual(): m_fitness( WORST_FITNESS ) {}
/**
* @brief Returns the individual's fitness. */
Params::Size_t Fitness() const { return m_fitness; }
/**
* @brief Sets the individual's fitness */
void Fitness( Params::Size_t f ) { m_fitness = f; }
/**
* @brief Compare two individuals.
*
* First the fitness is compared; if they are equal, then compare their
* genomes.
*/
bool operator==( const Individual& i ) const
{
if( !AlmostEqual( Fitness(), i.Fitness() ) ) return false;
return Genome() == i.Genome();
}
/**
* @brief Compare the fitness of two individuals.
*/
friend bool operator>( Individual &a, Individual &b )
{
return a.m_fitness > b.m_fitness;
}
/**
* @brief Returns the individual's genome ( set of bins ).
*/
BinSet& Genome() { return m_genome; }
/**
* @brief Returns the individual's genome ( set of bins ); const version.
*/
const BinSet& Genome() const { return m_genome; }
/**
* @brief Returns the individual's ith genome (a bin).
*/
Bin& Genome(int i) { return m_genome[i]; }
/**
* @brief Returns the individual's ith genome (a bin); const version.
*/
const Bin& Genome(int i) const { return m_genome[i]; }
public:
BinSet m_genome; /**< The genome is the genetic material (i.e.,
chromosomes) of an individual */
Params::Size_t m_fitness; /**< The individual's fitness. */
};
// ---------------------------------------------------------------------------
/**
* @class GeneticAlgorithm
*
* @brief This class implements a Genetic Algorithm system as search algorithm.
*
* This implementation is based on Falkenauer's HGGA (Hybrid Grouping Genetic
* Algorithm).
*
* In the HGGA, the genes represent each one a group of items, i.e., each gene
* is treated as a bin and their items act as an unit, a building block;
* therefore, the crossover operator does not mixes items on an individual
* basis, but, rather, it combines groups of bins. Besides, HGGA uses a local
* optimizer inspired on the Dominance Criterion of Martello and Toth, which
* basically tries iteratively to replace a few items of a certain bin by
* fewer items that fit better in. This procedure not only optimizes the bin,
* but also eases the reallocation of the replaced items, since smaller items
* are easier to fit.
*
* Reference:
*
* A Hybrid Grouping Genetic Algorithm for Bin Packing
* http://citeseer.ist.psu.edu/falkenauer96hybrid.html
*/
class GeneticAlgorithm: public Optimizer {
public:
/**
* If not specified, the constructor will automatically adjust population
* size and number of generations. The Random::Seed is also set.
*/
GeneticAlgorithm( Input& );
private:
/** Copies are not allowed. */
GeneticAlgorithm( const GeneticAlgorithm& );
/** Attributions are not allowed. */
GeneticAlgorithm& operator=( const GeneticAlgorithm& );
public:
/**
* @brief Genetic Algorithm search.
*
* GA searches for optimal (though not guaranteed) solutions by means of
* Darwinian evolution.
*/
void Evolve();
/**
* @brief Evaluate an individual.
*/
bool Evaluate( int i ) { return Evaluate( m_individuals[i] ); }
/**
* @brief Evaluate an individual.
*/
bool Evaluate( Individual& );
protected:
/**
* Create the population of individuals and put it in \ref m_individuals
*
* As usually in GA, the creation of individuals is basically a random
* process. For each individual a new permutation over the m_files is
* generated and then those randomized items are inserted via the First Fit
* algorithm.
*/
bool InitPopulation();
/**
* Runs the GA for one generation. Returns true if a perfect fit was found;
* or the stop criterion was reached; false otherwise.
*
* A perfect fit occurs when either (1) just one bin is suffice to pack all
* files; or (2) an individual reaches the maximum fitness (1.0).
*/
bool Generation();
/** Just for notation convenience. */
Params::Size_t Fitness( int index ) const
{
return Fitness( m_individuals[index] );
}
/**
* Returns how well is the given individual. The objective is to maximize
* its fitness.
*/
Params::Size_t Fitness( const Individual& i ) const { return i.Fitness(); }
/** Select in [a,b] a random individual. */
int Select( int a, int b ) const { return Random::Int( a, b ); }
/** Select in [a,b] a random individual 'r' not equal 'p'. */
int Select( int a, int b, int p ) const
{
int r = Select( a, b );
// equals?
if( r == p ) return r > a ? r - 1 : a + 1;
return r; // Ok: 'b' not equal 'a'!
}
/** Select in [a,b] a random individual 'r' not equal 'p1' and 'p2'
* Required: b - a > 2
* */
int Select( int a, int b, int p1, int p2 ) const
{
int r = Select( a, b );
if( p1 > p2 ) std::swap( p1, p2 );
if( r == p1 )
{
if( p1 == a ) return p1 + 1 == p2 ? r + 2 : r + 1;
if( p1 > a ) return r - 1;
}
if( r == p2 )
{
if( p2 == b ) return p2 == p1 + 1 ? r - 2 : r - 1;
if( p2 < b ) return r + 1;
}
return r;
}
/**
* @brief Promotes the crossover between two individuals, generating two children.
*
* Basically, the crossover involves:
* -# Selecting crossover points (sections) on both parents.
* -# Inserting the crossover section of a parent into the crossover
* section of the another parent, and vice-versa. Actually, this is done
* on the children, so the parents' genomes remain intact.
* -# After the insertion procedure, likely some old bins of the children
* will contain items that were again inserted by the new bins that came
* from the crossover section of the other parent. Thus, those old bins
* containing duplicate items will be removed and their items (just the
* non-duplicates) will be marked as "unassigned".
* -# Finally, the DominanceOptimizer is applied in order to try to
* reallocate the unassigned bins. The remaining items--i.e., those that
* could not be reallocated--will be inserted on children via
* FirstFitDecreasing method.
*/
bool Crossover( unsigned, unsigned, unsigned, unsigned );
/**
* @brief Mutate the ith individual.
*
* The mutation operator removes a random bin, makes its items "unassigned",
* calls @ref DominanceOptimizer to try to better reallocate those items and
* finally insert the remaining unassigned items via @ref FirstFitDecreasing.
*/
void Mutate( int i );
/**
* Choose an individual via tournament (need 2 or more competitors). This
* is a two-competitor optimized version.
*
* @sa TournamentN()
*/
std::pair<int,int> Tournament2( int, int ) const;
/**
* Choose an individual via tournament (need 2 or more competitors).
* This is a three+ competitor version.
*
* @sa Tournament2()
*/
std::pair<int,int> TournamentN( int, int ) const;
/**
* Pointer to @ref Tournament2() or @ref TournamentN(), depending on
* the tournament size.
*/
std::pair<int,int> (GeneticAlgorithm::*Tournament)( int, int ) const;
/**
* @brief Returns the ith individual.
*/
Individual& Individuals( int i ) { return m_individuals[i]; }
/**
* @brief Returns the ith individual; const version.
*/
const Individual& Individuals( int i ) const { return m_individuals[i]; }
/**
* @brief Returns the vector of individuals.
*/
std::vector<Individual>& Individuals() { return m_individuals; }
/**
* @brief Returns the vector of individuals; const version.
*/
const std::vector<Individual>& Individuals() const { return m_individuals; }
std::vector<Individual> m_individuals; /**< The population (vector) of
individuals. */
Individual m_best_individual; /**< The best individual so far. */
public:
/**
* @brief Allocate items via FirstFit Algorithm.
*
* The FirstFit algorithm fit a given item into the first bin able to
* accommodate it.
*/
void FirstFit( BinSet&, const std::vector<const SizeName*>& ) const;
/**
* @brief Allocate items via FirstFitDecreasing Algorithm.
*
* The FirstFitDecreasing algorithm first sort in descending order the
* given list of items and then pass this sorted list to @ref FirstFit.
*/
void FirstFitDecreasing( BinSet&, std::vector<const SizeName*>& ) const;
/**
* @brief Try to reallocate items via Dominance Criterion.
*
* Basically, the DominanceOptimizer algorithm tries to replace smaller
* items with bigger (possibility fitter) items. It tries iteratively to
* replace a few items of a certain bin by fewer items that fit better in.
* This procedure not only optimizes the bin, but also eases the
* reallocation of the replaced items, since smaller items are easier to
* fit.
*/
void DominanceOptimizer( BinSet& bs, std::vector<const SizeName*>&
unassigned ) const;
private:
/**
* @brief Tries to replace one item per time via Dominance Optimizer.
*/
int DominanceForOne( Bin& bin, std::vector<const SizeName*>&
unassigned ) const;
/**
* @brief Tries to replace two items per time via Dominance Optimizer.
*/
int DominanceForTwo( Bin& bin, std::vector<const SizeName*>&
unassigned ) const;
/**
* @brief Tries to replace three items per time via Dominance Optimizer.
*/
int DominanceForThree( Bin& bin, std::vector<const SizeName*>&
unassigned ) const;
protected:
/**
* Writes some information (like algorithm name and parameters) in
* ostream object (usually cout).
*/
std::ostream& Write( std::ostream& ) const;
private:
int m_cur_gen; /**< Current generation. */
unsigned m_tournament_size; /**< Tournament size. */
};
// ---------------------------------------------------------------------------
#endif

+ 73
- 0
src/gaffitter/optimizers/Split.cc

@ -0,0 +1,73 @@
// ---------------------------------------------------------------------------
// $Id: Split.cc 227 2008-08-13 20:51:32Z daaugusto $
//
// Split.cc (created on Fri Aug 4 12:59:27 BRT 2006)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------------
#include "Split.h"
#include <vector>
using namespace std;
// ---------------------------------------------------------------------------
void
Split::Evolve()
{
if( m_params.m_verbose ) cout << *this;
m_solution = new BinSet();
m_solution->AddBin( m_params.m_target );
int bin = 0;
for( unsigned i = 0; i < m_files.size(); ++i )
{
if( (*m_solution)[bin].Free() >= m_files[i]->Size() )
{
(*m_solution)[bin].AddItem( m_files[i] );
}
else
{
m_solution->AddBin( m_params.m_target ).AddItem( m_files[i] ); ++bin;
}
}
}
// ---------------------------------------------------------------------------
ostream&
Split::Write( ostream& s ) const
{
s << endl;
s << "> -----------------------------------" << endl;
s << "> Split \"search\" " << endl;
s << "> -----------------------------------" << endl;
Optimizer::Write( s );
s << endl << flush;
return s;
}
// ---------------------------------------------------------------------------

+ 76
- 0
src/gaffitter/optimizers/Split.h

@ -0,0 +1,76 @@
/*
* --- SDE-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* Filename: src/gaffitter/optimizers/Split.h
* Copyright (C) 2009 The OpenSDE Project
*
* More information can be found in the files COPYING and README.
*
* 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; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- SDE-COPYRIGHT-NOTE-END ---
*/
// ---------------------------------------------------------------------
// $Id: Split.h 230 2008-08-14 01:45:04Z daaugusto $
//
// Split.h (created on Fri Aug 4 12:59:27 BRT 2006)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------
#ifndef Split_hh
#define Split_hh
#include "../Optimizer.h"
// ---------------------------------------------------------------------
/**
* Split an input into pieces
*/
class Split: public Optimizer {
public:
/**
* Calls the base constructor and prints some information if needed.
*/
Split( Input& i ): Optimizer( i ) {}
~Split() { delete m_solution; }
/**
* Just splits the input (in original order) according to target size,
* i.e., select file by file until fit the specified volume.
*/
void Evolve();
protected:
/**
* Writes some information (like algorithm name and parameters) in
* ostream object (usually cout).
*/
std::ostream& Write( std::ostream& ) const;
};
// ---------------------------------------------------------------------
#endif

+ 211
- 0
src/gaffitter/util/CmdLineException.h

@ -0,0 +1,211 @@
/*
* --- SDE-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* Filename: src/gaffitter/util/CmdLineException.h
* Copyright (C) 2009 The OpenSDE Project
*
* More information can be found in the files COPYING and README.
*
* 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; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- SDE-COPYRIGHT-NOTE-END ---
*/
// ---------------------------------------------------------------------
// $Id: CmdLineException.h 79 2008-08-10 15:58:07Z daaugusto $
//
// CmdLineException.h (created on Tue Aug 23 01:08:35 BRT 2005)
//
// Command-line Parser
//
// Copyright (C) 2006-2008 Douglas Adriano Augusto (daaugusto)
//
// This file is part of Command-line Parser.
//
// Command-line Parser is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// Command-line Parser 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 Command-line Parser; if not, see <http://www.gnu.org/licenses/>.
//
// ------------------------------------------------------------------------
#ifndef cmdline_exception_h
#define cmdline_exception_h
#include <string>
#include <sstream>
#include <limits>
#include <exception>
#include <list>
namespace CmdLine {
class E_Exception;
//----------------------------------------------------------------------
/**
* Exception base class.
*/
class E_Exception: std::exception {
public:
/**
* Create an exception with an optional message "L" and an
* error message "M".
*/
E_Exception( const std::string& L = "", const std::string& M = "" )
: m_msg( M ), m_loc( L ) {}
virtual ~E_Exception() throw() {};
/**
* Return the user message.
*/
virtual const char* local() { return m_loc.c_str(); }
/**
* Return the error message.
*/
virtual const char* what() const throw() { return m_msg.c_str(); }
protected:
std::string m_msg; /**< The error message. */
std::string m_loc; /**< Optional message, such as the name of the
function where throw was called. */
};
//----------------------------------------------------------------------
inline std::ostream&
operator<<( std::ostream& o, const E_Exception& e )
{
o << '\n' << "> Error: " << e.what() << std::endl;
return o;
}
//-----------------------------------------------------------------------------
/**
* When a Max value is smaller than a given Min value.
*
* Usage: if (max<min) throw E_MaxMin<type>(min, max,"optional text");
*/
template<class T> class E_MaxMin : public E_Exception {
public:
E_MaxMin (T min, T max, const std::string& loc = "")
{
std::ostringstream o;
o << loc << "'max' (" << max << ") smaller than 'min' (" << min << ")"
<< ", feasible range: ["<< std::numeric_limits<T>::min() << ":"
<< std::numeric_limits<T>::max() << "]";
m_msg = o.str();
}
};
//-----------------------------------------------------------------------------
/**
* When a value is not provided or it is incompatible
*
* Usage: throw E_NoValue("option");
*/
class E_NoValue : public E_Exception {
public:
E_NoValue( const std::string& loc = "" )
{
std::ostringstream o;
o << loc << ": a value was not provided or it is incompatible.";
m_msg = o.str();
}
};
//-----------------------------------------------------------------------------
/**
* When a value is out of a defined range.
*
* Usage: throw E_OutOfRange<type>(min, max,"optional text");
*/
template<class T> class E_OutOfRange : public E_Exception {
public:
E_OutOfRange (T value, T min, T max, const std::string& loc = "")
{
std::ostringstream o;
o << loc << ": value " << value << " is out of range"
<< ", feasible range: ["<< min << ":"
<< max << "]";
m_msg = o.str();
}
};
//-----------------------------------------------------------------------------
/**
* When a value is out of a defined range.
*
* Usage: throw E_OutOfRange<string>("value", m_range, "arg" );
*/
template< > class E_OutOfRange<std::string> : public E_Exception {
public:
E_OutOfRange<std::string>( const std::string& value, const
std::list<std::string>& range, const std::string& arg = "" )
{
std::ostringstream o;
std::list<std::string>::const_iterator it = range.begin();
o << arg << ": value '" << value << "' is out of range. Allowed values:";
while( it != range.end() ) o << " '" << *it++ << "'";
m_msg = o.str();
}
};
//-----------------------------------------------------------------------------
/**
* When a value is out of a defined range.
*
* Usage: throw E_OutOfRange<char>("value", m_range, "arg" );
*/
template< > class E_OutOfRange<char> : public E_Exception {
public:
E_OutOfRange<char>( const char* value, const char* range,
const std::string& arg = "" )
{
std::ostringstream o;
o << arg << ": value '" << value << "' is out of range. Allowed values:";
for( int i = 0; range[i] != '\0'; ++i ) { o << " '" << range[i] << "'"; }
m_msg = o.str();
}
};
//-----------------------------------------------------------------------------
/**
* When a option is declared twice (or more) times.
*
* Usage: throw E_Duplicate( "option" );
*/
class E_Duplicate: public E_Exception {
public:
E_Duplicate( const std::string& loc = "" )
{
std::ostringstream o; o << loc << ": duplicate option.";
m_msg = o.str();
}
};
//-----------------------------------------------------------------------------
} // end namespace scope
//-----------------------------------------------------------------------------
#endif

+ 396
- 0
src/gaffitter/util/CmdLineParser.cc

@ -0,0 +1,396 @@
// ------------------------------------------------------------------------
// $Id: CmdLineParser.cc 226 2008-08-05 08:40:14Z daaugusto $
//
// CmdLineParser.cc (created on Tue Aug 8 11:01:58 BRT 2006)
//
// Command-line Parser
//
// Copyright (C) 2006-2008 Douglas Adriano Augusto (daaugusto)
//
// Command-line Parser is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// Command-line Parser 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 Command-line Parser; if not, see <http://www.gnu.org/licenses/>.
//
// ------------------------------------------------------------------------
#include <iostream>
#include <algorithm>
#include <cstdarg> // for va_list, va_star, and va_end
#include "CmdLineParser.h"
using namespace CmdLine;
// ---------------------------------------------------------------------------
Option<INT>&
OptionsINT::Add( const std::string& name, const std::string& alias, INT def,
INT min, INT max )
{
if( max < min ) throw E_MaxMin<INT>( min, max, "Option " + name + ": " );
// calls the base Add function
return OptionsType<INT>::Add( name, alias, def, min, max ).
Flags( m_parser.m_flags );
}
// ---------------------------------------------------------------------------
Option<FLOAT>&
OptionsFLOAT::Add( const std::string& name, const std::string& alias,
FLOAT def, FLOAT min, FLOAT max )
{
if( max < min ) throw E_MaxMin<FLOAT>( min, max, "Option " + name + ": " );
// calls the base Add function
return OptionsType<FLOAT>::Add( name, alias, def, min, max ).
Flags( m_parser.m_flags );
}
// ---------------------------------------------------------------------------
Option<char>&
OptionsCHAR::Add( const std::string& name, const std::string& alias, char def,
const char* range, bool include_null_char )
{
m_ranges[name] = std::pair<const char*, bool>(range, include_null_char);
// calls the base Add function
return OptionsType<char>::Add( name, alias, def ).Flags( m_parser.m_flags );
}
// ---------------------------------------------------------------------------
Option<std::string>&
OptionsSTRING::Add( const std::string& name, const std::string& alias,
std::string def, const char* first, ... )
{
std::list<std::string> range;
if( first ) // check if a list of strings was provided
{
const char* str;
va_list vl;
str = first;
va_start( vl, first );
do
{
range.push_back( std::string( str ) );
str = va_arg( vl, const char* );
} while( str != NULL ); // don't work with Zero (0), use NULL
va_end(vl);
}
if( !range.empty() ) m_ranges[name] = range;
// calls the base Add function
return OptionsType<std::string>::Add( name, alias, def ).
Flags( m_parser.m_flags );
}
// ---------------------------------------------------------------------------
bool
OptionsINT::Match( int& i, char** argv, int argc )
{
// try to find
Option<INT>* p = Find( argv[i] );
if( p ) // found in the database of options OptionsType.m_opts
{
// try to convert the option arg to 'int'
if( i + 1 < argc )
{
std::istringstream s( argv[i + 1] ); INT tmp;
if( !(s >> std::dec >> tmp).fail() ) // ok, successful conversion
{
/* This is a special case. Although the provided value could
* be converted to an integer type, if the value is real
* (float) and there is a FLOAT option with the same name,
* then we ignore it and the function returns false, i.e.,
* "that option was not found in the database of options". */
if( std::string( argv[i + 1] ).find( '.' ) != std::string::npos &&
m_parser.Float.Find( argv[i] ) )
return false;
/* If argv[i] is duplicate, check if we may continue. If not, dis-
* card its argument (++i) and return true (found, but ignored).*/
if( !CheckDuplicate( p, argv[i] ) ) { ++i; return true; }
p->m_found = true; /* an useful/complete option (it has correct value)
found in the command-line. */
if( tmp >= p->m_min && tmp <= p->m_max )
p->m_value = tmp;
else {
if( p->IsSet( OUT_OF_RANGE ) )
throw E_OutOfRange<INT>( tmp, p->m_min, p->m_max, argv[i] );
if( !p->IsSet( SILENT ) )
std::cerr << "> [Ignoring] Option '" << argv[i] <<
"': value out of range." << std::endl;
}
// if used then "eat the argument"
++i;
// ok, there was used tmp or the default value
return true;
}
}
/* Option found in command-line, but was a compatible value found
* either? */
if( !p->m_found && p->IsSet( NO_VALUE ) ) throw E_NoValue( argv[i] );
}
return false;
}
// ---------------------------------------------------------------------
bool
OptionsFLOAT::Match( int& i, char** argv, int argc )
{
// try to find
Option<FLOAT>* p = Find( argv[i] );
if( p ) // found in the database of options OptionsType.m_opts
{
// try to convert the option arg to 'FLOAT'
if( i + 1 < argc )
{
std::istringstream s( argv[i + 1] ); FLOAT tmp;
if( !(s >> std::dec >> tmp).fail() ) // ok, successful conversion
{
/* If argv[i] is duplicate, check if we may continue. If not, dis-
* card its argument (++i) and return true (found, but ignored).*/
if( !CheckDuplicate( p, argv[i] ) ) { ++i; return true; }
p->m_found = true;
// Check the range
if( tmp >= p->m_min && tmp <= p->m_max )
p->m_value = tmp;
else {
if( p->IsSet( OUT_OF_RANGE ) )
throw E_OutOfRange<FLOAT>( tmp, p->m_min, p->m_max, argv[i] );
if( !p->IsSet( SILENT ) )
std::cerr << "> [Ignoring] Option '" << argv[i] <<
"': value out of range." << std::endl;
}
// if used then "eat the argument"
++i;
return true;
}
}
/* Option found in command-line, but was a compatible value found
* either? */
if( !p->m_found && p->IsSet( NO_VALUE ) ) throw E_NoValue( argv[i] );
}
return false;
}
// ---------------------------------------------------------------------
bool
OptionsBOOL::Match( int& i, char** argv, int argc )
{
/* A minus sign ("-") after the option name disable the previous one,
i.e.: -d- disables -d if -d was already declared. */
std::string tmp( argv[i] ); bool disable = false;
if( tmp.size() > 1 && tmp[tmp.size() - 1] == '-' )
{
disable = true; tmp.erase(tmp.end() - 1);
}
Option<bool>* p = Find( tmp );
if( p ) // found!
{
/* If argv[i] is duplicate, check if we may continue. If not,
* return true (found, but ignored).*/
if( !CheckDuplicate( p, argv[i] ) ) return true;
p->m_found = true;
p->m_value = disable ? false : true;
return true;
}
return false;
}
// ---------------------------------------------------------------------
bool
OptionsCHAR::Match( int& i, char** argv, int argc )
{
Option<char>* p = Find( argv[i] );
if( p ) { // found!
if( i + 1 < argc )
{
/* If argv[i] is duplicate, check if we may continue. If not, dis-
* card its argument (++i) and return true (found, but ignored).*/
if( !CheckDuplicate( p, argv[i] ) ) { ++i; return true; }
char default_value = p->m_value;
// accept only if has one character or two (if the first is
// a backslash)
if( argv[i + 1][0] == '\0' || argv[i+1][1] == '\0')
{
p->m_value = argv[i+1][0];
p->m_found = true;
}
else if( argv[i + 1][0] == '\\' && argv[i + 1][2] == '\0' )
{
switch( argv[i + 1][1] ) {
case '0' : p->m_value = '\0'; break;
case 'a' : p->m_value = '\a'; break;
case 'b' : p->m_value = '\b'; break;
case 'f' : p->m_value = '\f'; break;
case 'n' : p->m_value = '\n'; break;
case 'r' : p->m_value = '\r'; break;
case 't' : p->m_value = '\t'; break;
case 'v' : p->m_value = '\v'; break;
case '\\': p->m_value = '\\'; break;
default : p->m_value = argv[i+1][1]; break;
}
p->m_found = true;
}
if( p->m_found )
{
std::map<std::string, std::pair<const char*, bool> >
::iterator it = m_ranges.find( argv[i] );
/*
* it->second: pair<const char*, bool>
* it->second.first: const char* [ range of valid chars ]
* it->second.second: bool [ if \0 is also a valid char ]
*/
// A valid set of values was provided?
if( it != m_ranges.end() && it->second.first )
{
bool in_range = false;
for( int j = 0; (it->second.first)[j] != '\0'; ++j )
{
if( p->m_value == (it->second.first)[j] )
{
in_range = true;
break;
}
}
// Include the null char as a valid one?
if( it->second.second ) in_range |= p->m_value == '\0';
if( !in_range ) // p->m_value not in it
{
if( p->IsSet( OUT_OF_RANGE ) )
throw E_OutOfRange<char>( argv[i + 1], it->second.first, argv[i] );
if( !p->IsSet( SILENT ) )
std::cerr << "> [Ignoring] Option '" << argv[i] <<
"': value out of range." << std::endl;
// restore the default value
p->m_value = default_value;
}
}
++i; // if used then "eat the argument"
return true;
}
}
/* Option found in command-line, but was a compatible value found
* either? */
if( p->IsSet( NO_VALUE ) ) throw E_NoValue( argv[i] );
}
return false;
}
// ---------------------------------------------------------------------
bool
OptionsSTRING::Match( int& i, char** argv, int argc )
{
// try to find
Option<std::string>* p = Find( argv[i] );
if( p ) // found!
{
if( i + 1 < argc )
{
/* If argv[i] is duplicate, check if we may continue. If not, dis-
* card its argument (++i) and return true (found, but ignored).*/
if( !CheckDuplicate( p, argv[i] ) ) { ++i; return true; }
p->m_found = true;
// check if a range was given for the option argv[i]
std::map<std::string, std::list<std::string> >
::iterator it = m_ranges.find( argv[i] );
// verify if a range has specified and if argv[i + 1] is in range
if( it != m_ranges.end() &&
find( it->second.begin(), it->second.end(),
std::string( argv[i + 1] ) ) == it->second.end() )
{
if( p->IsSet( OUT_OF_RANGE ) )
throw E_OutOfRange<std::string>( argv[i + 1], it->second,
argv[i] );
if( !p->IsSet( SILENT ) )
std::cerr << "> [Ignoring] Option '" << argv[i] <<
"': value out of range." << std::endl;
}
else p->m_value = std::string( argv[i + 1] );
// if used then "eat the argument"
++i;
return true;
}
/* Option found in command-line, but was a value found either? */
if( !p->m_found && p->IsSet( NO_VALUE ) ) throw E_NoValue( argv[i] );
}
return false;
}
// ---------------------------------------------------------------------
int
Parser::Process()
{
int matched = 0;
for( int i = 1; i < m_argc; ++i )
{
if( !strcmp( m_argv[i], "--" ) ) break; // "--" stops the option processing
if( m_argv[i][0] == '-' && ( Int.Match( i, m_argv, m_argc ) ||
Float.Match( i, m_argv, m_argc ) || Bool.Match( i, m_argv, m_argc ) ||
Char.Match( i, m_argv, m_argc ) || String.Match( i, m_argv, m_argc )) )
{
++matched;
}
}
return matched;
}
// ---------------------------------------------------------------------

+ 889
- 0
src/gaffitter/util/CmdLineParser.h

@ -0,0 +1,889 @@
/*
* --- SDE-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* Filename: src/gaffitter/util/CmdLineParser.h
* Copyright (C) 2009 The OpenSDE Project
*
* More information can be found in the files COPYING and README.
*
* 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; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- SDE-COPYRIGHT-NOTE-END ---
*/
// ---------------------------------------------------------------------------
// $Id: CmdLineParser.h 232 2008-08-15 18:19:35Z daaugusto $
//
// CmdLineParser.h (created on Tue Aug 8 11:01:58 BRT 2006)
//
// Command-line Parser
//
// Copyright (C) 2006-2008 Douglas Adriano Augusto (daaugusto)
//
// Command-line Parser is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// Command-line Parser 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 Command-line Parser; if not, see <http://www.gnu.org/licenses/>.
//
// ------------------------------------------------------------------------
#ifndef cmd_line_parser_h
#define cmd_line_parser_h
/** @file CmdLineParser.h
*
* Reads and extracts options/args from the command-line (via argv/argc).
*
Example:
@code
int main( int argc, char** argv )
{
CmdLine::Parser Opts( argc, argv );
// declaring a boolean option with an alias (optional)
Opts.Bool.Add( "-h", "--help" );
// an integer option (without alias) with default, min and max values
Opts.Int.Add( "-n","",5, 0, 10 );
// a float (float/double/long double) option
Opts.Float.Add( "--float", "--float-option" ,1.0, -10.0, 10.0 );
// a char option that specifies a set of valid characters
Opts.Char.Add( "--letter", "", "A", "abcABC" );
// a string option
Opts.String.Add( "-s", "--string-option", "default string" );
// another string option, but it specifies a range of values
Opts.String.Add( "--rgb-color", "", "red", "red", "green" ,"blue", NULL );
// ...
// it will contain the unrecognized options/arguments
vector<const char*> remains;
// processing the command-line
Opts.Process( remains );
// getting the results!
if (Opts.Bool.Get("-h")) cout << "-h is set" << endl;
if (!Opts.Int.Found("-n"))
cout << "-n not declared, using default." << endl;
int integer = Opts.Int.Get("-n");
cout << "Value for '-n': " << integer << " As short int: "
<< Opts.Int.Get<short int>("-n") << endl;
cout << "Value for '-s': " << Opts.String.Get("-s") << endl;
// ...
cout << "\nUnrecognized arguments:" << endl;
list<const char*>::const_iterator ci = remains.begin();
while (ci != remains.end()) cout << *ci++ << endl;
}
@endcode
For the code above, for example:
@verbatim
$ ./a.out -h --string-option "abc" item1 item2
-h is set
-n not declared, using default.
Value for '-n': 5
Value for '-s': abc
Unrecognized arguments:
item1
item2
@endverbatim
Other features:
@li A command-line with '--' makes the remaining parameters "unrecognized"
a priori, i.e., stops the searching/processing for options.
@li Using an option with a minus sign after the name cancels the previous
declaration (if any). For instance, '-x-' (or '--blahblah-') turns off
the previous declaration of '-x' (or '--blahblah').
@li If an option is declared two or more times, the last is used.
@li 'Char' options allow special characters such as '\\0', '\\n', etc.
*/
/**
* @page page1 Command-line Parser: General Documentation
There are four steps for a complete parsing of the command-line
arguments:
-# Initialization (@ref sec1)
-# Options inclusion (@ref sec2)
-# The parsing itself (@ref sec3)
-# Getting the values of the options (@ref sec4)
@section sec1 Initialization
In the initialization phase it is given to parser two variables: (1)
an integer indicating the @e number of strings (tokens) provided; (2)
the <tt>char** argv</tt>, containing a null-terminated list of
strings (the command-line itself). There are two ways to call the
@ref CmdLine::Parser constructor:
@code
CmdLine::Parser Opts( argc, argv );
@endcode
that creates the parser object Opts over the command-line argv.
Also, one could pass some flags:
@code
CmdLine::Parser Opts( m_argc, m_argv, CmdLine::SILENT |
CmdLine::OUT_OF_RANGE | CmdLine::NO_VALUE );
@endcode
The possible flags are:
- @b NONE just an alias to zero (0). To be used as Flags( CmdLine::NONE )
in order to clear the current flags.
- @b SILENT if set don't print warning messages to cerr (stderr).
- @b OUT_OF_RANGE throw a fatal exception (@ref CmdLine::E_OutOfRange)
when a value is out of a certain range provided by the user. If not
set, then the @b default value (provided by the user) is used when
a argument value is out of range.
- @b NO_VALUE throw a fatal exception (@ref CmdLine::E_NoValue) when no
value is found for an option that requires argument. If not set, that
option will be @b ignored and considered not found (Found() will return
false).
- @b DUPLICATE throw an error when an option is declared twice (or more)
times in command-line.
- @b FIRSTONLY pick up the first declaration only (discards all duplicates).
@section sec2 Declaring the Options
An user may specify five types of option: @b boolean (Bool), @b integer (Int),
@b float (Float), @b char (Char), and @b string (String) options.
The basic declaration format is: <tt>Object.<type>.Add( "--option-name" )</tt>.
For instance:
@code
Opts.Bool.Add( "-h" );
@endcode
will declare a boolean option labeled @c "-h". You can also create an alias
for an option:
@code
Opts.Bool.Add( "-h", "--help" );
@endcode
so the following two command-lines are equivalent:
@verbatim
program -h
program --help
@endverbatim
For the @e integer and @e float options it is possible to provide a default
value and a range of accepted values (min and max). For example:
@code
Opts.Int.Add( "-age", "", 18, 10, 65 );
Opts.Float.Add( "-f", "--float", 3.14, -1.0, numeric_limits<float>::max() );
@endcode
will declare an option labeled @c -age with no alias, default value @c 18,
minimum value @c 10 and maximum allowed value @c 65. Analogically, a float
option @c -f/--float is declared with a maximum value defined as the maximum
value supported by a primitive float type.
The @b Char and @b String options go further allowing the specification,
respectively, of a set of valid characters or strings. For instance, the
code:
@code
Opts.Char.Add( "-c", "", 'a', "abcXYZ\n" );
@endcode
declares an option '-c' with default value 'a' and allows one of 'a', 'b',
'c', 'X', 'Y', 'Z', and '\\n' chars. If the user gives a value not in this
valid set, the default value 'a' is used or an exception out of range is
thrown (if @c OUT_OF_RANGE is set).
The String type uses a slightly different mode:
@code
Opts.String.Add( "-s", "", "low", "low", "high", NULL );
@endcode
In the above declaration, the valid values for -s are "low" and "high";
the default is "low".
@attention Since that version of the Add function allows variable
number of arguments, the keyword @b NULL is required in order to
close the list of valid strings. An unexpected error will be caused
if you forget that.
Also, one can specify custom flags to each option. E.g.:
@code
// Adding flags (use the operator | to add more than one at a time):
Opts.Int.Add( "-i", "--int" ).Set( CmdLine::NO_VALUE );
// Unsetting flags:
Opts.Int.Add( "-i", "--int" ).UnSet( CmdLine::NO_VALUE );
// Reseting default flags and adding specific ones:
Opts.Int.Add( "-i", "--int" ).Flags( CmdLine::SILENT | CmdLine::NO_VALUE );
// Reseting all default flags:
Opts.Int.Add( "-i", "--int" ).Flags( CmdLine::NONE );
@endcode
@section sec3 Parsing
The parsing is done by the @ref Parser::Process() function. It searches the
command-line, store the values of the arguments of each declared option and
finally returns the number of found (matched) options.
If the user wants to access the unrecognized options--like filenames--, it
is possible to pass a STL container as argument of Process(), e.g.:
@code
vector<string> residue;
Opts.Process( residue ); // will fill residue with the unrecognized tokens
@endcode
One could also @c char* and <tt>const char*</tt> instead of @c
string. Moreover, Process( T& ), being a template function, will
accept any container provided that it implements @c clear() and @c
push_back() member functions.
@section sec4 Getting the Values
Finally, the processed values of the arguments of the options can be
accessed by the Get() function. Also, finding out whether an
option was found or not may be useful; this can be achieved by the function
Found( "option label" ). Consider the examples below:
@code
if( Opts.Bool.Get( "-h" ) ) { ShowHelp(); return; }
// If not provided by the user, it returns the default value
int age = Opts.Int.Get( "-age" );
// Alternative mode
int age;
bool found = Opts.Int.Get( "-age", age );
if( found )
cout << "The age is: " << age;
else
cout << "-age option not provided."
// Still, if the user just needs to know whether an option was
// provided on the command-line:
if( Opts.Int.Found( "-age" ) ) cout << "Age not specified."
@endcode
*/
#include <string>
#include <sstream>
#include <list>
#include <limits>
#include <map>
#include <cstring>
#include "CmdLineException.h"
// ---------------------------------------------------------------------
namespace CmdLine {
/** Default type for the <b>float</b> options */
typedef long double FLOAT;
/** Default type for the <b>integer</b> options */
typedef long INT;
/** @enum */
enum { NONE = 0, /**< Alias to zero (0) */
SILENT = 1, /**< if set, don't print warnings to stderr. */
OUT_OF_RANGE = 2, /**< Throw an out of range exception if an
option value is out of its defined range. */
NO_VALUE = 4, /**< Throw an error when an option is found
in command-line but its value is either
incompatible or unspecified. */
DUPLICATE = 8, /**< Throw an error when an option is declared twice
(or more) times in command-line. */
FIRSTONLY = 16 /**< Pick up the first declaration only (discards all
duplicates). */
};
// ---------------------------------------------------------------------
/**
* Holds the current value, min and max values for an option.
*/
template<class T> class Option {
public:
Option( T def, T min, T max )
: m_value( def ), m_min( min ), m_max( max ),
m_found( false ), m_has_alias( false ), m_flags( 0 ) {}
public:
T m_value, /**< Current value (the last encountered) for the option. */
m_min, /**< Minimum allowed value (only for numerical types).*/
m_max; /**< Maximum allowed value (only for numerical types).*/
bool m_found; /**< @c true if the option was provided on the
command-line; @c false otherwise. */
public:
/** @brief Check if one or more flags are set.
*
* @param flag The flag to be checked. To check for more than one flag at a
* time, use the operator @b | (or).
* @return @c true if @c flag is set; @c false otherwise.
**/
bool IsSet( unsigned flag ) const { return m_flags & flag; }
/** @brief Set one or more flags.
*
* @param flag The flag to be set. To set more than one flag at a time, use
* the operator @b | (or).
* @return The current object @c Option<T>.*/
Option<T>& Set( unsigned flag ) { return m_flags |= flag, *this; }
/** @brief Unset one or more flags.
*
* @param flag The flag to be unset. To unset more than one flag at a time,
* use the operator @b | (or).
* @return The current object @c Option<T>.*/
Option<T>& UnSet( unsigned flag ) { return m_flags &= ~flag, *this; }
/** @brief Reset the current flags and set new ones.
*
* @param flag The flag to be set. To set more than one flag at a time, use
* the operator @b | (or).
* @return The current object @c Option<T>.*/
Option<T>& Flags( unsigned flag ) { return m_flags = flag, *this; }
public:
/**
* Indicate if this option has an alias. Used to avoid double free
* corruption during memory deallocation.
*
* @see OptionsType::~OptionsType()
*/
bool m_has_alias;
private:
unsigned m_flags; /**< Custom flags for this option. Currently may hold
NONE, SILENT, OUT_OF_RANGE and NO_VALUE flags */
};
// ---------------------------------------------------------------------
/**
* Base class for the five types of options: Bool, Integer, Float, Char
* and String.
*/
template <class T> class OptionsType {
public:
/**
* @param[in] parser Reference to the Parser object that owns this
* OptionsType object.
*/
OptionsType( const class Parser& parser ): m_parser( parser ) {}
/**
* Just for maintaining the code clean.
*/
typedef typename std::map<std::string, void*>::const_iterator CI;
/**
* Add an option into @ref m_opts, checking for errors. Actually
* m_opts holds just the name/alias (sorted), which then link to an
* Option<T> object:
*
* @verbatim
...
[name_option_1] ------> | Option<T> |
... / | object |
[alias_option_1] ----/ (values of
... option_1)
@endverbatim
*/
Option<T>& Add(const std::string& name, const std::string& alias="",
T def=T(), T min=T(), T max=T() )
{
CheckOption( name, alias );
void* tmp = new Option<T>( def, min, max );
m_opts[name] = tmp;
if( alias.size() > 0 ) // was provided an alias?
{
m_opts[alias] = tmp;
static_cast<Option<T>*>( tmp )->m_has_alias = true;
}
return *static_cast<Option<T>*>( tmp );
}
/**
* Return the value of option 's'. If 's' is not found in
* command-line (or not in range [min:max]) then @c default value
* is returned.
*
* @param[in] s The option's label
* @return The option's value
*/
T Get( const std::string& s ) const
{
const Option<T>* p = Find( s ); if( p ) return p->m_value;
throw E_Exception("","Option "+s+" does not exist");
}
/**
* Overloaded version of Get( const std::string& ) that puts the
* option argument value in the given parameter @c value and returns
* true if option @c s was provided on the command-line; false
* otherwise.
*
* @param[in] s The option's label/name
* @param[out] value The option's value
* @return true if matched; false otherwise
*/
bool Get( const std::string& s, T& value ) const
{
const Option<T>* p = Find( s );
if( p ) {
value = p->m_value;
return p->m_found;
}
throw E_Exception("","Option "+s+" does not exist");
}
/**
* Simplified interface to perform casting. At times it is necessary
* to convert a INT (possibly "long int") into 'short int', for
* instance.
*/
template<class C> C Get( const std::string& s ) const
{
return static_cast<C>( Get( s ) );
}
/** Same as above but it returns both the option's value and if the
* option was found on the command-line. */
template<class C> bool Get( const std::string& s, C& value ) const
{
const Option<T>* p = Find( s );
if( p ) {
value = static_cast<C>( p->m_value );
return p->m_found;
}
throw E_Exception("","Option "+s+" does not exist");
}
/**
* Returns true if the option specified as 's' was found in
* command-line parameters. Returns false otherwise.
*
* @attention It isn't recommended to call Found() followed by Get()
* because doing so two calls to Find() are being performed. Instead,
* prefer to use bool Get( const std::string&, T& ), in which just a
* single call to Find() is performed.
*/
bool Found( const std::string& s ) const
{
const Option<T>* p = Find( s ); if( p ) return p->m_found;
throw E_Exception("","Option "+s+" does not exist");
}
public:
/** This reference provides access to Parser member
* objects/variables. Passing a reference to Parser is
* preferable to declaring its member objects as static.
*/
const class Parser& m_parser;
protected:
/**
* Memory deallocation for Option<T> objects. First checks if the
* object has two shared references (when an alias is used), making
* sure that only one reference (pointer) will be deleted.
*/
virtual ~OptionsType()
{
for( CI p = m_opts.begin(); p != m_opts.end(); ++p )
{
if( Cast(p)->m_has_alias ) { Cast(p)->m_has_alias = false; continue; }
delete Cast(p);
}
}
/**
* Make sure that an option name/alias begins with minus sign.
*/
void CheckOption( const std::string& name, const std::string& alias ) const
{
if( name[0] != '-' )
throw E_Exception( "","Invalid option name: '"+name+"'" );
if( alias.size() > 0 && alias[0] != '-' )
throw E_Exception( "","Invalid option alias: '"+alias+"'" );
}
/**
* Performs a static_cast from a void pointer, returning the
* correct type of option.
*/
Option<T>* Cast( CI p ) const { return static_cast<Option<T>*>(p->second); }
/**
* Try to find an option 's' and returns its pointer. The binary
* search--provided by std::map--is used.
*/
Option<T>* Find( const std::string& s ) const
{
CI p = m_opts.find(s); return p != m_opts.end() ? Cast(p) : 0;
}
/**
* @brief Check if an option was declared before.
*
* @param p Pointer to option to be checked
* @param opt Option's name
* @return @c true if one should accept the option; @c false otherwise.
*
* If flag @c DUPLICATE is set then a fatal exception is thrown if the option
* was declared before. If flag @c FIRSTONLY is set then the function
* returns @c false indicating that this duplicate declaration is to be
* ignored.
*/
bool CheckDuplicate( const Option<T>* p, const std::string opt ) const
{
if( p->m_found ) // already declared before?
{
if( p->IsSet( DUPLICATE ) ) throw E_Duplicate( opt );
if( !p->IsSet( SILENT ) )
std::cerr << "> Option '" << opt
<< "' was declared more than once.\n";
return !p->IsSet( FIRSTONLY );
}
return true; // ok, not declared before
}
private:
/**
* Database of options of type T (Bool, Int, Float, Char or String).
* STL 'map' object provides fast search via 'binary search'.
*/
std::map<std::string, void*> m_opts;
};
class Parser;
// ---------------------------------------------------------------------
/**
* Integer options.
*/
class OptionsINT: public OptionsType<INT> {
public:
OptionsINT( const Parser& parser ): OptionsType<INT>( parser ) {}
Option<INT>& Add( const std::string&, const std::string& = "",
INT = 0, INT = std::numeric_limits<INT>::min(),
INT = std::numeric_limits<INT>::max() );
/**
* Try to identify an integer option in command-line and then add it
* (together its int argument) into @ref m_opts.
*/
bool Match( int&, char**, int );
};
// ---------------------------------------------------------------------
/**
* Float options.
*/
class OptionsFLOAT: public OptionsType<FLOAT> {
public:
OptionsFLOAT( const Parser& parser ): OptionsType<FLOAT>( parser ) {}
Option<FLOAT>& Add( const std::string&, const std::string& = "",
FLOAT = 0.0, FLOAT = std::numeric_limits<FLOAT>::min(),
FLOAT = std::numeric_limits<FLOAT>::max() );
/**
* Try to identify a float option in command-line and then add it
* (together its float argument) into @ref m_opts.
*/
bool Match( int&, char**, int );
/** Class OptionsINT needs to access OptionsFLOAT::Find() in order to
* check if there exists a FLOAT option with the same name. */
friend bool OptionsINT::Match( int&, char**, int );
};
// ---------------------------------------------------------------------
/**
* Boolean options.
*/
class OptionsBOOL: public OptionsType<bool> {
public:
OptionsBOOL( const Parser& parser ): OptionsType<bool>( parser ) {}
/**
* Try to identify a bool option in command-line and then add it
* into @ref m_opts.
*/
bool Match( int&, char**, int );
};
// ---------------------------------------------------------------------
/**
* Char options.
*/
class OptionsCHAR: public OptionsType<char> {
public:
OptionsCHAR( const Parser& parser ): OptionsType<char>( parser ) {}
/** This function allows a certain range of chars (null terminated
* string) to be specified. If the found value doesn't match one of
* these chars, then the default value is used.
*
* @param[in] name The option's label
* @param[in] alias The option's alias
* @param[in] def The option's default value
* @param[in] range An array of characters that defines the set of
* allowed chars
* @param[in] include_null_char If the NULL char is one of the
* allowed values of the option, set this parameter to @c true
*
* Example usage:
*
* @code
* Bool.Add("-c", "--char", 'a", "abc");
* @endcode
*
* In this example the default char is 'a' and the allowed chars are
* 'a', 'b' and 'c'. If the user gives, for instance, '--char d',
* then Bool.Get("-c") will return 'a' rather than 'd'.
*
* If you want to add the NULL char (\\0) as a valid value, then calls
* Bool.Add as follows:
*
* @code
* Bool.Add("-c", "--char", 'a", "abc", true);
* @endcode
*/
Option<char>& Add( const std::string&, const std::string& = "", char =
'\0', const char* = 0, bool = false );
/**
Try to identify a char option in command-line and then add it
(together its char argument) into @ref m_opts.
Some input combinations are interpreted as special characters:
@verbatim
\0 = null byte
\a = bell character
\b = backspace
\f = formfeed
\n = newline
\r = carriage return
\t = horizontal tab
\v = vertical tab
\\ = backslash
@endverbatim
*/
bool Match( int&, char**, int );
private:
std::map<std::string, std::pair<const char*, bool> > m_ranges;
};
// ---------------------------------------------------------------------
/**
* String options.
*/
class OptionsSTRING: public OptionsType<std::string> {
public:
OptionsSTRING( const Parser& parser ): OptionsType<std::string>( parser ) {}
/**
* @attention Do not forget to end the sequence with @b NULL. For
* instance:
*
* @code
* String.Add( "-s", "--str", "name1", "name2", NULL );
* @endcode
*/
Option<std::string>& Add( const std::string&, const std::string& = "",
std::string = "", const char* first = 0, ... );
/**
* Try to identify a string option in command-line and then add it
* (together its string argument) into @ref m_opts.
*/
bool Match( int&, char**, int );
private:
std::map<std::string, std::list<std::string> > m_ranges;
};
// ---------------------------------------------------------------------
/**
* The user interface for the command-line parser.
*/
class Parser {
public:
/**
* Starts the command-line parser.
*
* @param[in] argc The number of tokens in the command-line
* @param[in] argv The array of string of tokens (in fact, the command-line)
* @param[in] flags Flags controlling the behaviour of the Parser
* regarding verbosity, out of range occurrences and absence of
* values for options requiring arguments (@ref CmdLine::SILENT,
* CmdLine::OUT_OF_RANGE, and CmdLine::NO_VALUE)
*/
Parser( int argc, char** argv, unsigned flags = 0 ):
Int( *this ), Float( *this ), Bool( *this ), Char( *this ),
String( *this ), m_argc( argc ), m_argv( argv ), m_flags( flags )
{ }
/**
* After added all options then this function process the command-line
* parameters searching for options and their arguments.
*
* @return The number of matched options
*/
int Process();
/**
* This version of Process() accepts a container of 'const char*',
* 'char*' or 'string' type that will holds the remaining command-line
* tokens, i.e, those that do not matched.
*
* For example:
*
* @code
* (...)
* vector<string> remaining;
*
* int matched = Opts.Process( remaining );
*
* vector<string>::const_iterator ci = remaining.begin();
*
* cout << "\nMatched: " << matched << " Unrecognized: " << remaining.size();
* cout << "\nUnrecognized arguments:\n";
* while( ci != remaining.end() ) cout << *ci++ << endl;
* @endcode
*
* @warning The container must provide the clear() and push_back()
* functions.
*/
template<class T> int Process( T& );
/** @brief Check if one or more flags are set.
*
* @param flag The flag to be checked. To check for more than one flag at a
* time, use the operator @b | (or).
* @return @c true if @c flag is set; @c false otherwise.
**/
bool IsSet( unsigned flag ) const { return m_flags & flag; }
/** @brief Set one or more flags.
*
* @param flag The flag to be set. To set more than one flag at a time, use
* the operator @b | (or).
* @return The current object @c Parser.*/
Parser& Set( unsigned flag ) { return m_flags |= flag, *this; }
/** @brief Unset one or more flags.
*
* @param flag The flag to be unset. To unset more than one flag at a time,
* use the operator @b | (or).
* @return The current object @c Parser.*/
Parser& UnSet( unsigned flag ) { return m_flags &= ~flag, *this; }
/** @brief Reset the current flags and set new ones.
*
* @param flag The flag to be set. To set more than one flag at a time, use
* the operator @b | (or).
* @return The current object @c Parser.*/
Parser& Flags( unsigned flag ) { return m_flags = flag, *this; }
public:
class OptionsINT Int; /**< A database of integer options. */
class OptionsFLOAT Float; /**< A database of float options. */
class OptionsBOOL Bool; /**< A database of boolean options. */
class OptionsCHAR Char; /**< A database of char options. */
class OptionsSTRING String; /**< A database of string options. */
friend class OptionsINT;
friend class OptionsFLOAT;
friend class OptionsBOOL;
friend class OptionsCHAR;
friend class OptionsSTRING;
private:
int m_argc; /**< Number of command-line "tokens". */
char** m_argv; /**< The "command-line" (pointer to) itself. */
unsigned m_flags; /**< Currently may hold SILENT, OUT_OF_RANGE and
NO_VALUE flags */
};
// ---------------------------------------------------------------------
template<class T> int Parser::Process( T& remains )
{
remains.clear(); int i = 1, matched = 0;
while( i < m_argc )
{
if( !strcmp( m_argv[i], "--" ) ) break; // "--" stops the option processing
if( m_argv[i][0] == '-' && ( Int.Match( i, m_argv, m_argc ) ||
Float.Match( i, m_argv, m_argc ) || Bool.Match( i, m_argv, m_argc ) ||
Char.Match( i, m_argv, m_argc ) || String.Match( i, m_argv, m_argc )) )
{
++matched;
}
else remains.push_back( m_argv[i] ); // not a valid option
++i;
}
// only if encountered "--": do not process the remaining
while( ++i < m_argc ) { remains.push_back( m_argv[i] ); }
return matched;
}
// ---------------------------------------------------------------------
} // end namespace CmdLine
// ---------------------------------------------------------------------
#endif

+ 129
- 0
src/gaffitter/util/Exception.h

@ -0,0 +1,129 @@
/*
* --- SDE-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* Filename: src/gaffitter/util/Exception.h
* Copyright (C) 2009 The OpenSDE Project
*
* More information can be found in the files COPYING and README.
*
* 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; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- SDE-COPYRIGHT-NOTE-END ---
*/
// ---------------------------------------------------------------------
// $Id: Exception.h 227 2008-08-13 20:51:32Z daaugusto $
//
// Exception.h (created on Tue Aug 23 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------
#ifndef exception_hh
#define exception_hh
#include <string>
#include <sstream>
#include <exception>
//----------------------------------------------------------------------
#ifdef NDEBUG
const bool debug = false;
#else
const bool debug = true;
#endif
class E_Exception;
//----------------------------------------------------------------------
/**
* Exception base class.
*/
class E_Exception: std::exception {
public:
/**
* Create an exception with an optional message "L" and an
* error message "M".
*/
E_Exception(const std::string& L = "", const std::string& M = "")
: m_msg( M ), m_loc( L ) {}
virtual ~E_Exception() throw() {};
/**
* Return the user message.
*/
virtual const char * local() { return m_loc.c_str(); }
/**
* Return the error message.
*/
virtual const char * what() const throw() { return m_msg.c_str(); }
protected:
std::string m_msg; /**< The error message. */
std::string m_loc; /**< Optional message, such as the name of the
function where throw was called. */
};
//----------------------------------------------------------------------
inline std::ostream&
operator<<( std::ostream& o, const E_Exception& e )
{
o << '\n' << "> Error: " << e.what() << std::endl;
return o;
}
//-----------------------------------------------------------------------------
class E_NoInputFiles : public E_Exception {
public:
E_NoInputFiles ( const std::string& loc = "" )
: E_Exception (loc, "No input to process") {};
};
//-----------------------------------------------------------------------------
class E_BigInput : public E_Exception {
public:
E_BigInput ( const std::string& loc = "" )
: E_Exception (loc, "Too many input files/items") {};
};
//-----------------------------------------------------------------------------
class E_NoTarget : public E_Exception {
public:
E_NoTarget (const std::string& app = "gaffitter"): E_Exception ("",
"Missing '--target' (Try '"+app+" -h' for more information)") {};
};
//-----------------------------------------------------------------------------
template<class X, class A> inline void Assert(A expression)
{
if (debug && !expression) throw X();
}
inline void Assert(bool expression)
{
Assert<E_Exception>(expression);
}
//-----------------------------------------------------------------------------
#endif

+ 109
- 0
src/gaffitter/util/Random.h

@ -0,0 +1,109 @@
/*
* --- SDE-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* Filename: src/gaffitter/util/Random.h
* Copyright (C) 2009 The OpenSDE Project
*
* More information can be found in the files COPYING and README.
*
* 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; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- SDE-COPYRIGHT-NOTE-END ---
*/
// ---------------------------------------------------------------------
// $Id: Random.h 156 2008-06-08 07:13:49Z daaugusto $
//
// Random.h (created on Tue Nov 08 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter 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 gaffitter; if not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------
#ifndef random_hh
#define random_hh
#include <cstdlib>
#include <cmath>
#include <ctime>
// ---------------------------------------------------------------------
/**
* Simple random number generator (based on standard rand() function).
*/
class Random {
public:
/** Sets the random seed. (0 = "random") */
static unsigned long Seed(unsigned long seed = 0L)
{
srand(seed = (seed == 0L) ? time(NULL) : seed);
return seed;
}
/** Uniform random [0:RAND_MAX] */
static unsigned long Int() { return rand(); }
/** Uniform random (integer) [a:b] */
static long Int(long a, long b)
{
return a + static_cast<long>( Int()*(b-a+1.0) / (RAND_MAX+1.0) );
}
/** Uniform random (real) [a:b] */
static double Real(double a=0.0, double b=1.0)
{
return a + Int()*(b-a) / RAND_MAX;
}
/* Non Uniform Random Numbers
*
* 'weight = 1': uniform distribution between 'a' and 'b' [a,b]
* 'weight > 1': non uniform distribution towards 'a'
* 'weight < 1': non uniform distribution towards 'b'
*/
/** Non-uniform. Integer version [a,b) */
static long NonUniformInt(double weight, long a, long b)
{
return static_cast<long>(pow(Real(0.0, 1.0), weight) * (b-a) + a);
}
/** Non-uniform. Float version */
static double NonUniformReal(double weight, double a=0.0, double b=1.0)
{
return pow(Real(0.0, 1.0), weight) * (b-a) + a;
}
/** Probability ("flip coin"): [0% = 0.0 and 100% = 1.0] */
static bool Probability(double p)
{
if (p <= 0.0) return false;
if (p >= 1.0) return true;
return (Real(0.0,1.0) < p) ? true : false;
}
};
// --------------------------------------------------------------------
#endif

Loading…
Cancel
Save