]> www.ginac.de Git - ginac.git/blob - ginac/function.pl
- Changed a few switches.
[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','GiNaC::ex const & 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','ex const & 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 'ex const &','');
57
58 $typedef_evalf_funcp=generate(
59 'typedef ex (* evalf_funcp_${N})(${SEQ1});'."\n",
60 'ex const &','');
61
62 $typedef_diff_funcp=generate(
63 'typedef ex (* diff_funcp_${N})(${SEQ1}, unsigned);'."\n",
64 'ex const &','');
65
66 $typedef_series_funcp=generate(
67 'typedef ex (* series_funcp_${N})(${SEQ1}, symbol const &, ex const &, int);'."\n",
68 'ex const &','');
69
70 $constructors_interface=generate(
71 '    function(unsigned ser, ${SEQ1});'."\n",
72 'ex const & param${N}','');
73
74 $register_new_interface=generate(
75 '    static unsigned register_new(char const * nm, eval_funcp_${N} e,'."\n".
76 '                                 evalf_funcp_${N} ef=0, diff_funcp_${N} d=0, series_funcp_${N} s=0);'.
77 "\n",'','');
78
79 $constructors_implementation=generate(
80     <<'END_OF_CONSTRUCTORS_IMPLEMENTATION','ex const & 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 ((diff_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(char const * nm, eval_funcp_${N} e,
125                                  evalf_funcp_${N} ef, diff_funcp_${N} d, series_funcp_${N} s)
126 {
127     registered_function_info rfi={nm,${N},0,eval_funcp(e),
128                                   evalf_funcp(ef),diff_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 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 <ginac/exprseq.h>
173
174 #ifndef NO_GINAC_NAMESPACE
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_GINAC_NAMESPACE
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_GINAC_NAMESPACE
187
188 #ifndef NO_GINAC_NAMESPACE
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_GINAC_NAMESPACE
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_GINAC_NAMESPACE
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_GINAC_NAMESPACE
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_GINAC_NAMESPACE
216
217 #define TYPECHECK_INTEGER(VAR) \\
218 if (!(VAR).info(info_flags::integer)) { \\
219     automatic_typecheck=false; \\
220 } else
221
222 #endif // ndef NO_GINAC_NAMESPACE
223
224 #define END_TYPECHECK(RV) \\
225 {} \\
226 if (!automatic_typecheck) { \\
227     return RV.hold(); \\
228 }
229
230 #ifndef NO_GINAC_NAMESPACE
231 namespace GiNaC {
232 #endif // ndef NO_GINAC_NAMESPACE
233
234 class function;
235
236 typedef ex (* eval_funcp)();
237 typedef ex (* evalf_funcp)();
238 typedef ex (* diff_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_diff_funcp
245 $typedef_series_funcp
246 // end of generated lines
247
248 struct registered_function_info {
249     char const * name;
250     unsigned nparams;
251     unsigned options;
252     eval_funcp e;
253     evalf_funcp ef;
254     diff_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     // CINT has a linking problem
263     friend void ginsh_get_ginac_functions(void);
264
265 // member functions
266
267     // default constructor, destructor, copy constructor assignment operator and helpers
268 public:
269     function();
270     ~function();
271     function(function const & other);
272     function const & operator=(function const & other);
273 protected:
274     void copy(function const & other);
275     void destroy(bool call_parent);
276
277     // other constructors
278 public:
279     function(unsigned ser);
280     // the following lines have been generated for max. ${maxargs} parameters
281 $constructors_interface
282     // end of generated lines
283     function(unsigned ser, exprseq const & es);
284     function(unsigned ser, exvector const & v, bool discardable=0);
285     function(unsigned ser, exvector * vp); // vp will be deleted
286
287     // functions overriding virtual functions from bases classes
288 public:
289     basic * duplicate() const;
290     void printraw(ostream & os) const; 
291     void print(ostream & os, unsigned upper_precedence=0) const;
292     void printtree(ostream & os, unsigned indent) const;
293     void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
294     ex expand(unsigned options=0) const;
295     ex eval(int level=0) const;
296     ex evalf(int level=0) const;
297     ex diff(symbol const & s) const;
298     ex series(symbol const & s, ex const & point, int order) const;
299     ex thisexprseq(exvector const & v) const;
300     ex thisexprseq(exvector * vp) const;
301 protected:
302     int compare_same_type(basic const & other) const;
303     bool is_equal_same_type(basic const & other) const;
304     unsigned return_type(void) const;
305     unsigned return_type_tinfo(void) const;
306     
307     // new virtual functions which can be overridden by derived classes
308     // none
309     
310     // non-virtual functions in this class
311 protected:
312     ex pdiff(unsigned diff_param) const; // partial differentiation
313     static vector<registered_function_info> & registered_functions(void);
314 public:
315     // the following lines have been generated for max. ${maxargs} parameters
316 $register_new_interface
317     // end of generated lines
318     unsigned getserial(void) const {return serial;}
319     
320 // member variables
321
322 protected:
323     unsigned serial;
324 };
325
326 // utility macros
327
328 #ifndef NO_GINAC_NAMESPACE
329
330 #define is_ex_the_function(OBJ, FUNCNAME) \\
331     (is_ex_exactly_of_type(OBJ, function) && static_cast<GiNaC::function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
332
333 #else // ndef NO_GINAC_NAMESPACE
334
335 #define is_ex_the_function(OBJ, FUNCNAME) \\
336     (is_ex_exactly_of_type(OBJ, function) && static_cast<function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
337
338 #endif // ndef NO_GINAC_NAMESPACE
339
340 // global constants
341
342 extern const function some_function;
343 extern type_info const & typeid_function;
344
345 #ifndef NO_GINAC_NAMESPACE
346 } // namespace GiNaC
347 #endif // ndef NO_GINAC_NAMESPACE
348
349 #endif // ndef __GINAC_FUNCTION_H__
350
351 END_OF_INTERFACE
352
353 $implementation=<<END_OF_IMPLEMENTATION;
354 /** \@file function.cpp
355  *
356  *  Implementation of class function. */
357
358 /*
359  *  This file was generated automatically by function.pl.
360  *  Please do not modify it directly, edit the perl script instead!
361  *  function.pl options: \$maxargs=${maxargs}
362  *
363  *  GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
364  *
365  *  This program is free software; you can redistribute it and/or modify
366  *  it under the terms of the GNU General Public License as published by
367  *  the Free Software Foundation; either version 2 of the License, or
368  *  (at your option) any later version.
369  *
370  *  This program is distributed in the hope that it will be useful,
371  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
372  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
373  *  GNU General Public License for more details.
374  *
375  *  You should have received a copy of the GNU General Public License
376  *  along with this program; if not, write to the Free Software
377  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
378  */
379
380 #include <string>
381 #include <stdexcept>
382
383 #include "function.h"
384 #include "ex.h"
385 #include "utils.h"
386 #include "debugmsg.h"
387
388 #ifndef NO_GINAC_NAMESPACE
389 namespace GiNaC {
390 #endif // ndef NO_GINAC_NAMESPACE
391
392 //////////
393 // default constructor, destructor, copy constructor assignment operator and helpers
394 //////////
395
396 // public
397
398 function::function() : serial(0)
399 {
400     debugmsg("function default constructor",LOGLEVEL_CONSTRUCT);
401     tinfo_key = TINFO_function;
402 }
403
404 function::~function()
405 {
406     debugmsg("function destructor",LOGLEVEL_DESTRUCT);
407     destroy(0);
408 }
409
410 function::function(function const & other)
411 {
412     debugmsg("function copy constructor",LOGLEVEL_CONSTRUCT);
413     copy(other);
414 }
415
416 function const & function::operator=(function const & other)
417 {
418     debugmsg("function operator=",LOGLEVEL_ASSIGNMENT);
419     if (this != &other) {
420         destroy(1);
421         copy(other);
422     }
423     return *this;
424 }
425
426 // protected
427
428 void function::copy(function const & other)
429 {
430     exprseq::copy(other);
431     serial=other.serial;
432 }
433
434 void function::destroy(bool call_parent)
435 {
436     if (call_parent) exprseq::destroy(call_parent);
437 }
438
439 //////////
440 // other constructors
441 //////////
442
443 // public
444
445 function::function(unsigned ser) : serial(ser)
446 {
447     debugmsg("function constructor from unsigned",LOGLEVEL_CONSTRUCT);
448     tinfo_key = TINFO_function;
449 }
450
451 // the following lines have been generated for max. ${maxargs} parameters
452 $constructors_implementation
453 // end of generated lines
454
455 function::function(unsigned ser, exprseq const & es) : exprseq(es), serial(ser)
456 {
457     debugmsg("function constructor from unsigned,exprseq",LOGLEVEL_CONSTRUCT);
458     tinfo_key = TINFO_function;
459 }
460
461 function::function(unsigned ser, exvector const & v, bool discardable) 
462     : exprseq(v,discardable), serial(ser)
463 {
464     debugmsg("function constructor from string,exvector,bool",LOGLEVEL_CONSTRUCT);
465     tinfo_key = TINFO_function;
466 }
467
468 function::function(unsigned ser, exvector * vp) 
469     : exprseq(vp), serial(ser)
470 {
471     debugmsg("function constructor from unsigned,exvector *",LOGLEVEL_CONSTRUCT);
472     tinfo_key = TINFO_function;
473 }
474
475 //////////
476 // functions overriding virtual functions from bases classes
477 //////////
478
479 // public
480
481 basic * function::duplicate() const
482 {
483     debugmsg("function duplicate",LOGLEVEL_DUPLICATE);
484     return new function(*this);
485 }
486
487 void function::printraw(ostream & os) const
488 {
489     debugmsg("function printraw",LOGLEVEL_PRINT);
490
491     GINAC_ASSERT(serial<registered_functions().size());
492
493     os << "function(name=" << registered_functions()[serial].name;
494     for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
495         os << ",";
496         (*it).bp->print(os);
497     }
498     os << ")";
499 }
500
501 void function::print(ostream & os, unsigned upper_precedence) const
502 {
503     debugmsg("function print",LOGLEVEL_PRINT);
504
505     GINAC_ASSERT(serial<registered_functions().size());
506
507     os << registered_functions()[serial].name;
508     printseq(os,'(',',',')',exprseq::precedence,function::precedence);
509 }
510
511 void function::printtree(ostream & os, unsigned indent) const
512 {
513     debugmsg("function printtree",LOGLEVEL_PRINT);
514
515     GINAC_ASSERT(serial<registered_functions().size());
516
517     os << string(indent,' ') << "function "
518        << registered_functions()[serial].name
519        << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
520        << ", flags=" << flags
521        << ", nops=" << nops() << endl;
522     for (int i=0; i<nops(); ++i) {
523         seq[i].printtree(os,indent+delta_indent);
524     }
525     os << string(indent+delta_indent,' ') << "=====" << endl;
526 }
527
528 void function::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
529 {
530     debugmsg("function print csrc",LOGLEVEL_PRINT);
531
532     GINAC_ASSERT(serial<registered_functions().size());
533
534         // Print function name in lowercase
535     string lname;
536     lname=registered_functions()[serial].name;
537     for (unsigned i=0; i<lname.size(); i++)
538         lname[i] = tolower(lname[i]);
539     os << lname << "(";
540
541         // Print arguments, separated by commas
542     exvector::const_iterator it = seq.begin();
543     exvector::const_iterator itend = seq.end();
544     while (it != itend) {
545         it->bp->printcsrc(os, type, 0);
546         it++;
547         if (it != itend)
548             os << ",";
549     }
550     os << ")";
551 }
552
553 ex function::expand(unsigned options) const
554 {
555     return this->setflag(status_flags::expanded);
556 }
557
558 ex function::eval(int level) const
559 {
560     GINAC_ASSERT(serial<registered_functions().size());
561
562     exvector eseq=evalchildren(level);    
563
564     if (registered_functions()[serial].e==0) {
565         return function(serial,eseq).hold();
566     }
567     switch (registered_functions()[serial].nparams) {
568         // the following lines have been generated for max. ${maxargs} parameters
569 ${eval_switch_statement}
570         // end of generated lines
571     }
572     throw(std::logic_error("function::eval(): invalid nparams"));
573 }
574
575 ex function::evalf(int level) const
576 {
577     GINAC_ASSERT(serial<registered_functions().size());
578
579     exvector eseq=evalfchildren(level);
580     
581     if (registered_functions()[serial].ef==0) {
582         return function(serial,eseq).hold();
583     }
584     switch (registered_functions()[serial].nparams) {
585         // the following lines have been generated for max. ${maxargs} parameters
586 ${evalf_switch_statement}
587         // end of generated lines
588     }
589     throw(std::logic_error("function::evalf(): invalid nparams"));
590 }
591
592 ex function::thisexprseq(exvector const & v) const
593 {
594     return function(serial,v);
595 }
596
597 ex function::thisexprseq(exvector * vp) const
598 {
599     return function(serial,vp);
600 }
601
602 /** Implementation of ex::series for functions.
603  *  \@see ex::series */
604 ex function::series(symbol const & s, ex const & point, int order) const
605 {
606     GINAC_ASSERT(serial<registered_functions().size());
607
608     if (registered_functions()[serial].s==0) {
609         return basic::series(s, point, order);
610     }
611     ex res;
612     switch (registered_functions()[serial].nparams) {
613         // the following lines have been generated for max. ${maxargs} parameters
614 ${series_switch_statement}
615         // end of generated lines
616     }
617     throw(std::logic_error("function::series(): invalid nparams"));
618 }
619
620 // protected
621
622 int function::compare_same_type(basic const & other) const
623 {
624     GINAC_ASSERT(is_of_type(other, function));
625     function const & o=static_cast<function &>(const_cast<basic &>(other));
626
627     if (serial!=o.serial) {
628         return serial < o.serial ? -1 : 1;
629     }
630     return exprseq::compare_same_type(o);
631 }
632
633 bool function::is_equal_same_type(basic const & other) const
634 {
635     GINAC_ASSERT(is_of_type(other, function));
636     function const & o=static_cast<function &>(const_cast<basic &>(other));
637
638     if (serial!=o.serial) return false;
639     return exprseq::is_equal_same_type(o);
640 }
641
642 unsigned function::return_type(void) const
643 {
644     if (seq.size()==0) {
645         return return_types::commutative;
646     }
647     return (*seq.begin()).return_type();
648 }
649    
650 unsigned function::return_type_tinfo(void) const
651 {
652     if (seq.size()==0) {
653         return tinfo_key;
654     }
655     return (*seq.begin()).return_type_tinfo();
656 }
657
658 //////////
659 // new virtual functions which can be overridden by derived classes
660 //////////
661
662 // none
663
664 //////////
665 // non-virtual functions in this class
666 //////////
667
668 // protected
669
670 ex function::pdiff(unsigned diff_param) const // partial differentiation
671 {
672     GINAC_ASSERT(serial<registered_functions().size());
673     
674     if (registered_functions()[serial].d==0) {
675         throw(std::logic_error(string("function::pdiff(") + registered_functions()[serial].name + "): no diff function defined"));
676     }
677     switch (registered_functions()[serial].nparams) {
678         // the following lines have been generated for max. ${maxargs} parameters
679 ${diff_switch_statement}
680         // end of generated lines
681     }        
682     throw(std::logic_error("function::pdiff(): no diff function defined"));
683 }
684
685 vector<registered_function_info> & function::registered_functions(void)
686 {
687     static vector<registered_function_info> * rf=new vector<registered_function_info>;
688     return *rf;
689 }
690
691 // public
692
693 // the following lines have been generated for max. ${maxargs} parameters
694 $register_new_implementation
695 // end of generated lines
696
697 //////////
698 // static member variables
699 //////////
700
701 // none
702
703 //////////
704 // global constants
705 //////////
706
707 const function some_function;
708 type_info const & typeid_function=typeid(some_function);
709
710 #ifndef NO_GINAC_NAMESPACE
711 } // namespace GiNaC
712 #endif // ndef NO_GINAC_NAMESPACE
713
714 END_OF_IMPLEMENTATION
715
716 print "Creating interface file function.h...";
717 open OUT,">function.h" or die "cannot open function.h";
718 print OUT $interface;
719 close OUT;
720 print "ok.\n";
721
722 print "Creating implementation file function.cpp...";
723 open OUT,">function.cpp" or die "cannot open function.cpp";
724 print OUT $implementation;
725 close OUT;
726 print "ok.\n";
727
728 print "done.\n";