Migration from SVN

This commit is contained in:
quemy 2012-08-30 11:30:11 +02:00
commit 8cd56f37db
61 changed files with 0 additions and 4096888 deletions

340
eo/contrib/mathsym/COPYING Normal file
View file

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View file

@ -0,0 +1,101 @@
COMPILEFLAGS=-Wno-deprecated -g -Wall -mpreferred-stack-boundary=2 -falign-functions=0#-DINTERVAL_DEBUG
OPTFLAGS= #-O3 -DNDEBUG
PROFILE_FLAGS=#-pg
LDFLAGS=#-a
INCLUDES=-I. -Isym -Ifun -Igen -Ieval -Iregression -I../../src -Ieo_interface -I..
CPPFLAGS=$(COMPILEFLAGS) $(OPTFLAGS) $(INCLUDES) $(PROFILE_FLAGS) -D__I386__ -DSIZEOF_UNSIGNED_LONG=4
EXTLIBS=tcc/libtcc.a tcc/libtcc1.a ../../src/libeo.a ../../src/utils/libeoutils.a
LIBS=${EXTLIBS} -ldl
SYMLIB=libsym.a
VPATH=sym fun gen eval regression eo_interface
CXXSOURCES=FunDef.cpp Sym.cpp SymImpl.cpp SymOps.cpp sym_compile.cpp TreeBuilder.cpp LanguageTable.cpp\
Dataset.cpp ErrorMeasure.cpp Scaling.cpp TargetInfo.cpp BoundsCheck.cpp util.cpp NodeSelector.cpp\
eoSymCrossover.cpp sym_operations.cpp eoSymMutate.cpp eoSymLambdaMutate.cpp MultiFunction.cpp
TESTPROGRAMS=test/test_compile test/testeo test/test_simplify test/test_diff test/test_lambda test/test_mf test/test_interval
OBJS= $(CXXSOURCES:.cpp=.o) c_compile.o
all: tcc/ symreg
include $(CXXSOURCES:.cpp=.d) symreg.d
clean:
rm *.o *.d $(TESTPROGRAMS) $(SYMLIB) symreg test/*.o || true
distclean: clean
rm -rf tcc
symreg: libsym.a symreg.o $(EXTLIBS)
$(CXX) -o symreg symreg.o libsym.a $(LIBS) $(PROFILE_FLAGS) ${LDFLAGS}
libsym.a: $(OBJS)
rm libsym.a; ar cq $(SYMLIB) $(OBJS)
check: $(TESTPROGRAMS)
test/test_compile && test/test_interval && test/testeo && test/test_simplify && test/test_diff && test/test_lambda && echo "all tests succeeded"
test/test_compile: test/test_compile.o ${SYMLIB}
$(CXX) -o test/test_compile test/test_compile.o $(SYMLIB) ${LIBS}
test/testeo: test/testeo.o ${SYMLIB}
$(CXX) -o test/testeo test/testeo.o $(SYMLIB) ${LIBS}
test/test_simplify: test/test_simplify.o $(SYMLIB)
$(CXX) -o test/test_simplify test/test_simplify.o $(SYMLIB) ${LIBS}
test/test_diff: test/test_diff.o $(SYMLIB)
$(CXX) -o test/test_diff test/test_diff.o $(SYMLIB) ${LIBS}
test/test_lambda: test/test_lambda.o $(SYMLIB)
$(CXX) -o test/test_lambda test/test_lambda.o $(SYMLIB) ${LIBS}
test/test_mf: test/test_mf.o $(SYMLIB)
$(CXX) -o test/test_mf test/test_mf.o $(SYMLIB) ${LIBS}
test/test_interval: test/test_interval.o
$(CXX) -o test/test_interval test/test_interval.o $(SYMLIB) ${LIBS}
# eo
../../src/libeo.a:
make -C ../../src libeo.a
../../src/utils/libeoutils.a:
make -C ../../src/utils libeoutils.a
# tiny cc
tcc/: tcc.tar.gz
tar xvfz tcc.tar.gz && cd tcc && ./configure && make
tcc/Makefile: tcc/
cd tcc && ./configure
tcc/libtcc.a: tcc/Makefile
make -Ctcc
tcc/libtcc1.a: tcc/Makefile
make -Ctcc
#rules
c_compile.o: eval/c_compile.c
$(CC) -c eval/c_compile.c -I./tcc $(COMPILEFLAGS) $(OPTFLAGS)
%.o:%.cpp
$(CXX) -o $@ -c $< $(CPPFLAGS) $(INCLUDE)
%.d: %.cpp
$(SHELL) -ec '$(CXX) -M $(CPPFLAGS) $< | sed "s/$*.o/& $@/g" > $@ '
%.d: %.c
$(SHELL) -ec '$(CXX) -M $(CPPFLAGS) $< | sed "s/$*.o/& $@/g" > $@ '

198
eo/contrib/mathsym/README Normal file
View file

@ -0,0 +1,198 @@
This is not yet another gp system (nyagp). For one, it is not general.
It does one thing, find mathematical functions, and tries to do that well.
So, if you're trying to steer ants on various New Mexico trails, or build your
own tiny block world, you're in the wrong place. However, if you're interested
in finding mathematical functions either through direct application on data or
running it through a simulator, you might find what you're looking for here.
=== Representation (sym/ + gen/) ========
Mathsym has a few interesting characteristics. First and foremost is the
basic representation. It uses trees, but these trees are stored in a
reference counted hashtable. This means that every distinct subtree that is alive
is stored once and only once.
The reference counting mechanism takes care of memory management.
The idea of using a hashtable (for offline analysis) comes from Walter Tackett, in his
1994 dissertation. The current system is just a real-time implementation of this
idea, adding the reference counting for ease of use.
The hashtable brings overhead. It's still pretty fast, but a string based representation
would run circles around it. However, by virtue of it storing every subtree only once, it
is fairly tight on memory. This helps tremendously when confronted with excessively growing populations, bloat.
The hashtable implementation can not stop bloat, but does make it more manageable. In a typical
GP run, the number of distinct subtrees is only 10-20% of the total number of subtrees.
Other advantages of the hashtable are in the ability to examine the run more thoroughly. It is easy
to check how many subtrees are present in the system, and for each subtree you can check the reference
count.
The basic tree is called a Sym. A Sym is simply a tree, and has children, accessible through args().
A Sym simply contains an iterator (== decorated pointer) to an entry in the hashtable.
Every time you create a Sym, it is either looked up in the hashtable or added to the hashtable.
A Sym has several members: size, depth, args, etc. One interesting member is the refcount().
This returns the reference count of the Sym in the hashtable, and thus returns the number
of distinct contexts in which the Sym is used.
Another nice thing of these hashtable Syms is that a check for equality reduces to a pointer comparison.
The Sym nodes are identified by a simple token, of type token_t (usually an unsigned int). It
is completely generic and could conceivably be adapted to steer ants. The rest of the library
is however targeted at mathematical functions purely.
sym/Sym.h is the file to look into for the functionality provided by Sym. The sym/ directory
is where the source files are stored that are relevant for the generic Sym functionality. The
'gen/' directory contains some generic functionality to build and traverse trees, independent of
the function and terminal set.
The file sym/README.cpp documents the use of the sym library for general GP use.
=== Function Set (fun/) ===
The standard GP function set of binary functions: addition, multiplication, subtraction and
division is NOT supported.
What is however supported are the functions of:
summation: arbitrary arity, arity zero meaning 0.0. Arity 2 is standard addition
product: arbitrary arity, arity zero meaning 1.0. Arity 2 is standard multiplication
inversion: 1.0 / x. Only arity 1
unary minus: -x. Only arity 1
Plus a whole bunch of other functions (see "fun/FunDef.h")
The reason for this is the observation (actually from a friend of mine, thanks Luuk),
that this set of functions is complete and slightly more orthogonal than a binary set.
The directory 'fun' contains the functionality for the function and terminal set, together
with ERC's etc. fun/FunDef.cpp contains the definition of the functionality. Stuff can be
added here, but best to contact me if you miss particular functions.
With the sym and the function set in place, some fairly nice overloading is possible. A quick tour:
To create a variable that reads the first value from the inputs, do:
Sym var = SymVar(0);
To create a constant of value 0.4432, do
Sym cnst = SymConst(0.4432);
The constants are also stored uniquely so that:
Sym cnst2 = SymConst(0.4432)
will lead to:
cnst == cnst2
to be true (this happens without value compare, they point to the same element in the hashtable)
To add two values, do
Sym sym = var + const;
This will create a tree with three nodes. Other operators are overloaded similarily.
=== Evaluation (eval/) ===
The second important thing is evaluation. Although Syms can be evaluated through an interpreter,
this is not the fastest way to go about with it. The standard way of evaluating a Sym is to
first *compile* it to a function, and then run it in your favourite environment. Compilation
is done through the use of the excellent tinycc compiler, which is blazingly fast and produces
pretty good functions.
Compilation comes in several flavours: compile a single function and retrieve a pointer to a function
of signature:
double func(const double* x);
where x is the input array. Another option is to compile a bunch of functions in one go, and retrieve an array
of such function pointers. The Syms are simply printed and compiled. An example:
double func(const double* x) { return x*x + x * 1./x; }
The batch version proceeds significantly more quickly than calling compile every time. The function pointers
can be given to a simulation for extremely quick evaluation.
A third option is to compile a complete population in one go, and return a single pointer of signature
void func(const double* x, double* y);
Where 'y' is the (preallocated) output array. This allows to evaluate a complete population in one function
call, storing the results in 'y'. It uses the hashtable to store every calculation only once. An example
for the two function x*x + x*1./x and x + sin(x*x) is:
void func(const double* x, double* y) {
double a0 = x;
double a1 = a0 * a0;
double a2 = 1.0;
double a3 = a2 / a0;
double a4 = a2 * a3;
y[0] = a4;
double a5 = sin(a1);
double a6 = a0 + a5;
y[1] = a6;
}
This is the fastest way to evaluate even humongous populations quickly. You might be surprised at
the amount of code re-use in a GP population.
The three compilation functions can be found in eval/sym_compile.h
A limiting factor in tinycc is that the struct TCCState that is used to hold the compilation context,
is not really self-contained. This unfortunately means that with every call to 'compile' ALL previous
pointers that have been produced become unsafe for use. I'm still looking at ways to circumvent this.
To work with mathsym, a few small changes in tccelf.c were necessary, check README.TCC for details.
=== Interval Arithmetic (eval/) ===
GP is pretty good at finding mathematical expressions that are numerically unsound. Take for instance
the function '1 / x'. This is well defined only when x is strictly positive, but will lead to problems
when x equals 0. The standard answer is to define some pseudo-arithmetical function called 'protected
division' that will return some value (usually 1) when a division by zero occurs. This leads to a number
of protected functions (sqrt, log, tan, etc.) which all need to be protected. Interpreting results from
GP using such functions is in general hard.
Interval arithmetic (through another excellent library boost/numeric/interval) is used to calculate
if particular functions can conceivably produce problems. This completely annihilates the use for Koza-style
protected operators and is a more safe and sound method. For interval arithmetic to function, the bounds
on the input variables need to be known. As for every function we can calculate a guarenteed,
though not necessarily tight, output interval given the input intervals, we can check arbitrary functions
for possible problems. If, for example for division, the input interval contains 0, we know that a division
by zero is theoretically possible. It's then best to throw away the entire function.
Interval Arithmetic is accessible through the class IntervalBoundsCheck (eval/BoundsCheck.h)
=== More generic support (gen/) ===
The gen subdirectory contains some general utility classes for defining function sets and for
creating trees. The idea is that these functions are generic and only append on the sym/ part
of the library. Unfortunately, the language table currently needs an ERC function, a default
implementation is hidden inside fun/FunDef.cpp. Will fix at some point.
gen/LanguageTable.cpp -> defines the functions/terminals that can be used
gen/TreeBuilder.cpp -> can create trees based on a LanguageTable
=== Data and Errors (regression/) ===
The above classes are generic and apply for any type of problem where a mathematical function can be
used to steer some process, run a simulation, whatever. First check the intervals, then compile the
Sym(s) to a (set of) function pointer(s), and use the pointers in some way to evaluate for fitness.
One particular type of problem for which support is built in is 'symbolic regression'. This type of
problem involves finding an mathematical input/output relationship based on some data.
To enable this, regression/ introduces the class Dataset to contain the data and ErrorMeasure to calculate
error. Currently supported: mean squared error, mean absolute error and mean squared error scaled (proportional
to correlation squared). They use some helper classes such as Scaling and TargetInfo.
=== EO interface (eo_interface/) ===
Contains the classes to make it all work with EO. Check the root application 'symreg' for ways to use this

View file

@ -0,0 +1,5 @@
To refrain tcc from searching for libtcc1.a in the path, uncomment
out the lines looking for that in 'tccelf.c'. Search for libtcc1 and uncomment
these two lines. All should be well.

View file

@ -0,0 +1,65 @@
/*
* Copyright (C) 2005 Maarten Keijzer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EOSYM_H_
#define EOSYM_H_
#include <EO.h>
#include <sym/Sym.h>
#include <fun/FunDef.h>
template <class Fitness>
class EoSym : public EO<Fitness>, public Sym {
public:
void set(const Sym& sym) {
EO<Fitness>::invalidate();
static_cast<Sym*>(this)->operator=(sym);
}
Sym& get() { return static_cast<Sym&>(*this); };
Sym get() const { return static_cast<Sym&>(*this); };
virtual void printOn(std::ostream& os) const;
virtual void readFrom(std::istream& is);
};
template <class Fitness>
void EoSym<Fitness>::printOn(std::ostream& os) const {
EO<Fitness>::printOn(os);
os << ' ';
write_raw(os, *this);
}
template <class Fitness>
void EoSym<Fitness>::readFrom(std::istream& is) {
EO<Fitness>::readFrom(is);
read_raw(is, *this);
}
template <class Fitness>
inline std::ostream& operator<<(std::ostream& os, const EoSym<Fitness>& f) { f.printOn(os); return os; }
template <class Fitness>
inline std::istream& operator>>(std::istream& is, EoSym<Fitness>& f) { f.readFrom(is); return is; }
#endif

View file

@ -0,0 +1,123 @@
/*
* Copyright (C) 2005 Maarten Keijzer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <Sym.h>
#include <NodeSelector.h>
#include <eoSymCrossover.h>
#include <utils/eoRNG.h>
#include <vector>
using namespace std;
bool subtree_quad(Sym& a, Sym& b, NodeSelector& select) {
NodeSelector::NodeSelection sel_a = select.select_node(a);
NodeSelector::NodeSelection sel_b = select.select_node(b);
Sym aprime = insert_subtree(a, sel_a.idx(), sel_b.subtree() );
Sym bprime = insert_subtree(b, sel_b.idx(), sel_a.subtree() );
a = aprime;
b = bprime;
return true;
}
bool subtree_bin(Sym& a, const Sym& b, NodeSelector& select) {
NodeSelector::NodeSelection sel_a = select.select_node(a);
NodeSelector::NodeSelection sel_b = select.select_node(b);
a = insert_subtree(a, sel_a.idx(), sel_b.subtree());
return true;
}
Sym homologous_binimpl(Sym a, Sym b) {
if(a == b) { return a; } // no point
bool use_a = rng.random(2);
token_t head = (use_a? a : b).token();
SymVec args = use_a?a.args() : b.args();
const SymVec& a_args = a.args();
const SymVec& b_args = b.args();
unsigned mn = std::min(a_args.size(), b_args.size());
bool changed = !use_a;
for (unsigned i = 0; i < mn; ++i) {
args[i] = homologous_binimpl(a_args[i], b_args[i]);
if (args[i] != a_args[i]) {
changed = true;
}
}
return changed? Sym(head, args) : a;
}
bool homologous_bin(Sym& a, const Sym& b) {
if (a==b) return false;
Sym org = a;
a = homologous_binimpl(a,b);
return org != a;
}
void set_size_levels(Sym sym, vector<unsigned>& l, vector<unsigned>& s, unsigned level = 1) {
l.push_back(level);
s.push_back(sym.size());
for (unsigned i = 0; i < sym.args().size(); ++i) {
set_size_levels(sym.args()[i], l, s, level+1);
}
}
bool size_level_xover(Sym& a, const Sym& b) {
Sym org = a;
vector<unsigned> levela;
vector<unsigned> sizesa;
vector<unsigned> levelb;
vector<unsigned> sizesb;
set_size_levels(a, levela, sizesa);
set_size_levels(b, levelb, sizesb);
unsigned p0;
unsigned p1;
for (unsigned tries = 0;; ++tries) {
p0 = rng.random(a.size());
p1 = rng.random(b.size());
if (tries < 5 && (sizesa[p0] != sizesb[p1] && levela[p0] != levelb[p1])) {
continue;
}
break;
}
a = insert_subtree(a, p0, get_subtree(b, p1));
return org != a;
}

View file

@ -0,0 +1,73 @@
/*
* Copyright (C) 2005 Maarten Keijzer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EOSYMCROSSOVER_H
#define EOSYMCROSSOVER_H
class NodeSelector;
class Sym;
#include <eoOp.h>
extern bool subtree_quad(Sym& a, Sym& b, NodeSelector& select);
template <class EoType>
class eoQuadSubtreeCrossover : public eoQuadOp<EoType> {
NodeSelector& node_selector;
public:
eoQuadSubtreeCrossover(NodeSelector& _node_selector) : node_selector(_node_selector) {}
bool operator()(EoType& a, EoType& b) { return subtree_quad(a,b, node_selector); }
};
extern bool subtree_bin(Sym& a, const Sym& b, NodeSelector& select);
template <class EoType>
class eoBinSubtreeCrossover : public eoBinOp<EoType> {
NodeSelector& node_selector;
public :
eoBinSubtreeCrossover(NodeSelector& _node_selector) : node_selector(_node_selector) {}
bool operator()(EoType& a, const EoType& b) { return subtree_bin(a, b, node_selector); }
};
/** Yet another homologous crossover, afaik not particularly
* defined in the literature
*/
extern bool homologous_bin(Sym& a, const Sym& b);
template <class EoType>
class eoBinHomologousCrossover : public eoBinOp<EoType> {
public:
bool operator()(EoType& a, const EoType& b) {
return homologous_bin(a,b);
}
};
extern bool size_level_xover(Sym& a, const Sym& b);
template <class EoType>
class eoSizeLevelCrossover : public eoBinOp<EoType> {
public:
bool operator()(EoType& a, const EoType& b) {
return size_level_xover(a,b);
}
};
#endif

View file

@ -0,0 +1,96 @@
/*
* Copyright (C) 2005 Maarten Keijzer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SYMEVAL_H
#define SYMEVAL_H
#include <Sym.h>
#include <FunDef.h>
#include <ErrorMeasure.h>
#include <BoundsCheck.h>
#include <eoPopEvalFunc.h>
template <class EoType>
class eoSymPopEval : public eoPopEvalFunc<EoType> {
BoundsCheck& check;
ErrorMeasure& measure;
unsigned size_cap;
public:
eoSymPopEval(BoundsCheck& _check, ErrorMeasure& _measure, unsigned _size_cap) :
check(_check), measure(_measure), size_cap(_size_cap) {}
/** apparently this thing works on two populations,
*
* In any case, currently only implemented the population wide
* evaluation version, as that one is much faster. This because the
* compile going on behind the scenes is much faster when done in one
* go (and using subtree similarity) then when done on a case by case
* basis.
*/
void operator()(eoPop<EoType>& p1, eoPop<EoType>& p2) {
std::vector<unsigned> unevaluated;
std::vector<Sym> tmppop;
for (unsigned i = 0; i < p1.size(); ++i) {
if (p1[i].invalid()) {
if (expand_all(p1[i]).size() < size_cap && check.in_bounds(p1[i])) {
unevaluated.push_back(i);
tmppop.push_back( static_cast<Sym>(p1[i]) );
} else {
p1[i].fitness( measure.worst_performance() );
}
}
}
for (unsigned i = 0; i < p2.size(); ++i) {
if (p2[i].invalid()) {
if (expand_all(p2[i]).size() < size_cap && check.in_bounds(p2[i])) {
unevaluated.push_back(p1.size() + i);
tmppop.push_back( static_cast<Sym>(p2[i]) );
} else {
p2[i].fitness( measure.worst_performance() ); // pretty bad error
}
}
}
std::vector<ErrorMeasure::result> result = measure.calc_error(tmppop);
for (unsigned i = 0; i < result.size(); ++i) {
unsigned idx = unevaluated[i];
if (idx < p1.size()) {
p1[idx].fitness(result[i].error);
} else {
idx -= p1.size();
p2[idx].fitness(result[i].error);
}
}
}
};
#endif

View file

@ -0,0 +1,64 @@
/*
* Copyright (C) 2005 Maarten Keijzer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef EOSYMINIT_H
#define EOSYMINIT_H
#include <eoInit.h>
#include <gen/TreeBuilder.h>
/** Default initializer, Koza style */
template <class EoType>
class eoSymInit : public eoInit<EoType> {
TreeBuilder& builder;
double own_grow_prob;
unsigned own_max_depth;
double& grow_prob;
unsigned& max_depth;
public:
/** By default build ramped half and half with max depth 6 */
eoSymInit(TreeBuilder& _builder)
: builder(_builder),
own_grow_prob(0.5),
own_max_depth(6),
grow_prob(own_grow_prob),
max_depth(own_max_depth)
{}
/** Control the grow_prob and max_depth externally */
eoSymInit(TreeBuilder& _builder, double& _grow_prob, unsigned& _max_depth)
: builder(_builder),
grow_prob(_grow_prob),
max_depth(_max_depth)
{}
/** build the tree */
void operator()(EoType& tree) {
int depth_to_use = rng.random(max_depth-2) + 2; // two levels minimum
builder.build_tree(tree, depth_to_use, rng.flip(grow_prob));
}
};
#endif

View file

@ -0,0 +1,29 @@
#include <eoSymLambdaMutate.h>
#include "FunDef.h"
#include "NodeSelector.h"
Sym compress(Sym sym, NodeSelector& sel) {
return ::compress(sym);
NodeSelector::NodeSelection s = sel.select_node(sym);
Sym f = SymLambda( s.subtree());
if (f == s.subtree()) { return sym; }
return insert_subtree(sym, s.idx(), f);
}
extern Sym expand(Sym sym, NodeSelector& sel) {
return ::expand_all(sym);
NodeSelector::NodeSelection s = sel.select_node(sym);
Sym f = SymUnlambda( s.subtree());
if (f == s.subtree()) { return sym; }
return insert_subtree(sym, s.idx(), f);
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (C) 2005 Maarten Keijzer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SYMLAMBDAMUTATE_H
#define SYMLAMBDAMUTATE_H
#include <eoOp.h>
class NodeSelector;
class Sym;
extern Sym compress(Sym, NodeSelector&);
extern Sym expand(Sym, NodeSelector&);
template <class EoType>
class eoSymLambdaMutate : public eoMonOp<EoType> {
NodeSelector& selector;
public :
eoSymLambdaMutate(NodeSelector& s) : selector(s) {}
bool operator()(EoType& tomutate) {
if (rng.flip()) {
tomutate.set( expand(tomutate, selector));
} else {
tomutate.set( compress(tomutate, selector));
}
return true;
}
};
#endif

View file

@ -0,0 +1,72 @@
/*
* Copyright (C) 2005 Maarten Keijzer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <eoSymMutate.h>
#include <FunDef.h>
#include <utils/eoRNG.h>
using namespace std;
std::pair<Sym, bool> do_mutate(Sym sym, double p, const LanguageTable& table) {
bool changed = false;
SymVec args = sym.args();
if (rng.flip(p)) {
token_t new_token = table.get_random_function(sym.token(), args.size());
if (new_token != sym.token()) {
changed = true;
sym = Sym(new_token, args);
}
}
for (unsigned i = 0; i < args.size(); ++i) {
std::pair<Sym,bool> r = do_mutate(args[i], p, table);
changed |= r.second;
if (r.second)
args[i] = r.first;
}
if (changed)
return std::make_pair(Sym(sym.token(), args), true);
// else
return std::make_pair(sym, false);
}
// these two can (should?) move to an impl file
bool mutate(Sym& sym, double p, const LanguageTable& table) {
std::pair<Sym, bool> r = do_mutate(sym, p, table);
sym = r.first;
return r.second;
}
bool mutate_constants(Sym& sym, double stdev) {
vector<double> values = get_constants(sym);
if (values.empty()) {
return false;
}
for (unsigned i = 0; i < values.size(); ++i) {
values[i] += rng.normal() * stdev / values.size();
}
sym = set_constants(sym, values);
return true;
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (C) 2005 Maarten Keijzer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SYMMUTATE_H
#define SYMMUTATE_H
#include <gen/TreeBuilder.h>
#include <gen/NodeSelector.h>
#include <eoSym.h>
#include <eoOp.h>
template <class EoType>
class eoSymSubtreeMutate : public eoMonOp<EoType> {
TreeBuilder& subtree_builder;
NodeSelector& node_selector;
public :
eoSymSubtreeMutate(TreeBuilder& _subtree_builder, NodeSelector& _node_selector)
: subtree_builder(_subtree_builder), node_selector(_node_selector) {}
bool operator()(EoType& tomutate) {
unsigned xover_point = node_selector.select_node(tomutate).idx();
// create subtree
Sym newtree = subtree_builder.build_tree(6, true); // TODO, parameterize
static_cast<Sym&>(tomutate) = insert_subtree(tomutate, xover_point, newtree);
return true;
}
};
/** Class for doing node mutation
* Two parameters:
*
* mutation_rate (the rate at which to do mutation)
* is_rate_absolute : don't rescale the rate to the size of the tree
*/
extern bool mutate(Sym& sym, double p, const LanguageTable& table);
template <class EoType>
class eoSymNodeMutate : public eoMonOp<EoType> {
LanguageTable& table;
double own_mutation_rate;
bool own_is_rate_absolute;
public:
double& mutation_rate;
bool& is_rate_absolute;
eoSymNodeMutate(LanguageTable& _table)
: table(_table),
own_mutation_rate(1.0),
own_is_rate_absolute(false), // this means a probability of node mutation of 1/sym.size()
mutation_rate(own_mutation_rate),
is_rate_absolute(own_is_rate_absolute)
{}
eoSymNodeMutate(LanguageTable& _table, double& _mutation_rate, bool& _is_rate_absolute)
: table(_table),
mutation_rate(_mutation_rate),
is_rate_absolute(_is_rate_absolute)
{}
bool operator()(EoType& _eo) {
double p = mutation_rate;
if (!is_rate_absolute) p /= _eo.size();
return mutate(_eo, p, table);
}
};
/**
* Simple constant mutation class, adds gaussian noise (configurable variance) to the individuals
**/
extern bool mutate_constants(Sym& sym, double stdev);
template <class EoType>
class eoSymConstantMutate : public eoMonOp<EoType> {
double& stdev;
public :
eoSymConstantMutate(double& _stdev) : stdev(_stdev) {}
bool operator()(EoType& _eo) {
return mutate_constants(_eo, stdev);
}
};
#endif

View file

@ -0,0 +1,80 @@
/*
* Copyright (C) 2005 Maarten Keijzer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <vector>
#include "BoundsCheck.h"
#include <Sym.h>
#include <FunDef.h>
#include <sstream>
using namespace std;
class IntervalBoundsCheckImpl {
public :
vector<Interval> bounds;
};
IntervalBoundsCheck::IntervalBoundsCheck(const vector<double>& mins, const vector<double>& maxes) {
pimpl = new IntervalBoundsCheckImpl;
vector<Interval>& b = pimpl->bounds;
b.resize( mins.size());
for (unsigned i = 0; i < b.size(); ++i) {
b[i] = Interval(mins[i], maxes[i]);
}
}
IntervalBoundsCheck::~IntervalBoundsCheck() { delete pimpl; }
IntervalBoundsCheck::IntervalBoundsCheck(const IntervalBoundsCheck& that) { pimpl = new IntervalBoundsCheckImpl(*that.pimpl); }
IntervalBoundsCheck& IntervalBoundsCheck::operator=(const IntervalBoundsCheck& that) { *pimpl = *that.pimpl; return *this; }
bool IntervalBoundsCheck::in_bounds(const Sym& sym) const {
Interval bounds;
try {
bounds = eval(sym, pimpl->bounds);
if (!valid(bounds)) return false;
} catch (interval_error) {
return false;
}
return true;
}
std::string IntervalBoundsCheck::get_bounds(const Sym& sym) const {
try {
Interval bounds = eval(sym, pimpl->bounds);
if (!valid(bounds)) return "err";
ostringstream os;
os << bounds;
return os.str();
} catch (interval_error) {
return "err";
}
}
std::pair<double, double> IntervalBoundsCheck::calc_bounds(const Sym& sym) const {
Interval bounds = eval(sym, pimpl->bounds);
return make_pair(bounds.lower(), bounds.upper());
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 2005 Maarten Keijzer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef BOUNDS_CHECK_H_
#define BOUNDS_CHECK_H_
#include <string>
class IntervalBoundsCheckImpl;
class Sym;
class BoundsCheck {
public :
virtual ~BoundsCheck() {};
virtual bool in_bounds(const Sym&) const = 0;
virtual std::string get_bounds(const Sym&) const = 0;
};
// checks if a formula keeps within bounds using interval arithmetic
class IntervalBoundsCheck : public BoundsCheck {
IntervalBoundsCheckImpl* pimpl;
public:
IntervalBoundsCheck(const std::vector<double>& minima, const std::vector<double>& maxima);
~IntervalBoundsCheck();
IntervalBoundsCheck(const IntervalBoundsCheck&);
IntervalBoundsCheck& operator=(const IntervalBoundsCheck&);
bool in_bounds(const Sym&) const;
std::string get_bounds(const Sym&) const;
std::pair<double, double> calc_bounds(const Sym&) const;
};
class NoBoundsCheck : public BoundsCheck {
bool in_bounds(const Sym&) const { return false; }
std::string get_bounds(const Sym&) const { return ""; }
};
#endif

View file

@ -0,0 +1,82 @@
/*
* Copyright (C) 2005 Maarten Keijzer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef INTERVAL__H__
#define INTERVAL__H__
#include <boost/numeric/interval.hpp>
#include <iostream>
#include <limits>
typedef boost::numeric::interval_lib::rounded_transc_exact<double> RoundingTransc;
typedef boost::numeric::interval_lib::save_state<RoundingTransc> Rounding;
typedef boost::numeric::interval_lib::checking_base<double> Checking;
typedef boost::numeric::interval_lib::policies<Rounding,Checking> Policy;
typedef boost::numeric::interval<double, Policy> Interval;
struct interval_error{};
inline bool valid(const Interval& val) {
if (!finite(val.lower()) || !finite(val.upper())) return false;
return val.lower() > -1e10 && val.upper() < 1e10;
}
inline Interval sqrt(const Interval& val) {
if (val.lower() < 0.0) {
return Interval::whole();
}
return boost::numeric::sqrt(val);
}
inline Interval sqr(const Interval& val) {
return square(val);
}
inline Interval acos(const Interval& val) {
if (val.lower() < 1.0 || val.upper() > 1.0) {
return Interval::whole();
}
return boost::numeric::acos(val);
}
inline Interval asin(const Interval& val) {
if (val.lower() < 1.0 || val.upper() > 1.0) {
return Interval::whole();
}
return boost::numeric::asin(val);
}
inline Interval acosh(const Interval& val) {
if (val.lower() < 1.0) return Interval::whole();
return boost::numeric::acosh(val);
}
inline
std::ostream& operator<<(std::ostream& os, const Interval& val) {
os << '[' << val.lower() << ", " << val.upper() << ']';
return os;
}
#ifdef TEST_INTERVAL
#endif
#endif

View file

@ -0,0 +1,26 @@
namespace multi_function {
double plus(arg_ptr args) {
return *args[0] + *args[1];
}
double mult(arg_ptr args) {
return *args[0] * *args[1];
}
double min(arg_ptr args) {
return -**args;
}
double inv(arg_ptr args) {
return 1 / **args;
}
//template <typename f> class F { public: double operator()(double a) { return f(a); } };
double exp(arg_ptr args) {
return ::exp(**args);
}
} // namespace

View file

@ -0,0 +1,341 @@
#include <vector.h>
#include "MultiFunction.h"
#include "Sym.h"
#include "FunDef.h"
using namespace std;
typedef vector<double>::const_iterator data_ptr;
typedef vector<data_ptr> data_ptrs;
typedef data_ptrs::const_iterator arg_ptr;
#include "MultiFuncs.cpp"
typedef double (*fptr)( arg_ptr );
string print_function( fptr f) {
if (f == multi_function::plus) return "+";
if (f == multi_function::mult) return "*";
if (f == multi_function::min) return "-";
if (f == multi_function::inv) return "/";
if (f == multi_function::exp) return "e";
return "unknown";
}
struct Function {
fptr function;
arg_ptr args;
double operator()() const { return function(args); }
};
static vector<Function> token_2_function;
Sym make_binary(Sym sym) {
if (sym.args().size() == 2) return sym;
SymVec args = sym.args();
Sym an = args.back();
args.pop_back();
Sym nw = make_binary( Sym( sym.token(), args) );
args.resize(2);
args[0] = nw;
args[1] = an;
return Sym(sym.token(), args);
}
class Compiler {
public:
enum func_type {constant, variable, function};
typedef pair<func_type, unsigned> entry;
#if USE_TR1
typedef std::tr1::unordered_map<Sym, entry, HashSym> HashMap;
#else
typedef hash_map<Sym, entry, HashSym> HashMap;
#endif
HashMap map;
vector<double> constants;
vector<unsigned> variables;
vector< fptr > functions;
vector< vector<entry> > function_args;
unsigned total_args;
vector<entry> outputs;
Compiler() : total_args(0) {}
entry do_add(Sym sym) {
HashMap::iterator it = map.find(sym);
if (it == map.end()) { // new entry
token_t token = sym.token();
if (is_constant(token)) {
constants.push_back( get_constant_value(token) ); // set value
entry e = make_pair(constant, constants.size()-1);
map.insert( make_pair(sym, e) );
return e;
} else if (is_variable(token)) {
unsigned idx = get_variable_index(token);
variables.push_back(idx);
entry e = make_pair(variable, variables.size()-1);
map.insert( make_pair(sym, e) );
return e;
} // else
fptr f;
vector<entry> vec;
const SymVec& args = sym.args();
switch (token) {
case sum_token:
{
if (args.size() == 0) {
return do_add( SymConst(0.0));
}
if (args.size() == 1) {
return do_add(args[0]);
}
if (args.size() == 2) {
vec.push_back(do_add(args[0]));
vec.push_back(do_add(args[1]));
f = multi_function::plus;
//cout << "Adding + " << vec[0].second << ' ' << vec[1].second << endl;
break;
} else {
return do_add( make_binary(sym) );
}
}
case prod_token:
{
if (args.size() == 0) {
return do_add( SymConst(1.0));
}
if (args.size() == 1) {
return do_add(args[0]);
}
if (args.size() == 2) {
vec.push_back(do_add(args[0]));
vec.push_back(do_add(args[1]));
f = multi_function::mult;
//cout << "Adding * " << vec[0].second << ' ' << vec[1].second << endl;
break;
} else {
return do_add( make_binary(sym) );
}
}
case sqr_token:
{
SymVec newargs(2);
newargs[0] = args[0];
newargs[1] = args[0];
return do_add( Sym(prod_token, newargs));
}
default :
{
if (args.size() != 1) {
cerr << "Unknown function " << sym << " encountered" << endl;
exit(1);
}
vec.push_back(do_add(args[0]));
switch (token) {
case min_token: f = multi_function::min; break;
case inv_token: f = multi_function::inv; break;
case exp_token :f = multi_function::exp; break;
default :
{
cerr << "Unimplemented token encountered " << sym << endl;
exit(1);
}
}
//cout << "Adding " << print_function(f) << ' ' << vec[0].second << endl;
}
}
total_args += vec.size();
function_args.push_back(vec);
functions.push_back(f);
entry e = make_pair(function, functions.size()-1);
map.insert( make_pair(sym, e) );
return e;
}
return it->second; // entry
}
void add(Sym sym) {
entry e = do_add(sym);
outputs.push_back(e);
}
};
class MultiFunctionImpl {
public:
// input mapping
vector<unsigned> input_idx;
unsigned constant_offset;
unsigned var_offset;
// evaluation
vector<double> data;
vector<Function> funcs;
data_ptrs args;
vector<unsigned> output_idx;
MultiFunctionImpl() {}
void clear() {
input_idx.clear();
data.clear();
funcs.clear();
args.clear();
output_idx.clear();
constant_offset = 0;
}
void eval(const double* x, double* y) {
unsigned i;
// evaluate variables
for (i = constant_offset; i < constant_offset + input_idx.size(); ++i) {
data[i] = x[input_idx[i-constant_offset]];
}
for(; i < data.size(); ++i) {
data[i] = funcs[i-var_offset]();
//cout << i << " " << data[i] << endl;
}
for (i = 0; i < output_idx.size(); ++i) {
y[i] = data[output_idx[i]];
}
}
void eval(const vector<double>& x, vector<double>& y) {
eval(&x[0], &y[0]);
}
void setup(const vector<Sym>& pop) {
clear();
Compiler compiler;
for (unsigned i = 0; i < pop.size(); ++i) {
Sym sym = (expand_all(pop[i]));
compiler.add(sym);
}
// compiler is setup so get the data
constant_offset = compiler.constants.size();
var_offset = constant_offset + compiler.variables.size();
int n = var_offset + compiler.functions.size();
data.resize(n);
funcs.resize(compiler.functions.size());
args.resize(compiler.total_args);
// constants
for (unsigned i = 0; i < constant_offset; ++i) {
data[i] = compiler.constants[i];
//cout << i << ' ' << data[i] << endl;
}
// variables
input_idx = compiler.variables;
//for (unsigned i = constant_offset; i < var_offset; ++i) {
//cout << i << " x" << input_idx[i-constant_offset] << endl;
//}
// functions
unsigned which_arg = 0;
for (unsigned i = 0; i < funcs.size(); ++i) {
Function f;
f.function = compiler.functions[i];
//cout << i+var_offset << ' ' << print_function(f.function);
// interpret args
for (unsigned j = 0; j < compiler.function_args[i].size(); ++j) {
Compiler::entry e = compiler.function_args[i][j];
unsigned idx = e.second;
switch (e.first) {
case Compiler::function: idx += compiler.variables.size();
case Compiler::variable: idx += compiler.constants.size();
case Compiler::constant: {}
}
args[which_arg + j] = data.begin() + idx;
//cout << ' ' << idx << "(" << e.second << ")";
}
//cout << endl;
f.args = args.begin() + which_arg;
which_arg += compiler.function_args[i].size();
funcs[i] = f;
}
// output indices
output_idx.resize(compiler.outputs.size());
for (unsigned i = 0; i < output_idx.size(); ++i) {
output_idx[i] = compiler.outputs[i].second;
switch(compiler.outputs[i].first) {
case Compiler::function: output_idx[i] += compiler.variables.size();
case Compiler::variable: output_idx[i] += compiler.constants.size();
case Compiler::constant: {}
}
//cout << "out " << output_idx[i] << endl;
}
}
};
MultiFunction::MultiFunction(const std::vector<Sym>& pop) : pimpl(new MultiFunctionImpl) {
pimpl->setup(pop);
}
MultiFunction::~MultiFunction() { delete pimpl; }
void MultiFunction::operator()(const std::vector<double>& x, std::vector<double>& y) {
pimpl->eval(x,y);
}
void MultiFunction::operator()(const double* x, double* y) {
pimpl->eval(x,y);
}

View file

@ -0,0 +1,26 @@
#ifndef MULTIFUNCTION_H_
#define MULTIFUNCTION_H_
#include <vector>
class Sym;
class MultiFunctionImpl;
class MultiFunction {
MultiFunction& operator=(const MultiFunction&);
MultiFunction(const MultiFunction&);
MultiFunctionImpl* pimpl;
public:
MultiFunction(const std::vector<Sym>& pop);
~MultiFunction();
void operator()(const std::vector<double>& x, std::vector<double>& y);
void operator()(const double* x, double* y);
};
#endif

View file

@ -0,0 +1,57 @@
#include <stdio.h>
#include <libtcc.h>
#include <math.h>
static TCCState* s = 0;
extern void symc_init() {
if (s != 0) {
tcc_delete(s);
}
s = tcc_new();
if (s == 0) {
fprintf(stderr, "Tiny cc doesn't function properly");
exit(1);
}
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
}
extern int symc_compile(const char* func_str) {
//printf("Compiling %s\n", func_str);
int err = tcc_compile_string(s, func_str);
if (err) {
fprintf(stderr,"Compile failed");
}
return err;
}
extern int symc_link() {
int err = tcc_relocate(s);
if (err) {
fprintf(stderr,"Compile failed");
exit(1);
}
return err;
}
extern void* symc_get_fun(const char* func_name) {
unsigned long val;
tcc_get_symbol(s, &val, func_name);
if (val == 0) {
fprintf(stderr,"getfun failed");
exit(1);
}
return (void*) val;
}
extern void* symc_make(const char* func_str, const char* func_name) {
symc_init();
symc_compile(func_str);
symc_link();
return symc_get_fun(func_name);
}

Some files were not shown because too many files have changed in this diff Show more