]> www.ginac.de Git - ginac.git/blob - ginac/function.pl
- Added Cint 5.4.25 to the list of working Cints
[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 {
20     my ($template,$seq_template1,$seq_template2)=@_;
21     my ($res,$N,$SEQ);
22
23     $res='';
24     for ($N=1; $N<=$maxargs; $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 $declare_function_macro_namespace=generate(
35     <<'END_OF_DECLARE_FUNCTION_MACRO_NAMESPACE','const GiNaC::ex & p${N}','p${N}');
36 #define DECLARE_FUNCTION_${N}P(NAME) \\
37 extern const unsigned function_index_##NAME; \\
38 inline GiNaC::function NAME(${SEQ1}) { \\
39     return GiNaC::function(function_index_##NAME, ${SEQ2}); \\
40 }
41
42 END_OF_DECLARE_FUNCTION_MACRO_NAMESPACE
43
44 $declare_function_macro_no_namespace=generate(
45     <<'END_OF_DECLARE_FUNCTION_MACRO_NO_NAMESPACE','const ex & p${N}','p${N}');
46 #define DECLARE_FUNCTION_${N}P(NAME) \\
47 extern const unsigned function_index_##NAME; \\
48 inline function NAME(${SEQ1}) { \\
49     return function(function_index_##NAME, ${SEQ2}); \\
50 }
51
52 END_OF_DECLARE_FUNCTION_MACRO_NO_NAMESPACE
53
54 $typedef_eval_funcp=generate(
55 'typedef ex (* eval_funcp_${N})(${SEQ1});'."\n",
56 'const ex &','');
57
58 $typedef_evalf_funcp=generate(
59 'typedef ex (* evalf_funcp_${N})(${SEQ1});'."\n",
60 'const ex &','');
61
62 $typedef_derivative_funcp=generate(
63 'typedef ex (* derivative_funcp_${N})(${SEQ1}, unsigned);'."\n",
64 'const ex &','');
65
66 $typedef_series_funcp=generate(
67 'typedef ex (* series_funcp_${N})(${SEQ1}, const symbol &, const ex &, int);'."\n",
68 'const ex &','');
69
70 $constructors_interface=generate(
71 '    function(unsigned ser, ${SEQ1});'."\n",
72 'const ex & param${N}','');
73
74 $register_new_interface=generate(
75 '    static unsigned register_new(const char * nm, eval_funcp_${N} e,'."\n".
76 '                                 evalf_funcp_${N} ef=0, derivative_funcp_${N} d=0, series_funcp_${N} s=0);'.
77 "\n",'','');
78
79 $constructors_implementation=generate(
80     <<'END_OF_CONSTRUCTORS_IMPLEMENTATION','const ex & param${N}','param${N}');
81 function::function(unsigned ser, ${SEQ1})
82     : exprseq(${SEQ2}), serial(ser)
83 {
84     debugmsg(\"function constructor from unsigned,${N}*ex\",LOGLEVEL_CONSTRUCT);
85     tinfo_key = TINFO_function;
86 }
87 END_OF_CONSTRUCTORS_IMPLEMENTATION
88
89 $eval_switch_statement=generate(
90     <<'END_OF_EVAL_SWITCH_STATEMENT','eseq[${N}-1]','');
91     case ${N}:
92         return ((eval_funcp_${N})(registered_functions()[serial].e))(${SEQ1});
93         break;
94 END_OF_EVAL_SWITCH_STATEMENT
95
96 $evalf_switch_statement=generate(
97     <<'END_OF_EVALF_SWITCH_STATEMENT','eseq[${N}-1]','');
98     case ${N}:
99         return ((evalf_funcp_${N})(registered_functions()[serial].ef))(${SEQ1});
100         break;
101 END_OF_EVALF_SWITCH_STATEMENT
102
103 $diff_switch_statement=generate(
104     <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','');
105     case ${N}:
106         return ((derivative_funcp_${N})(registered_functions()[serial].d))(${SEQ1},diff_param);
107         break;
108 END_OF_DIFF_SWITCH_STATEMENT
109
110 $series_switch_statement=generate(
111     <<'END_OF_SERIES_SWITCH_STATEMENT','seq[${N}-1]','');
112     case ${N}:
113         try {
114             res = ((series_funcp_${N})(registered_functions()[serial].s))(${SEQ1},s,point,order);
115         } catch (do_taylor) {
116             res = basic::series(s, point, order);
117         }
118         return res;
119         break;
120 END_OF_SERIES_SWITCH_STATEMENT
121
122 $register_new_implementation=generate(
123     <<'END_OF_REGISTER_NEW_IMPLEMENTATION','','');
124 unsigned function::register_new(const char * nm, eval_funcp_${N} e,
125                                  evalf_funcp_${N} ef, derivative_funcp_${N} d, series_funcp_${N} s)
126 {
127     registered_function_info rfi={nm,${N},0,eval_funcp(e),
128                                   evalf_funcp(ef),derivative_funcp(d),series_funcp(s)};
129     registered_functions().push_back(rfi);
130     return registered_functions().size()-1;
131 }
132 END_OF_REGISTER_NEW_IMPLEMENTATION
133
134 $interface=<<END_OF_INTERFACE;
135 /** \@file function.h
136  *
137  *  Interface to abstract class function (new function concept). */
138
139 /*
140  *  This file was generated automatically by function.pl.
141  *  Please do not modify it directly, edit the perl script instead!
142  *  function.pl options: \$maxargs=${maxargs}
143  *
144  *  GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
145  *
146  *  This program is free software; you can redistribute it and/or modify
147  *  it under the terms of the GNU General Public License as published by
148  *  the Free Software Foundation; either version 2 of the License, or
149  *  (at your option) any later version.
150  *
151  *  This program is distributed in the hope that it will be useful,
152  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
153  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
154  *  GNU General Public License for more details.
155  *
156  *  You should have received a copy of the GNU General Public License
157  *  along with this program; if not, write to the Free Software
158  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
159  */
160
161 #ifndef __GINAC_FUNCTION_H__
162 #define __GINAC_FUNCTION_H__
163
164 #include <string>
165 #include <vector>
166
167 #ifdef __CINT__
168 // CINT needs <algorithm> to work properly with <vector> 
169 #include <algorithm>
170 #endif // def __CINT__
171
172 #include "exprseq.h"
173
174 #ifndef NO_NAMESPACE_GINAC
175
176 // the following lines have been generated for max. ${maxargs} parameters
177 $declare_function_macro_namespace
178 // end of generated lines
179
180 #else // ndef NO_NAMESPACE_GINAC
181
182 // the following lines have been generated for max. ${maxargs} parameters
183 $declare_function_macro_no_namespace
184 // end of generated lines
185
186 #endif // ndef NO_NAMESPACE_GINAC
187
188 #ifndef NO_NAMESPACE_GINAC
189
190 #define REGISTER_FUNCTION(NAME,E,EF,D,S) \\
191 const unsigned function_index_##NAME=GiNaC::function::register_new(#NAME,E,EF,D,S);
192
193 #else // ndef NO_NAMESPACE_GINAC
194
195 #define REGISTER_FUNCTION(NAME,E,EF,D,S) \\
196 const unsigned function_index_##NAME=function::register_new(#NAME,E,EF,D,S);
197
198 #endif // ndef NO_NAMESPACE_GINAC
199
200 #define BEGIN_TYPECHECK \\
201 bool automatic_typecheck=true;
202
203 #define TYPECHECK(VAR,TYPE) \\
204 if (!is_ex_exactly_of_type(VAR,TYPE)) { \\
205     automatic_typecheck=false; \\
206 } else
207
208 #ifndef NO_NAMESPACE_GINAC
209
210 #define TYPECHECK_INTEGER(VAR) \\
211 if (!(VAR).info(GiNaC::info_flags::integer)) { \\
212     automatic_typecheck=false; \\
213 } else
214
215 #else // ndef NO_NAMESPACE_GINAC
216
217 #define TYPECHECK_INTEGER(VAR) \\
218 if (!(VAR).info(info_flags::integer)) { \\
219     automatic_typecheck=false; \\
220 } else
221
222 #endif // ndef NO_NAMESPACE_GINAC
223
224 #define END_TYPECHECK(RV) \\
225 {} \\
226 if (!automatic_typecheck) { \\
227     return RV.hold(); \\
228 }
229
230 #ifndef NO_NAMESPACE_GINAC
231 namespace GiNaC {
232 #endif // ndef NO_NAMESPACE_GINAC
233
234 class function;
235
236 typedef ex (* eval_funcp)();
237 typedef ex (* evalf_funcp)();
238 typedef ex (* derivative_funcp)();
239 typedef ex (* series_funcp)();
240
241 // the following lines have been generated for max. ${maxargs} parameters
242 $typedef_eval_funcp
243 $typedef_evalf_funcp
244 $typedef_derivative_funcp
245 $typedef_series_funcp
246 // end of generated lines
247
248 struct registered_function_info {
249     const char * name;
250     unsigned nparams;
251     unsigned options;
252     eval_funcp e;
253     evalf_funcp ef;
254     derivative_funcp d;
255     series_funcp s;
256 };
257
258 /** The class function is used to implement builtin functions like sin, cos...
259     and user defined functions */
260 class function : public exprseq
261 {
262     GINAC_DECLARE_REGISTERED_CLASS(function, exprseq)
263
264     // CINT has a linking problem
265     friend void ginsh_get_ginac_functions(void);
266
267 // member functions
268
269     // default constructor, destructor, copy constructor assignment operator and helpers
270 public:
271     function();
272     ~function();
273     function(const function & other);
274     const function & operator=(const function & other);
275 protected:
276     void copy(const function & other);
277     void destroy(bool call_parent);
278
279     // other constructors
280 public:
281     function(unsigned ser);
282     // the following lines have been generated for max. ${maxargs} parameters
283 $constructors_interface
284     // end of generated lines
285     function(unsigned ser, const exprseq & es);
286     function(unsigned ser, const exvector & v, bool discardable=0);
287     function(unsigned ser, exvector * vp); // vp will be deleted
288
289     // functions overriding virtual functions from bases classes
290 public:
291     basic * duplicate() const;
292     void printraw(ostream & os) const; 
293     void print(ostream & os, unsigned upper_precedence=0) const;
294     void printtree(ostream & os, unsigned indent) const;
295     void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
296     ex expand(unsigned options=0) const;
297     ex eval(int level=0) const;
298     ex evalf(int level=0) const;
299     ex series(const symbol & s, const ex & point, int order) const;
300     ex thisexprseq(const exvector & v) const;
301     ex thisexprseq(exvector * vp) const;
302 protected:
303     ex derivative(const symbol & s) const;
304     int compare_same_type(const basic & other) const;
305     bool is_equal_same_type(const basic & other) const;
306     unsigned return_type(void) const;
307     unsigned return_type_tinfo(void) const;
308     
309     // new virtual functions which can be overridden by derived classes
310     // none
311     
312     // non-virtual functions in this class
313 protected:
314     ex pderivative(unsigned diff_param) const; // partial differentiation
315     static vector<registered_function_info> & registered_functions(void);
316 public:
317     // the following lines have been generated for max. ${maxargs} parameters
318 $register_new_interface
319     // end of generated lines
320     unsigned getserial(void) const {return serial;}
321     
322 // member variables
323
324 protected:
325     unsigned serial;
326 };
327
328 // utility macros
329
330 #ifndef NO_NAMESPACE_GINAC
331
332 #define is_ex_the_function(OBJ, FUNCNAME) \\
333     (is_ex_exactly_of_type(OBJ, function) && static_cast<GiNaC::function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
334
335 #else // ndef NO_NAMESPACE_GINAC
336
337 #define is_ex_the_function(OBJ, FUNCNAME) \\
338     (is_ex_exactly_of_type(OBJ, function) && static_cast<function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
339
340 #endif // ndef NO_NAMESPACE_GINAC
341
342 // global constants
343
344 extern const function some_function;
345 extern const type_info & typeid_function;
346
347 #ifndef NO_NAMESPACE_GINAC
348 } // namespace GiNaC
349 #endif // ndef NO_NAMESPACE_GINAC
350
351 #endif // ndef __GINAC_FUNCTION_H__
352
353 END_OF_INTERFACE
354
355 $implementation=<<END_OF_IMPLEMENTATION;
356 /** \@file function.cpp
357  *
358  *  Implementation of class function. */
359
360 /*
361  *  This file was generated automatically by function.pl.
362  *  Please do not modify it directly, edit the perl script instead!
363  *  function.pl options: \$maxargs=${maxargs}
364  *
365  *  GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
366  *
367  *  This program is free software; you can redistribute it and/or modify
368  *  it under the terms of the GNU General Public License as published by
369  *  the Free Software Foundation; either version 2 of the License, or
370  *  (at your option) any later version.
371  *
372  *  This program is distributed in the hope that it will be useful,
373  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
374  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
375  *  GNU General Public License for more details.
376  *
377  *  You should have received a copy of the GNU General Public License
378  *  along with this program; if not, write to the Free Software
379  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
380  */
381
382 #include <string>
383 #include <stdexcept>
384
385 #include "function.h"
386 #include "ex.h"
387 #include "archive.h"
388 #include "inifcns.h"
389 #include "utils.h"
390 #include "debugmsg.h"
391
392 #ifndef NO_NAMESPACE_GINAC
393 namespace GiNaC {
394 #endif // ndef NO_NAMESPACE_GINAC
395
396 GINAC_IMPLEMENT_REGISTERED_CLASS(function, exprseq)
397
398 //////////
399 // default constructor, destructor, copy constructor assignment operator and helpers
400 //////////
401
402 // public
403
404 function::function() : serial(0)
405 {
406     debugmsg("function default constructor",LOGLEVEL_CONSTRUCT);
407     tinfo_key = TINFO_function;
408 }
409
410 function::~function()
411 {
412     debugmsg("function destructor",LOGLEVEL_DESTRUCT);
413     destroy(0);
414 }
415
416 function::function(const function & other)
417 {
418     debugmsg("function copy constructor",LOGLEVEL_CONSTRUCT);
419     copy(other);
420 }
421
422 const function & function::operator=(const function & other)
423 {
424     debugmsg("function operator=",LOGLEVEL_ASSIGNMENT);
425     if (this != &other) {
426         destroy(1);
427         copy(other);
428     }
429     return *this;
430 }
431
432 // protected
433
434 void function::copy(const function & other)
435 {
436     exprseq::copy(other);
437     serial=other.serial;
438 }
439
440 void function::destroy(bool call_parent)
441 {
442     if (call_parent) exprseq::destroy(call_parent);
443 }
444
445 //////////
446 // other constructors
447 //////////
448
449 // public
450
451 function::function(unsigned ser) : serial(ser)
452 {
453     debugmsg("function constructor from unsigned",LOGLEVEL_CONSTRUCT);
454     tinfo_key = TINFO_function;
455 }
456
457 // the following lines have been generated for max. ${maxargs} parameters
458 $constructors_implementation
459 // end of generated lines
460
461 function::function(unsigned ser, const exprseq & es) : exprseq(es), serial(ser)
462 {
463     debugmsg("function constructor from unsigned,exprseq",LOGLEVEL_CONSTRUCT);
464     tinfo_key = TINFO_function;
465 }
466
467 function::function(unsigned ser, const exvector & v, bool discardable) 
468     : exprseq(v,discardable), serial(ser)
469 {
470     debugmsg("function constructor from string,exvector,bool",LOGLEVEL_CONSTRUCT);
471     tinfo_key = TINFO_function;
472 }
473
474 function::function(unsigned ser, exvector * vp) 
475     : exprseq(vp), serial(ser)
476 {
477     debugmsg("function constructor from unsigned,exvector *",LOGLEVEL_CONSTRUCT);
478     tinfo_key = TINFO_function;
479 }
480
481 //////////
482 // archiving
483 //////////
484
485 /** Construct object from archive_node. */
486 function::function(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
487 {
488     debugmsg("function constructor from archive_node", LOGLEVEL_CONSTRUCT);
489
490     // Find serial number by function name
491     string s;
492     if (n.find_string("name", s)) {
493         unsigned int ser = 0;
494         vector<registered_function_info>::const_iterator i = registered_functions().begin(), iend = registered_functions().end();
495         while (i != iend) {
496             if (s == i->name) {
497                 serial = ser;
498                 return;
499             }
500             i++; ser++;
501         }
502         throw (std::runtime_error("unknown function '" + s + "' in archive"));
503     } else
504         throw (std::runtime_error("unnamed function in archive"));
505 }
506
507 /** Unarchive the object. */
508 ex function::unarchive(const archive_node &n, const lst &sym_lst)
509 {
510     return (new function(n, sym_lst))->setflag(status_flags::dynallocated);
511 }
512
513 /** Archive the object. */
514 void function::archive(archive_node &n) const
515 {
516     inherited::archive(n);
517     GINAC_ASSERT(serial < registered_functions().size());
518     n.add_string("name", registered_functions()[serial].name);
519 }
520
521 //////////
522 // functions overriding virtual functions from bases classes
523 //////////
524
525 // public
526
527 basic * function::duplicate() const
528 {
529     debugmsg("function duplicate",LOGLEVEL_DUPLICATE);
530     return new function(*this);
531 }
532
533 void function::printraw(ostream & os) const
534 {
535     debugmsg("function printraw",LOGLEVEL_PRINT);
536
537     GINAC_ASSERT(serial<registered_functions().size());
538
539     os << "function(name=" << registered_functions()[serial].name;
540     for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
541         os << ",";
542         (*it).bp->print(os);
543     }
544     os << ")";
545 }
546
547 void function::print(ostream & os, unsigned upper_precedence) const
548 {
549     debugmsg("function print",LOGLEVEL_PRINT);
550
551     GINAC_ASSERT(serial<registered_functions().size());
552
553     os << registered_functions()[serial].name;
554     printseq(os,'(',',',')',exprseq::precedence,function::precedence);
555 }
556
557 void function::printtree(ostream & os, unsigned indent) const
558 {
559     debugmsg("function printtree",LOGLEVEL_PRINT);
560
561     GINAC_ASSERT(serial<registered_functions().size());
562
563     os << string(indent,' ') << "function "
564        << registered_functions()[serial].name
565        << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
566        << ", flags=" << flags
567        << ", nops=" << nops() << endl;
568     for (unsigned i=0; i<nops(); ++i) {
569         seq[i].printtree(os,indent+delta_indent);
570     }
571     os << string(indent+delta_indent,' ') << "=====" << endl;
572 }
573
574 void function::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
575 {
576     debugmsg("function print csrc",LOGLEVEL_PRINT);
577
578     GINAC_ASSERT(serial<registered_functions().size());
579
580         // Print function name in lowercase
581     string lname;
582     lname=registered_functions()[serial].name;
583     for (unsigned i=0; i<lname.size(); i++)
584         lname[i] = tolower(lname[i]);
585     os << lname << "(";
586
587         // Print arguments, separated by commas
588     exvector::const_iterator it = seq.begin();
589     exvector::const_iterator itend = seq.end();
590     while (it != itend) {
591         it->bp->printcsrc(os, type, 0);
592         it++;
593         if (it != itend)
594             os << ",";
595     }
596     os << ")";
597 }
598
599 ex function::expand(unsigned options) const
600 {
601     return this->setflag(status_flags::expanded);
602 }
603
604 ex function::eval(int level) const
605 {
606     GINAC_ASSERT(serial<registered_functions().size());
607
608     exvector eseq=evalchildren(level);    
609
610     if (registered_functions()[serial].e==0) {
611         return function(serial,eseq).hold();
612     }
613     switch (registered_functions()[serial].nparams) {
614         // the following lines have been generated for max. ${maxargs} parameters
615 ${eval_switch_statement}
616         // end of generated lines
617     }
618     throw(std::logic_error("function::eval(): invalid nparams"));
619 }
620
621 ex function::evalf(int level) const
622 {
623     GINAC_ASSERT(serial<registered_functions().size());
624
625     exvector eseq=evalfchildren(level);
626     
627     if (registered_functions()[serial].ef==0) {
628         return function(serial,eseq).hold();
629     }
630     switch (registered_functions()[serial].nparams) {
631         // the following lines have been generated for max. ${maxargs} parameters
632 ${evalf_switch_statement}
633         // end of generated lines
634     }
635     throw(std::logic_error("function::evalf(): invalid nparams"));
636 }
637
638 ex function::thisexprseq(const exvector & v) const
639 {
640     return function(serial,v);
641 }
642
643 ex function::thisexprseq(exvector * vp) const
644 {
645     return function(serial,vp);
646 }
647
648 /** Implementation of ex::series for functions.
649  *  \@see ex::series */
650 ex function::series(const symbol & s, const ex & point, int order) const
651 {
652     GINAC_ASSERT(serial<registered_functions().size());
653
654     if (registered_functions()[serial].s==0) {
655         return basic::series(s, point, order);
656     }
657     ex res;
658     switch (registered_functions()[serial].nparams) {
659         // the following lines have been generated for max. ${maxargs} parameters
660 ${series_switch_statement}
661         // end of generated lines
662     }
663     throw(std::logic_error("function::series(): invalid nparams"));
664 }
665
666 // protected
667
668
669 /** Implementation of ex::diff() for functions. It applies the chain rule,
670  *  except for the Order term function.
671  *  \@see ex::diff */
672 ex function::derivative(const symbol & s) const
673 {
674     ex result;
675     
676     if (serial==function_index_Order) {
677         // Order Term function only differentiates the argument
678         return Order(seq[0].diff(s));
679     } else {
680         // Chain rule
681         ex arg_diff;
682         for (unsigned i=0; i!=seq.size(); i++) {
683             arg_diff = seq[i].diff(s);
684             // We apply the chain rule only when it makes sense.  This is not
685             // just for performance reasons but also to allow functions to
686             // throw when differentiated with respect to one of its arguments
687             // without running into trouble with our automatic full
688             // differentiation:
689             if (!arg_diff.is_zero())
690                 result += pderivative(i)*arg_diff;
691         }
692     }
693     return result;
694 }
695
696 int function::compare_same_type(const basic & other) const
697 {
698     GINAC_ASSERT(is_of_type(other, function));
699     const function & o=static_cast<function &>(const_cast<basic &>(other));
700
701     if (serial!=o.serial) {
702         return serial < o.serial ? -1 : 1;
703     }
704     return exprseq::compare_same_type(o);
705 }
706
707 bool function::is_equal_same_type(const basic & other) const
708 {
709     GINAC_ASSERT(is_of_type(other, function));
710     const function & o=static_cast<function &>(const_cast<basic &>(other));
711
712     if (serial!=o.serial) return false;
713     return exprseq::is_equal_same_type(o);
714 }
715
716 unsigned function::return_type(void) const
717 {
718     if (seq.size()==0) {
719         return return_types::commutative;
720     }
721     return (*seq.begin()).return_type();
722 }
723    
724 unsigned function::return_type_tinfo(void) const
725 {
726     if (seq.size()==0) {
727         return tinfo_key;
728     }
729     return (*seq.begin()).return_type_tinfo();
730 }
731
732 //////////
733 // new virtual functions which can be overridden by derived classes
734 //////////
735
736 // none
737
738 //////////
739 // non-virtual functions in this class
740 //////////
741
742 // protected
743
744 ex function::pderivative(unsigned diff_param) const // partial differentiation
745 {
746     GINAC_ASSERT(serial<registered_functions().size());
747     
748     if (registered_functions()[serial].d==0) {
749         throw(std::logic_error(string("function::pderivative(") + registered_functions()[serial].name + "): no diff function defined"));
750     }
751     switch (registered_functions()[serial].nparams) {
752         // the following lines have been generated for max. ${maxargs} parameters
753 ${diff_switch_statement}
754         // end of generated lines
755     }        
756     throw(std::logic_error("function::pderivative(): no diff function defined"));
757 }
758
759 vector<registered_function_info> & function::registered_functions(void)
760 {
761     static vector<registered_function_info> * rf=new vector<registered_function_info>;
762     return *rf;
763 }
764
765 // public
766
767 // the following lines have been generated for max. ${maxargs} parameters
768 $register_new_implementation
769 // end of generated lines
770
771 //////////
772 // static member variables
773 //////////
774
775 // none
776
777 //////////
778 // global constants
779 //////////
780
781 const function some_function;
782 const type_info & typeid_function=typeid(some_function);
783
784 #ifndef NO_NAMESPACE_GINAC
785 } // namespace GiNaC
786 #endif // ndef NO_NAMESPACE_GINAC
787
788 END_OF_IMPLEMENTATION
789
790 print "Creating interface file function.h...";
791 open OUT,">function.h" or die "cannot open function.h";
792 print OUT $interface;
793 close OUT;
794 print "ok.\n";
795
796 print "Creating implementation file function.cpp...";
797 open OUT,">function.cpp" or die "cannot open function.cpp";
798 print OUT $implementation;
799 close OUT;
800 print "ok.\n";
801
802 print "done.\n";