From ba03470cb64a7e8f858502ec3c7be75e3626e618 Mon Sep 17 00:00:00 2001 From: Francois Fleuret Date: Wed, 8 Jul 2009 09:16:46 +0200 Subject: [PATCH] Initial commit. --- Makefile | 34 +++++++++ README | 31 ++++++++ main.cc | 52 +++++++++++++ mappings.cc | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++ mappings.h | 99 ++++++++++++++++++++++++ 5 files changed, 427 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 main.cc create mode 100644 mappings.cc create mode 100644 mappings.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..983d12f --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ + +######################################################################### +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the version 3 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, see . # +# # +# Written and (C) by Francois Fleuret # +# Contact for comments & bug reports # +######################################################################### + +ifeq ($(DEBUG),yes) + CXXFLAGS = -Wall -g +else + # Optimized compilation + CXXFLAGS = -Wall -ffast-math -fcaller-saves -finline-functions -funroll-all-loops -O3 +endif + +all: main + +main: main.cc mappings.o + $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) + +Makefile.depend: *.h *.cc Makefile + $(CC) -M *.cc > Makefile.depend + +-include Makefile.depend diff --git a/README b/README new file mode 100644 index 0000000..5f964cf --- /dev/null +++ b/README @@ -0,0 +1,31 @@ + +This mapping class is a usable example of a "sophisticated" symbolic +mapping class in C++. Bascially it allows you to do things like : + + // X will be the "identity mapping" + Mapping X = Mapping::X; + // A undefined mapping + Mapping f; + // Now contains some complex stuff + f = sin(X * X - (X * 3.0) + 0.5); + // Display it + cout << f*f << endl; + // fp will be the first derivative + Mapping fp = f.derivative(); + // fs the second derivative + Mapping fs = fp.derivative(); + // Compute the second derivative at 5 + cout << fs(5.0) << endl; + +The best is to check the mappings.h to look at what functions and +operators are available. It will be pretty easy to add your own +operators. + +The memory management is done in such a way that spurious copies are +avoided and intermediate results will be deallocated correctly. So far +I never traced a memory leak, but feel free to report it if you find +one. + +Francois Fleuret +May 2001 +Modified 2005, 2007 diff --git a/main.cc b/main.cc new file mode 100644 index 0000000..7c6feea --- /dev/null +++ b/main.cc @@ -0,0 +1,52 @@ + +/////////////////////////////////////////////////////////////////////////// +// This program is free software: you can redistribute it and/or modify // +// it under the terms of the version 3 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, see . // +// // +// Written and (C) by Francois Fleuret // +// Contact for comments & bug reports // +/////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include "mappings.h" + +using namespace std; + +int main(int argc, char **argv) { + + // X will be the "identity mapping" + Mapping X = Mapping::X; + + // A undefined mapping + Mapping f; + + // Now contains some complex stuff + f = sin(X * X - (X * 3.0) + 0.5); + + // Display it + cout << f * f << endl; + + // fp will be the first derivative + Mapping fp = f.derivative(); + + // fs the second derivative + Mapping fs = fp.derivative(); + + // Compute the second derivative at 5 + cout << fs(5.0) << endl; + +} diff --git a/mappings.cc b/mappings.cc new file mode 100644 index 0000000..236ae15 --- /dev/null +++ b/mappings.cc @@ -0,0 +1,211 @@ + +/////////////////////////////////////////////////////////////////////////// +// This program is free software: you can redistribute it and/or modify // +// it under the terms of the version 3 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, see . // +// // +// Written and (C) by Francois Fleuret // +// Contact for comments & bug reports // +/////////////////////////////////////////////////////////////////////////// + +#include +#include "mappings.h" + +#ifdef DEBUG +int nb_refs = 0; +#endif + +// I looked a bit at string.h of the g++ library to do this ref +// counting things in the grab() and release(). This strategy allows +// to avoid useless copies. + +// Each time you build an object which has a reference to a Map, you +// have to grab() the Map, and each time you destroy an object with a +// reference to a Map, you have to release() the Map. You should not +// have grab() or release() out of constructors / destructors and +// assignement operator. + +// With such a politic, you should not need to worry about references +// anywhere else + +class Map { + int ref; +public: + // If DEBUG is defined, we keep a count of the total number of + // constructed / deleted Maps. "NO REF!" is printed each time this + // counter goes to 0. + + Map() { ref = 0; +#ifdef DEBUG + nb_refs++; +#endif +} + virtual ~Map() { +#ifdef DEBUG + nb_refs--; if(nb_refs == 0) cout << "NO REF!" << endl; +#endif + } + virtual float eval(float x) = 0; + virtual Map *derivative() = 0; + virtual Map *compose(Map *g) = 0; + void release() { if(--ref == 0) delete this; } + Map *grab() { ref++; return this; } + virtual void print(ostream &o) = 0; +}; + +class Cst : public Map { + float value; +public: + Cst(float v) : value(v) { } + virtual float eval(float x) { return value; } + virtual Map *derivative() { return new Cst(0.0); } + virtual Map *compose(Map *g) { return this; } + virtual void print(ostream &o) { o << value; } +}; + +class Var : public Map { +public: + Var() {} + virtual float eval(float x) { return x; } + virtual Map *derivative() { return new Cst(1.0); } + virtual Map *compose(Map *g) { return g; } + virtual void print(ostream &o) { o << "X"; } +}; + +class Sum : public Map { + Map *f1, *f2; +public: + Sum(Map *g1, Map *g2) : f1(g1->grab()), f2(g2->grab()) { } + ~Sum() { f1->release(); f2->release(); } + virtual float eval(float x) { return f1->eval(x) + f2->eval(x); } + virtual Map *derivative() { return new Sum(f1->derivative(), f2->derivative()); } + virtual Map *compose(Map *g) { return new Sum(f1->compose(g), f2->compose(g)); } + virtual void print(ostream &o) { o << "( "; f1->print(o); o<< " ) + ( " ; f2->print(o); o << " )"; } +}; + +class Prd : public Map { + Map *f1, *f2; +public: + Prd(Map *g1, Map *g2) : f1(g1->grab()), f2(g2->grab()) { } + ~Prd() { f1->release(); f2->release(); } + virtual float eval(float x) { return f1->eval(x) * f2->eval(x); } + virtual Map *derivative() { return new Sum(new Prd(f1->derivative(), f2), new Prd(f1, f2->derivative())); } + virtual Map *compose(Map *g) { return new Prd(f1->compose(g), f2->compose(g)); } + virtual void print(ostream &o) { o << "( "; f1->print(o); o<< " ) * ( " ; f2->print(o); o << " )"; } +}; + +class Sin : public Map { + Map *f; +public: + Sin(Map *g) : f(g->grab()) { } + ~Sin() { f->release(); } + virtual float eval(float x) { return sin(f->eval(x)); } + virtual Map *derivative() { return new Prd(f->derivative(), new Sin(new Sum(f, new Cst(M_PI/2)))); } + virtual Map *compose(Map *g) { return new Sin(f->compose(g)); } + virtual void print(ostream &o) { o << "sin( "; f->print(o); o<< " )"; } +}; + +class Inv : public Map { + Map *f; +public: + Inv(Map *g) : f(g->grab()) {} + ~Inv() { f->release(); } + virtual float eval(float x) { return 1.0/f->eval(x); } + virtual Map *derivative() { return new Prd(new Prd(new Cst(-1.0), f->derivative()), new Inv(new Prd(f, f))); } + virtual Map *compose(Map *g) { return new Inv(f->compose(g)); } + virtual void print(ostream &o) { o << "1 / ( "; f->print(o); o<< " )"; } +}; + +class Exp : public Map { + Map *f; +public: + Exp(Map *g) : f(g->grab()) {} + ~Exp() { f->release(); } + virtual float eval(float x) { return exp(f->eval(x)); } + virtual Map *derivative() { return new Prd(f->derivative(), new Exp(f)); } + virtual Map *compose(Map *g) { return new Exp(f->compose(g)); } + virtual void print(ostream &o) { o << "exp( "; f->print(o); o<< " )"; } +}; + +class Log : public Map { + Map *f; +public: + Log(Map *g) : f(g->grab()) {} + ~Log() { f->release(); } + virtual float eval(float x) { return log(f->eval(x)); } + virtual Map *derivative() { return new Prd(f->derivative(), new Prd(f->derivative(), new Inv(f))); } + virtual Map *compose(Map *g) { return new Log(f->compose(g)); } + virtual void print(ostream &o) { o << "log( "; f->print(o); o<< " )"; } +}; + +class Pow : public Map { + Map *f; + int exponent; +public: + Pow(Map *g, int e) : f(g->grab()), exponent(e) { } + ~Pow() { f->release(); } + virtual float eval(float x) { return pow(f->eval(x), exponent); } + virtual Map *derivative() { return new Prd(new Prd(new Cst(float(exponent)), f->derivative()), new Pow(f, exponent-1)); } + virtual Map *compose(Map *g) { return new Pow(f->compose(g), exponent); } + virtual void print(ostream &o) { o << "( "; f->print(o); o<< " )^" << exponent; } +}; + +const Mapping Mapping::X(new Var()); + +Mapping::Mapping() : f(0) { } +Mapping::Mapping(Map *g) : f(g ? g->grab(): 0) { } +Mapping::Mapping(const Mapping &s) : f(s.f ? s.f->grab() : 0) { } +Mapping::Mapping(float x) : f((new Cst(x))->grab()) { } +Mapping::~Mapping() { if(f) f->release(); } + +// This is the only place where grab() and release() are not in a +// constructor / destructor +Mapping &Mapping::operator = (const Mapping &m) { + if(&m != this) { + if(f) f->release(); + if(m.f) f = m.f->grab(); else f = 0; + } + return *this; +} + +float Mapping::operator () (float x) const { return f->eval(x); } +Mapping Mapping::derivative() const { return Mapping(f->derivative()); }; +Mapping Mapping::compose(const Mapping &m) const { return Mapping(f->compose(m.f)); } + +Mapping Mapping::add(const Mapping &m) const { return Mapping(new Sum(f, m.f)); } +Mapping Mapping::sub(const Mapping &m) const { return Mapping(new Sum(f, new Prd(new Cst(-1.0), m.f))); } +Mapping Mapping::mul(const Mapping &m) const { return Mapping(new Prd(f, m.f)); } +Mapping Mapping::div(const Mapping &m) const { return Mapping(new Prd(f, new Inv(m.f))); } +Mapping Mapping::pow(int k) const { return Mapping(new Pow(f, k)); } +Mapping Mapping::neg() const { return Mapping(new Prd(new Cst(-1), f)); } + +Mapping Mapping::sin() const { return Mapping(new Sin(f)); } +Mapping Mapping::cos() const { return Mapping(new Sin(new Sum(f, new Cst(M_PI/2)))); } +Mapping Mapping::log() const { return Mapping(new Log(f)); } +Mapping Mapping::exp() const { return Mapping(new Exp(f)); } + +void Mapping::print(ostream &o) const { if(f) f->print(o); else o << "UNDEFINED"; } + +ostream &operator << (ostream &o, const Mapping &m) { m.print(o); return o; } + +Mapping operator + (const Mapping &mr) { return mr; } +Mapping operator + (const Mapping &ml, const Mapping &mr) { return ml.add(mr); } +Mapping operator - (const Mapping &mr) { return mr.neg(); } +Mapping operator - (const Mapping &ml, const Mapping &mr) { return ml.sub(mr); } +Mapping operator * (const Mapping &ml, const Mapping &mr) { return ml.mul(mr); } +Mapping operator / (const Mapping &ml, const Mapping &mr) { return ml.div(mr); } +Mapping operator ^ (const Mapping &ml, int k) { return ml.pow(k); } + +Mapping sin(const Mapping &m) { return m.sin(); } +Mapping cos(const Mapping &m) { return m.cos(); } +Mapping log(const Mapping &m) { return m.log(); } +Mapping exp(const Mapping &m) { return m.exp(); } + diff --git a/mappings.h b/mappings.h new file mode 100644 index 0000000..95c21db --- /dev/null +++ b/mappings.h @@ -0,0 +1,99 @@ + +/////////////////////////////////////////////////////////////////////////// +// This program is free software: you can redistribute it and/or modify // +// it under the terms of the version 3 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, see . // +// // +// Written and (C) by Francois Fleuret // +// Contact for comments & bug reports // +/////////////////////////////////////////////////////////////////////////// + +#ifndef MAPPINGS_H +#define MAPPINGS_H + +#include + +using namespace std; + +// We have a bunch of such classes inside +class Map; + +class Mapping { + Map *f; + + // We'll need this one from time to time, but nobody is supposed to + // use it from "outside" + Mapping(Map *g); + +public: + // This is the variable + const static Mapping X; + + // This build a non-defined Mapping. Everything is illegal on such a + // Mapping except delete, = and <<. All other operations will *crash* + Mapping(); + + // Cast from float to allow operations with constant values + Mapping(float x); + + // Standard copy constructor and destructor + Mapping(const Mapping &s); + ~Mapping(); + + // Assignment + Mapping &operator = (const Mapping &m); + + // Evaluation + float operator () (float x) const; + + // Derivation + Mapping derivative() const; + + // Composition of Mappings + Mapping compose(const Mapping &m) const; + + // Standard operations + Mapping pow(int k) const; + Mapping mul(const Mapping &m) const; + Mapping div(const Mapping &m) const; + Mapping add(const Mapping &m) const; + Mapping sub(const Mapping &m) const; + Mapping neg() const; + Mapping sin() const; + Mapping cos() const; + Mapping log() const; + Mapping exp() const; + + // Print the expression + void print(ostream &s) const; +}; + +// I guess we have all the ones we need? +Mapping operator + (const Mapping &m); +Mapping operator + (const Mapping &ml, const Mapping &mr); +Mapping operator - (const Mapping &m); +Mapping operator - (const Mapping &ml, const Mapping &mr); +Mapping operator * (const Mapping &ml, const Mapping &mr); +Mapping operator / (const Mapping &ml, const Mapping &mr); + +// Be very careful with this operator, it has a lower precedence than +// +-*/ +Mapping operator ^ (const Mapping &ml, int k); + +// stream stuff, I dont have the courage to do the >> +ostream &operator << (ostream &o, const Mapping &m); + +Mapping sin(const Mapping &m); +Mapping cos(const Mapping &m); +Mapping log(const Mapping &m); +Mapping exp(const Mapping &m); + +#endif -- 2.20.1