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