]> www.ginac.de Git - ginac.git/blob - ginac/function.pl
container.pl: can now generate constructors for an arbitary number
[ginac.git] / ginac / function.pl
1 #!/usr/bin/perl -w
2
3 $maxargs=10;
4
5 sub generate_seq {
6     my ($seq_template,$n)=@_;
7     my ($res,$N);
8     
9     $res='';
10     for ($N=1; $N<=$n; $N++) {
11         $res .= eval('"' . $seq_template . '"');
12         if ($N!=$n) {
13             $res .= ', ';
14         }
15     }
16     return $res;
17 }
18
19 sub generate_from_to {
20     my ($template,$seq_template1,$seq_template2,$from,$to)=@_;
21     my ($res,$N,$SEQ);
22
23     $res='';
24     for ($N=$from; $N<=$to; $N++) {
25         $SEQ1=generate_seq($seq_template1,$N);
26         $SEQ2=generate_seq($seq_template2,$N);
27         $res .= eval('"' . $template . '"');
28         $SEQ1=''; # to avoid main::SEQ1 used only once warning
29         $SEQ2=''; # same as above
30     }
31     return $res;
32 }
33
34 sub generate {
35     my ($template,$seq_template1,$seq_template2)=@_;
36     return generate_from_to($template,$seq_template1,$seq_template2,1,$maxargs);
37 }
38
39 $declare_function_macro_namespace = <<'END_OF_DECLARE_FUNCTION_1_AND_2P_MACRO_NAMESPACE';
40 #ifdef CINT_CONVERSION_WORKAROUND
41
42 #define DECLARE_FUNCTION_1P(NAME) \
43 extern const unsigned function_index_##NAME; \
44 inline GiNaC::function NAME(const GiNaC::ex & p1) { \
45     return GiNaC::function(function_index_##NAME, p1); \
46 } \
47 inline GiNaC::function NAME(const GiNaC::basic & p1) { \
48     return GiNaC::function(function_index_##NAME, GiNaC::ex(p1)); \
49 }
50 #define DECLARE_FUNCTION_2P(NAME) \
51 extern const unsigned function_index_##NAME; \
52 inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2) { \
53     return GiNaC::function(function_index_##NAME, p1, p2); \
54 } \
55 inline GiNaC::function NAME(const GiNaC::basic & p1, const GiNaC::ex & p2) { \
56     return GiNaC::function(function_index_##NAME, GiNaC::ex(p1), p2); \
57 } \
58 inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::basic & p2) { \
59     return GiNaC::function(function_index_##NAME, p1, GiNaC::ex(p2)); \
60 } \
61 inline GiNaC::function NAME(const GiNaC::basic & p1, const GiNaC::basic & p2) { \
62     return GiNaC::function(function_index_##NAME, GiNaC::ex(p1), GiNaC::ex(p2)); \
63 }
64
65 #else // def CINT_CONVERSION_WORKAROUND
66
67 #define DECLARE_FUNCTION_1P(NAME) \
68 extern const unsigned function_index_##NAME; \
69 inline GiNaC::function NAME(const GiNaC::ex & p1) { \
70     return GiNaC::function(function_index_##NAME, p1); \
71 }
72 #define DECLARE_FUNCTION_2P(NAME) \
73 extern const unsigned function_index_##NAME; \
74 inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2) { \
75     return GiNaC::function(function_index_##NAME, p1, p2); \
76 }
77
78 #endif // def CINT_CONVERSION_WORKAROUND
79
80 END_OF_DECLARE_FUNCTION_1_AND_2P_MACRO_NAMESPACE
81
82 $declare_function_macro_namespace .= generate_from_to(
83     <<'END_OF_DECLARE_FUNCTION_MACRO_NAMESPACE','const GiNaC::ex & p${N}','p${N}',3,$maxargs);
84 #define DECLARE_FUNCTION_${N}P(NAME) \\
85 extern const unsigned function_index_##NAME; \\
86 inline GiNaC::function NAME(${SEQ1}) { \\
87     return GiNaC::function(function_index_##NAME, ${SEQ2}); \\
88 }
89
90 END_OF_DECLARE_FUNCTION_MACRO_NAMESPACE
91
92 $declare_function_macro_no_namespace = <<'END_OF_DECLARE_FUNCTION_1_AND_2P_MACRO_NO_NAMESPACE';
93 #ifdef CINT_CONVERSION_WORKAROUND
94
95 #define DECLARE_FUNCTION_1P(NAME) \
96 extern const unsigned function_index_##NAME; \
97 inline function NAME(const ex & p1) { \
98     return function(function_index_##NAME, p1); \
99 } \
100 inline function NAME(const basic & p1) { \
101     return function(function_index_##NAME, ex(p1)); \
102 }
103 #define DECLARE_FUNCTION_2P(NAME) \
104 extern const unsigned function_index_##NAME; \
105 inline function NAME(const ex & p1, const ex & p2) { \
106     return function(function_index_##NAME, p1, p2); \
107 } \
108 inline function NAME(const basic & p1, const ex & p2) { \
109     return function(function_index_##NAME, ex(p1), p2); \
110 } \
111 inline function NAME(const ex & p1, const basic & p2) { \
112     return function(function_index_##NAME, p1, ex(p2)); \
113 } \
114 inline function NAME(const basic & p1, const basic & p2) { \
115     return function(function_index_##NAME, ex(p1), ex(p2)); \
116 }
117
118 #else // def CINT_CONVERSION_WORKAROUND
119
120 #define DECLARE_FUNCTION_1P(NAME) \
121 extern const unsigned function_index_##NAME; \
122 inline function NAME(const ex & p1) { \
123     return function(function_index_##NAME, p1); \
124 }
125 #define DECLARE_FUNCTION_2P(NAME) \
126 extern const unsigned function_index_##NAME; \
127 inline function NAME(const ex & p1, const ex & p2) { \
128     return function(function_index_##NAME, p1, p2); \
129 }
130
131 #endif // def CINT_CONVERSION_WORKAROUND
132
133 END_OF_DECLARE_FUNCTION_1_AND_2P_MACRO_NO_NAMESPACE
134
135 $declare_function_macro_no_namespace .= generate_from_to(
136     <<'END_OF_DECLARE_FUNCTION_MACRO_NO_NAMESPACE','const ex & p${N}','p${N}',3,$maxargs);
137 #define DECLARE_FUNCTION_${N}P(NAME) \\
138 extern const unsigned function_index_##NAME; \\
139 inline function NAME(${SEQ1}) { \\
140     return function(function_index_##NAME, ${SEQ2}); \\
141 }
142
143 END_OF_DECLARE_FUNCTION_MACRO_NO_NAMESPACE
144
145 $typedef_eval_funcp=generate(
146 'typedef ex (* eval_funcp_${N})(${SEQ1});'."\n",
147 'const ex &','');
148
149 $typedef_evalf_funcp=generate(
150 'typedef ex (* evalf_funcp_${N})(${SEQ1});'."\n",
151 'const ex &','');
152
153 $typedef_derivative_funcp=generate(
154 'typedef ex (* derivative_funcp_${N})(${SEQ1}, unsigned);'."\n",
155 'const ex &','');
156
157 $typedef_series_funcp=generate(
158 'typedef ex (* series_funcp_${N})(${SEQ1}, const symbol &, const ex &, int);'."\n",
159 'const ex &','');
160
161 $eval_func_interface=generate('    function_options & eval_func(eval_funcp_${N} e);'."\n",'','');
162
163 $evalf_func_interface=generate('    function_options & evalf_func(evalf_funcp_${N} ef);'."\n",'','');
164
165 $derivative_func_interface=generate('    function_options & derivative_func(derivative_funcp_${N} d);'."\n",'','');
166
167 $series_func_interface=generate('    function_options & series_func(series_funcp_${N} s);'."\n",'','');
168
169 $constructors_interface=generate(
170 '    function(unsigned ser, ${SEQ1});'."\n",
171 'const ex & param${N}','');
172
173 $constructors_implementation=generate(
174     <<'END_OF_CONSTRUCTORS_IMPLEMENTATION','const ex & param${N}','param${N}');
175 function::function(unsigned ser, ${SEQ1})
176     : exprseq(${SEQ2}), serial(ser)
177 {
178     debugmsg(\"function constructor from unsigned,${N}*ex\",LOGLEVEL_CONSTRUCT);
179     tinfo_key = TINFO_function;
180 }
181 END_OF_CONSTRUCTORS_IMPLEMENTATION
182
183 $eval_switch_statement=generate(
184     <<'END_OF_EVAL_SWITCH_STATEMENT','seq[${N}-1]','');
185     case ${N}:
186         eval_result=((eval_funcp_${N})(registered_functions()[serial].eval_f))(${SEQ1});
187         break;
188 END_OF_EVAL_SWITCH_STATEMENT
189
190 $evalf_switch_statement=generate(
191     <<'END_OF_EVALF_SWITCH_STATEMENT','eseq[${N}-1]','');
192     case ${N}:
193         return ((evalf_funcp_${N})(registered_functions()[serial].evalf_f))(${SEQ1});
194         break;
195 END_OF_EVALF_SWITCH_STATEMENT
196
197 $diff_switch_statement=generate(
198     <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','');
199     case ${N}:
200         return ((derivative_funcp_${N})(registered_functions()[serial].derivative_f))(${SEQ1},diff_param);
201         break;
202 END_OF_DIFF_SWITCH_STATEMENT
203
204 $series_switch_statement=generate(
205     <<'END_OF_SERIES_SWITCH_STATEMENT','seq[${N}-1]','');
206     case ${N}:
207         try {
208             res = ((series_funcp_${N})(registered_functions()[serial].series_f))(${SEQ1},s,point,order);
209         } catch (do_taylor) {
210             res = basic::series(s, point, order);
211         }
212         return res;
213         break;
214 END_OF_SERIES_SWITCH_STATEMENT
215
216 $eval_func_implementation=generate(
217     <<'END_OF_EVAL_FUNC_IMPLEMENTATION','','');
218 function_options & function_options::eval_func(eval_funcp_${N} e)
219 {
220     test_and_set_nparams(${N});
221     eval_f=eval_funcp(e);
222     return *this;
223 }        
224 END_OF_EVAL_FUNC_IMPLEMENTATION
225
226 $evalf_func_implementation=generate(
227     <<'END_OF_EVALF_FUNC_IMPLEMENTATION','','');
228 function_options & function_options::evalf_func(evalf_funcp_${N} ef)
229 {
230     test_and_set_nparams(${N});
231     evalf_f=evalf_funcp(ef);
232     return *this;
233 }        
234 END_OF_EVALF_FUNC_IMPLEMENTATION
235
236 $derivative_func_implementation=generate(
237     <<'END_OF_DERIVATIVE_FUNC_IMPLEMENTATION','','');
238 function_options & function_options::derivative_func(derivative_funcp_${N} d)
239 {
240     test_and_set_nparams(${N});
241     derivative_f=derivative_funcp(d);
242     return *this;
243 }        
244 END_OF_DERIVATIVE_FUNC_IMPLEMENTATION
245
246 $series_func_implementation=generate(
247     <<'END_OF_SERIES_FUNC_IMPLEMENTATION','','');
248 function_options & function_options::series_func(series_funcp_${N} s)
249 {
250     test_and_set_nparams(${N});
251     series_f=series_funcp(s);
252     return *this;
253 }        
254 END_OF_SERIES_FUNC_IMPLEMENTATION
255
256 $interface=<<END_OF_INTERFACE;
257 /** \@file function.h
258  *
259  *  Interface to abstract class function (new function concept). */
260
261 /*
262  *  This file was generated automatically by function.pl.
263  *  Please do not modify it directly, edit the perl script instead!
264  *  function.pl options: \$maxargs=${maxargs}
265  *
266  *  GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
267  *
268  *  This program is free software; you can redistribute it and/or modify
269  *  it under the terms of the GNU General Public License as published by
270  *  the Free Software Foundation; either version 2 of the License, or
271  *  (at your option) any later version.
272  *
273  *  This program is distributed in the hope that it will be useful,
274  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
275  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
276  *  GNU General Public License for more details.
277  *
278  *  You should have received a copy of the GNU General Public License
279  *  along with this program; if not, write to the Free Software
280  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
281  */
282
283 #ifndef __GINAC_FUNCTION_H__
284 #define __GINAC_FUNCTION_H__
285
286 #include <string>
287 #include <vector>
288
289 #ifdef __CINT__
290 // CINT needs <algorithm> to work properly with <vector> 
291 #include <algorithm>
292 #endif // def __CINT__
293
294 #include "exprseq.h"
295
296 #ifndef NO_NAMESPACE_GINAC
297
298 // the following lines have been generated for max. ${maxargs} parameters
299 $declare_function_macro_namespace
300 // end of generated lines
301
302 #else // ndef NO_NAMESPACE_GINAC
303
304 // the following lines have been generated for max. ${maxargs} parameters
305 $declare_function_macro_no_namespace
306 // end of generated lines
307
308 #endif // ndef NO_NAMESPACE_GINAC
309
310 #ifndef NO_NAMESPACE_GINAC
311
312 #define REGISTER_FUNCTION(NAME,OPT) \\
313 const unsigned function_index_##NAME= \\
314     GiNaC::function::register_new(GiNaC::function_options(#NAME).OPT);
315
316 #define REGISTER_FUNCTION_OLD(NAME,E,EF,D,S) \\
317 const unsigned function_index_##NAME= \\
318     GiNaC::function::register_new(GiNaC::function_options(#NAME). \\
319                                   eval_func(E). \\
320                                   evalf_func(EF). \\
321                                   derivative_func(D). \\
322                                   series_func(S));
323
324 #else // ndef NO_NAMESPACE_GINAC
325
326 #define REGISTER_FUNCTION(NAME,OPT) \\
327 const unsigned function_index_##NAME= \\
328     function::register_new(function_options(#NAME).OPT);
329
330 #define REGISTER_FUNCTION_OLD(NAME,E,EF,D,S) \\
331 const unsigned function_index_##NAME= \\
332     function::register_new(function_options(#NAME). \\
333                            eval_func(E). \\
334                            evalf_func(EF). \\
335                            derivative_func(D). \\
336                            series_func(S));
337
338 #endif // ndef NO_NAMESPACE_GINAC
339
340 #define BEGIN_TYPECHECK \\
341 bool automatic_typecheck=true;
342
343 #define TYPECHECK(VAR,TYPE) \\
344 if (!is_ex_exactly_of_type(VAR,TYPE)) { \\
345     automatic_typecheck=false; \\
346 } else
347
348 #ifndef NO_NAMESPACE_GINAC
349
350 #define TYPECHECK_INTEGER(VAR) \\
351 if (!(VAR).info(GiNaC::info_flags::integer)) { \\
352     automatic_typecheck=false; \\
353 } else
354
355 #else // ndef NO_NAMESPACE_GINAC
356
357 #define TYPECHECK_INTEGER(VAR) \\
358 if (!(VAR).info(info_flags::integer)) { \\
359     automatic_typecheck=false; \\
360 } else
361
362 #endif // ndef NO_NAMESPACE_GINAC
363
364 #define END_TYPECHECK(RV) \\
365 {} \\
366 if (!automatic_typecheck) { \\
367     return RV.hold(); \\
368 }
369
370 #ifndef NO_NAMESPACE_GINAC
371 namespace GiNaC {
372 #endif // ndef NO_NAMESPACE_GINAC
373
374 class function;
375
376 typedef ex (* eval_funcp)();
377 typedef ex (* evalf_funcp)();
378 typedef ex (* derivative_funcp)();
379 typedef ex (* series_funcp)();
380
381 // the following lines have been generated for max. ${maxargs} parameters
382 $typedef_eval_funcp
383 $typedef_evalf_funcp
384 $typedef_derivative_funcp
385 $typedef_series_funcp
386 // end of generated lines
387
388 class function_options
389 {
390     friend class function;
391 public:
392     function_options();
393     function_options(string const & n, string const & tn=string());
394     ~function_options();
395     void initialize(void);
396     function_options & set_name(string const & n, string const & tn=string());
397 // the following lines have been generated for max. ${maxargs} parameters
398 $eval_func_interface
399 $evalf_func_interface
400 $derivative_func_interface
401 $series_func_interface
402 // end of generated lines
403     function_options & set_return_type(unsigned rt, unsigned rtt=0);
404     function_options & do_not_evalf_params(void);
405     function_options & remember(unsigned size, unsigned assoc_size=0,
406                                 unsigned strategy=remember_strategies::delete_never);
407     function_options & overloaded(unsigned o);
408     void test_and_set_nparams(unsigned n);
409     string get_name(void) const { return name; }
410     unsigned get_nparams(void) const { return nparams; }
411
412 protected:
413     string name;
414     string TeX_name;
415
416     unsigned nparams;
417
418     eval_funcp eval_f;
419     evalf_funcp evalf_f;
420     derivative_funcp derivative_f;
421     series_funcp series_f;
422
423     bool evalf_params_first;
424
425     bool use_return_type;
426     unsigned return_type;
427     unsigned return_type_tinfo;
428
429     bool use_remember;
430     unsigned remember_size;
431     unsigned remember_assoc_size;
432     unsigned remember_strategy;
433
434     unsigned functions_with_same_name;
435 };
436
437 /** The class function is used to implement builtin functions like sin, cos...
438     and user defined functions */
439 class function : public exprseq
440 {
441     GINAC_DECLARE_REGISTERED_CLASS(function, exprseq)
442
443     // CINT has a linking problem
444     friend void ginsh_get_ginac_functions(void);
445
446     friend class remember_table_entry;
447     // friend class remember_table_list;
448     // friend class remember_table;
449
450 // member functions
451
452     // default constructor, destructor, copy constructor assignment operator and helpers
453 public:
454     function();
455     ~function();
456     function(const function & other);
457     const function & operator=(const function & other);
458 protected:
459     void copy(const function & other);
460     void destroy(bool call_parent);
461
462     // other constructors
463 public:
464     function(unsigned ser);
465     // the following lines have been generated for max. ${maxargs} parameters
466 $constructors_interface
467     // end of generated lines
468     function(unsigned ser, const exprseq & es);
469     function(unsigned ser, const exvector & v, bool discardable=0);
470     function(unsigned ser, exvector * vp); // vp will be deleted
471
472     // functions overriding virtual functions from bases classes
473 public:
474     basic * duplicate() const;
475     void printraw(ostream & os) const; 
476     void print(ostream & os, unsigned upper_precedence=0) const;
477     void printtree(ostream & os, unsigned indent) const;
478     void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
479     ex expand(unsigned options=0) const;
480     ex eval(int level=0) const;
481     ex evalf(int level=0) const;
482     ex series(const symbol & s, const ex & point, int order) const;
483     ex thisexprseq(const exvector & v) const;
484     ex thisexprseq(exvector * vp) const;
485 protected:
486     ex derivative(const symbol & s) const;
487     int compare_same_type(const basic & other) const;
488     bool is_equal_same_type(const basic & other) const;
489     unsigned return_type(void) const;
490     unsigned return_type_tinfo(void) const;
491     
492     // new virtual functions which can be overridden by derived classes
493     // none
494     
495     // non-virtual functions in this class
496 protected:
497     ex pderivative(unsigned diff_param) const; // partial differentiation
498     static vector<function_options> & registered_functions(void);
499     bool lookup_remember_table(ex & result) const;
500     void store_remember_table(ex const & result) const;
501 public:
502     static unsigned register_new(function_options const & opt);
503     unsigned getserial(void) const {return serial;}
504     
505 // member variables
506
507 protected:
508     unsigned serial;
509 };
510
511 // utility macros
512
513 #ifndef NO_NAMESPACE_GINAC
514
515 #define is_ex_the_function(OBJ, FUNCNAME) \\
516     (is_ex_exactly_of_type(OBJ, function) && static_cast<GiNaC::function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
517
518 #else // ndef NO_NAMESPACE_GINAC
519
520 #define is_ex_the_function(OBJ, FUNCNAME) \\
521     (is_ex_exactly_of_type(OBJ, function) && static_cast<function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
522
523 #endif // ndef NO_NAMESPACE_GINAC
524
525 // global constants
526
527 extern const function some_function;
528 extern const type_info & typeid_function;
529
530 #ifndef NO_NAMESPACE_GINAC
531 } // namespace GiNaC
532 #endif // ndef NO_NAMESPACE_GINAC
533
534 #endif // ndef __GINAC_FUNCTION_H__
535
536 END_OF_INTERFACE
537
538 $implementation=<<END_OF_IMPLEMENTATION;
539 /** \@file function.cpp
540  *
541  *  Implementation of class function. */
542
543 /*
544  *  This file was generated automatically by function.pl.
545  *  Please do not modify it directly, edit the perl script instead!
546  *  function.pl options: \$maxargs=${maxargs}
547  *
548  *  GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
549  *
550  *  This program is free software; you can redistribute it and/or modify
551  *  it under the terms of the GNU General Public License as published by
552  *  the Free Software Foundation; either version 2 of the License, or
553  *  (at your option) any later version.
554  *
555  *  This program is distributed in the hope that it will be useful,
556  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
557  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
558  *  GNU General Public License for more details.
559  *
560  *  You should have received a copy of the GNU General Public License
561  *  along with this program; if not, write to the Free Software
562  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
563  */
564
565 #include <string>
566 #include <stdexcept>
567 #include <list>
568
569 #include "function.h"
570 #include "ex.h"
571 #include "archive.h"
572 #include "inifcns.h"
573 #include "utils.h"
574 #include "debugmsg.h"
575
576 #ifndef NO_NAMESPACE_GINAC
577 namespace GiNaC {
578 #endif // ndef NO_NAMESPACE_GINAC
579
580 function_options::function_options()
581 {
582     initialize();
583 }
584
585 function_options::function_options(string const & n, string const & tn)
586 {
587     initialize();
588     set_name(n,tn);
589 }
590
591 function_options::~function_options()
592 {
593     // nothing to clean up at the moment
594 }
595
596 void function_options::initialize(void)
597 {
598     set_name("unnamed_function","\\\\operatorname{unnamed}");
599     nparams=0;
600     eval_f=evalf_f=derivative_f=series_f=0;
601     evalf_params_first=true;
602     use_return_type=false;
603     use_remember=false;
604     functions_with_same_name=1;
605 }
606
607 function_options & function_options::set_name(string const & n,
608                                               string const & tn)
609 {
610     name=n;
611     if (tn==string()) {
612         TeX_name="\\\\operatorname{"+name+"}";
613     } else {
614         TeX_name=tn;
615     }
616     return *this;
617 }
618
619 // the following lines have been generated for max. ${maxargs} parameters
620 $eval_func_implementation
621 $evalf_func_implementation
622 $derivative_func_implementation
623 $series_func_implementation
624 // end of generated lines
625
626 function_options & function_options::set_return_type(unsigned rt, unsigned rtt)
627 {
628     use_return_type=true;
629     return_type=rt;
630     return_type_tinfo=rtt;
631     return *this;
632 }
633
634 function_options & function_options::do_not_evalf_params(void)
635 {
636     evalf_params_first=false;
637     return *this;
638 }
639
640 function_options & function_options::remember(unsigned size,
641                                               unsigned assoc_size,
642                                               unsigned strategy)
643 {
644     use_remember=true;
645     remember_size=size;
646     remember_assoc_size=assoc_size;
647     remember_strategy=strategy;
648     return *this;
649 }
650
651 function_options & function_options::overloaded(unsigned o)
652 {
653     functions_with_same_name=o;
654     return *this;
655 }
656     
657 void function_options::test_and_set_nparams(unsigned n)
658 {
659     if (nparams==0) {
660         nparams=n;
661     } else if (nparams!=n) {
662         // we do not throw an exception here because this code is
663         // usually executed before main(), so the exception could not
664         // caught anyhow
665         cerr << "WARNING: number of parameters ("
666              << n << ") differs from number set before (" 
667              << nparams << ")" << endl;
668     }
669 }
670
671 class remember_table_entry {
672 public:
673     remember_table_entry(function const & f, ex const & r) :
674         hashvalue(f.gethash()), seq(f.seq), result(r)
675     {
676         last_access=0;
677         successful_hits=0;
678     }
679     bool is_equal(function const & f) const
680     {
681         GINAC_ASSERT(f.seq.size()==seq.size());
682         if (f.gethash()!=hashvalue) return false;
683         for (unsigned i=0; i<seq.size(); ++i) {
684             if (!seq[i].is_equal(f.seq[i])) return false;
685         }
686         last_access=access_counter++;
687         successful_hits++;
688         return true;
689     }
690     unsigned hashvalue;
691     exvector seq;
692     ex result;
693     mutable unsigned long last_access;
694     mutable unsigned successful_hits;
695
696     static unsigned access_counter;
697 };    
698
699 unsigned remember_table_entry::access_counter=0;
700
701 class remember_table_list : public list<remember_table_entry> {
702 public:
703     remember_table_list()
704     {
705         max_assoc_size=0;
706         delete_strategy=0;
707     }
708     remember_table_list(unsigned as, unsigned strat)
709     {
710         max_assoc_size=as;
711         delete_strategy=strat;
712     }
713     void add_entry(function const & f, ex const & result)
714     {
715         push_back(remember_table_entry(f,result));
716     }        
717     bool lookup_entry(function const & f, ex & result) const
718     {
719         for (const_iterator cit=begin(); cit!=end(); ++cit) {
720             if (cit->is_equal(f)) {
721                 result=cit->result;
722                 return true;
723             }
724         }
725         return false;
726     }
727 protected:
728     unsigned max_assoc_size;
729     unsigned delete_strategy;
730 };
731
732
733 class remember_table : public vector<remember_table_list> {
734 public:
735     remember_table()
736     {
737     }
738     remember_table(unsigned s, unsigned as, unsigned strat)
739     {
740         calc_size(s);
741         reserve(table_size);
742         for (unsigned i=0; i<table_size; ++i) {
743             push_back(remember_table_list(as,strat));
744         }
745     }
746     bool lookup_entry(function const & f, ex & result) const
747     {
748         unsigned entry=f.gethash() & (table_size-1);
749         if (entry>=size()) {
750             cerr << "entry=" << entry << ",size=" << size() << endl;
751         }
752         GINAC_ASSERT(entry<size());
753         return operator[](entry).lookup_entry(f,result);
754     }
755     void add_entry(function const & f, ex const & result)
756     {
757         unsigned entry=f.gethash() & (table_size-1);
758         GINAC_ASSERT(entry<size());
759         operator[](entry).add_entry(f,result);
760     }        
761     void calc_size(unsigned s)
762     {
763         // use some power of 2 next to s
764         table_size=1 << log2(s);
765     }
766 protected:
767     unsigned table_size;
768 };      
769
770 // this is not declared as a static function in the class function
771 // (like registered_function()) because of issues with cint
772 static vector<remember_table> & remember_tables(void)
773 {
774     static vector<remember_table> * rt=new vector<remember_table>;
775     return *rt;
776 }
777
778 GINAC_IMPLEMENT_REGISTERED_CLASS(function, exprseq)
779
780 //////////
781 // default constructor, destructor, copy constructor assignment operator and helpers
782 //////////
783
784 // public
785
786 function::function() : serial(0)
787 {
788     debugmsg("function default constructor",LOGLEVEL_CONSTRUCT);
789     tinfo_key = TINFO_function;
790 }
791
792 function::~function()
793 {
794     debugmsg("function destructor",LOGLEVEL_DESTRUCT);
795     destroy(0);
796 }
797
798 function::function(const function & other)
799 {
800     debugmsg("function copy constructor",LOGLEVEL_CONSTRUCT);
801     copy(other);
802 }
803
804 const function & function::operator=(const function & other)
805 {
806     debugmsg("function operator=",LOGLEVEL_ASSIGNMENT);
807     if (this != &other) {
808         destroy(1);
809         copy(other);
810     }
811     return *this;
812 }
813
814 // protected
815
816 void function::copy(const function & other)
817 {
818     exprseq::copy(other);
819     serial=other.serial;
820 }
821
822 void function::destroy(bool call_parent)
823 {
824     if (call_parent) exprseq::destroy(call_parent);
825 }
826
827 //////////
828 // other constructors
829 //////////
830
831 // public
832
833 function::function(unsigned ser) : serial(ser)
834 {
835     debugmsg("function constructor from unsigned",LOGLEVEL_CONSTRUCT);
836     tinfo_key = TINFO_function;
837 }
838
839 // the following lines have been generated for max. ${maxargs} parameters
840 $constructors_implementation
841 // end of generated lines
842
843 function::function(unsigned ser, const exprseq & es) : exprseq(es), serial(ser)
844 {
845     debugmsg("function constructor from unsigned,exprseq",LOGLEVEL_CONSTRUCT);
846     tinfo_key = TINFO_function;
847 }
848
849 function::function(unsigned ser, const exvector & v, bool discardable) 
850     : exprseq(v,discardable), serial(ser)
851 {
852     debugmsg("function constructor from string,exvector,bool",LOGLEVEL_CONSTRUCT);
853     tinfo_key = TINFO_function;
854 }
855
856 function::function(unsigned ser, exvector * vp) 
857     : exprseq(vp), serial(ser)
858 {
859     debugmsg("function constructor from unsigned,exvector *",LOGLEVEL_CONSTRUCT);
860     tinfo_key = TINFO_function;
861 }
862
863 //////////
864 // archiving
865 //////////
866
867 /** Construct object from archive_node. */
868 function::function(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
869 {
870     debugmsg("function constructor from archive_node", LOGLEVEL_CONSTRUCT);
871
872     // Find serial number by function name
873     string s;
874     if (n.find_string("name", s)) {
875         unsigned int ser = 0;
876         vector<function_options>::const_iterator i = registered_functions().begin(), iend = registered_functions().end();
877         while (i != iend) {
878             if (s == i->name) {
879                 serial = ser;
880                 return;
881             }
882             i++; ser++;
883         }
884         throw (std::runtime_error("unknown function '" + s + "' in archive"));
885     } else
886         throw (std::runtime_error("unnamed function in archive"));
887 }
888
889 /** Unarchive the object. */
890 ex function::unarchive(const archive_node &n, const lst &sym_lst)
891 {
892     return (new function(n, sym_lst))->setflag(status_flags::dynallocated);
893 }
894
895 /** Archive the object. */
896 void function::archive(archive_node &n) const
897 {
898     inherited::archive(n);
899     GINAC_ASSERT(serial < registered_functions().size());
900     n.add_string("name", registered_functions()[serial].name);
901 }
902
903 //////////
904 // functions overriding virtual functions from bases classes
905 //////////
906
907 // public
908
909 basic * function::duplicate() const
910 {
911     debugmsg("function duplicate",LOGLEVEL_DUPLICATE);
912     return new function(*this);
913 }
914
915 void function::printraw(ostream & os) const
916 {
917     debugmsg("function printraw",LOGLEVEL_PRINT);
918
919     GINAC_ASSERT(serial<registered_functions().size());
920
921     os << "function(name=" << registered_functions()[serial].name;
922     for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
923         os << ",";
924         (*it).bp->print(os);
925     }
926     os << ")";
927 }
928
929 void function::print(ostream & os, unsigned upper_precedence) const
930 {
931     debugmsg("function print",LOGLEVEL_PRINT);
932
933     GINAC_ASSERT(serial<registered_functions().size());
934
935     os << registered_functions()[serial].name;
936     printseq(os,'(',',',')',exprseq::precedence,function::precedence);
937 }
938
939 void function::printtree(ostream & os, unsigned indent) const
940 {
941     debugmsg("function printtree",LOGLEVEL_PRINT);
942
943     GINAC_ASSERT(serial<registered_functions().size());
944
945     os << string(indent,' ') << "function "
946        << registered_functions()[serial].name
947        << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
948        << ", flags=" << flags
949        << ", nops=" << nops() << endl;
950     for (unsigned i=0; i<nops(); ++i) {
951         seq[i].printtree(os,indent+delta_indent);
952     }
953     os << string(indent+delta_indent,' ') << "=====" << endl;
954 }
955
956 void function::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
957 {
958     debugmsg("function print csrc",LOGLEVEL_PRINT);
959
960     GINAC_ASSERT(serial<registered_functions().size());
961
962         // Print function name in lowercase
963     string lname;
964     lname=registered_functions()[serial].name;
965     for (unsigned i=0; i<lname.size(); i++)
966         lname[i] = tolower(lname[i]);
967     os << lname << "(";
968
969         // Print arguments, separated by commas
970     exvector::const_iterator it = seq.begin();
971     exvector::const_iterator itend = seq.end();
972     while (it != itend) {
973         it->bp->printcsrc(os, type, 0);
974         it++;
975         if (it != itend)
976             os << ",";
977     }
978     os << ")";
979 }
980
981 ex function::expand(unsigned options) const
982 {
983     return this->setflag(status_flags::expanded);
984 }
985
986 ex function::eval(int level) const
987 {
988     GINAC_ASSERT(serial<registered_functions().size());
989
990     if (level>1) {
991         // first evaluate children, then we will end up here again
992         return function(serial,evalchildren(level));
993     }
994
995     if (registered_functions()[serial].eval_f==0) {
996         return this->hold();
997     }
998
999     bool use_remember=registered_functions()[serial].use_remember;
1000     ex eval_result;
1001     if (use_remember && lookup_remember_table(eval_result)) {
1002         return eval_result;
1003     }
1004
1005     switch (registered_functions()[serial].nparams) {
1006         // the following lines have been generated for max. ${maxargs} parameters
1007 ${eval_switch_statement}
1008         // end of generated lines
1009     default:
1010         throw(std::logic_error("function::eval(): invalid nparams"));
1011     }
1012     if (use_remember) {
1013         store_remember_table(eval_result);
1014     }
1015     return eval_result;
1016 }
1017
1018 ex function::evalf(int level) const
1019 {
1020     GINAC_ASSERT(serial<registered_functions().size());
1021
1022     exvector eseq=evalfchildren(level);
1023     
1024     if (registered_functions()[serial].evalf_f==0) {
1025         return function(serial,eseq).hold();
1026     }
1027     switch (registered_functions()[serial].nparams) {
1028         // the following lines have been generated for max. ${maxargs} parameters
1029 ${evalf_switch_statement}
1030         // end of generated lines
1031     }
1032     throw(std::logic_error("function::evalf(): invalid nparams"));
1033 }
1034
1035 ex function::thisexprseq(const exvector & v) const
1036 {
1037     return function(serial,v);
1038 }
1039
1040 ex function::thisexprseq(exvector * vp) const
1041 {
1042     return function(serial,vp);
1043 }
1044
1045 /** Implementation of ex::series for functions.
1046  *  \@see ex::series */
1047 ex function::series(const symbol & s, const ex & point, int order) const
1048 {
1049     GINAC_ASSERT(serial<registered_functions().size());
1050
1051     if (registered_functions()[serial].series_f==0) {
1052         return basic::series(s, point, order);
1053     }
1054     ex res;
1055     switch (registered_functions()[serial].nparams) {
1056         // the following lines have been generated for max. ${maxargs} parameters
1057 ${series_switch_statement}
1058         // end of generated lines
1059     }
1060     throw(std::logic_error("function::series(): invalid nparams"));
1061 }
1062
1063 // protected
1064
1065
1066 /** Implementation of ex::diff() for functions. It applies the chain rule,
1067  *  except for the Order term function.
1068  *  \@see ex::diff */
1069 ex function::derivative(const symbol & s) const
1070 {
1071     ex result;
1072     
1073     if (serial==function_index_Order) {
1074         // Order Term function only differentiates the argument
1075         return Order(seq[0].diff(s));
1076     } else {
1077         // Chain rule
1078         ex arg_diff;
1079         for (unsigned i=0; i!=seq.size(); i++) {
1080             arg_diff = seq[i].diff(s);
1081             // We apply the chain rule only when it makes sense.  This is not
1082             // just for performance reasons but also to allow functions to
1083             // throw when differentiated with respect to one of its arguments
1084             // without running into trouble with our automatic full
1085             // differentiation:
1086             if (!arg_diff.is_zero())
1087                 result += pderivative(i)*arg_diff;
1088         }
1089     }
1090     return result;
1091 }
1092
1093 int function::compare_same_type(const basic & other) const
1094 {
1095     GINAC_ASSERT(is_of_type(other, function));
1096     const function & o=static_cast<function &>(const_cast<basic &>(other));
1097
1098     if (serial!=o.serial) {
1099         return serial < o.serial ? -1 : 1;
1100     }
1101     return exprseq::compare_same_type(o);
1102 }
1103
1104 bool function::is_equal_same_type(const basic & other) const
1105 {
1106     GINAC_ASSERT(is_of_type(other, function));
1107     const function & o=static_cast<function &>(const_cast<basic &>(other));
1108
1109     if (serial!=o.serial) return false;
1110     return exprseq::is_equal_same_type(o);
1111 }
1112
1113 unsigned function::return_type(void) const
1114 {
1115     if (seq.size()==0) {
1116         return return_types::commutative;
1117     }
1118     return (*seq.begin()).return_type();
1119 }
1120    
1121 unsigned function::return_type_tinfo(void) const
1122 {
1123     if (seq.size()==0) {
1124         return tinfo_key;
1125     }
1126     return (*seq.begin()).return_type_tinfo();
1127 }
1128
1129 //////////
1130 // new virtual functions which can be overridden by derived classes
1131 //////////
1132
1133 // none
1134
1135 //////////
1136 // non-virtual functions in this class
1137 //////////
1138
1139 // protected
1140
1141 ex function::pderivative(unsigned diff_param) const // partial differentiation
1142 {
1143     GINAC_ASSERT(serial<registered_functions().size());
1144     
1145     if (registered_functions()[serial].derivative_f==0) {
1146         throw(std::logic_error(string("function::pderivative(") + registered_functions()[serial].name + "): no diff function defined"));
1147     }
1148     switch (registered_functions()[serial].nparams) {
1149         // the following lines have been generated for max. ${maxargs} parameters
1150 ${diff_switch_statement}
1151         // end of generated lines
1152     }        
1153     throw(std::logic_error("function::pderivative(): no diff function defined"));
1154 }
1155
1156 vector<function_options> & function::registered_functions(void)
1157 {
1158     static vector<function_options> * rf=new vector<function_options>;
1159     return *rf;
1160 }
1161
1162 bool function::lookup_remember_table(ex & result) const
1163 {
1164     return remember_tables()[serial].lookup_entry(*this,result);
1165 }
1166
1167 void function::store_remember_table(ex const & result) const
1168 {
1169     remember_tables()[serial].add_entry(*this,result);
1170 }
1171
1172 // public
1173
1174 unsigned function::register_new(function_options const & opt)
1175 {
1176     unsigned same_name=0;
1177     for (unsigned i=0; i<registered_functions().size(); ++i) {
1178         if (registered_functions()[i].name==opt.name) {
1179             same_name++;
1180         }
1181     }
1182     if (same_name>=opt.functions_with_same_name) {
1183         // we do not throw an exception here because this code is
1184         // usually executed before main(), so the exception could not
1185         // caught anyhow
1186         cerr << "WARNING: function name " << opt.name
1187              << " already in use!" << endl;
1188     }
1189     registered_functions().push_back(opt);
1190     if (opt.use_remember) {
1191         remember_tables().push_back(remember_table(opt.remember_size,
1192                                                    opt.remember_assoc_size,
1193                                                    opt.remember_strategy));
1194     } else {
1195         remember_tables().push_back(remember_table());
1196     }
1197     return registered_functions().size()-1;
1198 }
1199
1200 //////////
1201 // static member variables
1202 //////////
1203
1204 // none
1205
1206 //////////
1207 // global constants
1208 //////////
1209
1210 const function some_function;
1211 const type_info & typeid_function=typeid(some_function);
1212
1213 #ifndef NO_NAMESPACE_GINAC
1214 } // namespace GiNaC
1215 #endif // ndef NO_NAMESPACE_GINAC
1216
1217 END_OF_IMPLEMENTATION
1218
1219 print "Creating interface file function.h...";
1220 open OUT,">function.h" or die "cannot open function.h";
1221 print OUT $interface;
1222 close OUT;
1223 print "ok.\n";
1224
1225 print "Creating implementation file function.cpp...";
1226 open OUT,">function.cpp" or die "cannot open function.cpp";
1227 print OUT $implementation;
1228 close OUT;
1229 print "ok.\n";
1230
1231 print "done.\n";