- switched to automake build environment
[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=generate(
35     <<'END_OF_DECLARE_FUNCTION_MACRO','ex const & p${N}','p${N}');
36 #define DECLARE_FUNCTION_${N}P(NAME) \\
37 extern unsigned function_index_##NAME; \\
38 inline function NAME(${SEQ1}) { \\
39     return function(function_index_##NAME, ${SEQ2}); \\
40 }
41
42 END_OF_DECLARE_FUNCTION_MACRO
43
44 $typedef_eval_funcp=generate(
45 'typedef ex (* eval_funcp_${N})(${SEQ1});'."\n",
46 'ex const &','');
47
48 $typedef_evalf_funcp=generate(
49 'typedef ex (* evalf_funcp_${N})(${SEQ1});'."\n",
50 'ex const &','');
51
52 $typedef_diff_funcp=generate(
53 'typedef ex (* diff_funcp_${N})(${SEQ1}, unsigned);'."\n",
54 'ex const &','');
55
56 $typedef_series_funcp=generate(
57 'typedef ex (* series_funcp_${N})(${SEQ1}, symbol const &, ex const &, int);'."\n",
58 'ex const &','');
59
60 $constructors_interface=generate(
61 '    function(unsigned ser, ${SEQ1});'."\n",
62 'ex const & param${N}','');
63
64 $register_new_interface=generate(
65 '    static unsigned register_new(char const * nm, eval_funcp_${N} e,'."\n".
66 '                                 evalf_funcp_${N} ef=0, diff_funcp_${N} d=0, series_funcp_${N} s=0);'.
67 "\n",'','');
68
69 $constructors_implementation=generate(
70     <<'END_OF_CONSTRUCTORS_IMPLEMENTATION','ex const & param${N}','param${N}');
71 function::function(unsigned ser, ${SEQ1})
72     : exprseq(${SEQ2}), serial(ser)
73 {
74     debugmsg(\"function constructor from unsigned,${N}*ex\",LOGLEVEL_CONSTRUCT);
75     tinfo_key = TINFO_FUNCTION;
76 }
77 END_OF_CONSTRUCTORS_IMPLEMENTATION
78
79 $eval_switch_statement=generate(
80     <<'END_OF_EVAL_SWITCH_STATEMENT','eseq[${N}-1]','');
81     case ${N}:
82         return ((eval_funcp_${N})(registered_functions()[serial].e))(${SEQ1});
83         break;
84 END_OF_EVAL_SWITCH_STATEMENT
85
86 $evalf_switch_statement=generate(
87     <<'END_OF_EVALF_SWITCH_STATEMENT','eseq[${N}-1]','');
88     case ${N}:
89         return ((evalf_funcp_${N})(registered_functions()[serial].ef))(${SEQ1});
90         break;
91 END_OF_EVALF_SWITCH_STATEMENT
92
93 $diff_switch_statement=generate(
94     <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','');
95     case ${N}:
96         return ((diff_funcp_${N})(registered_functions()[serial].d))(${SEQ1},diff_param);
97         break;
98 END_OF_DIFF_SWITCH_STATEMENT
99
100 $series_switch_statement=generate(
101     <<'END_OF_SERIES_SWITCH_STATEMENT','seq[${N}-1]','');
102     case ${N}:
103         return ((series_funcp_${N})(registered_functions()[serial].s))(${SEQ1},s,point,order);
104         break;
105 END_OF_SERIES_SWITCH_STATEMENT
106
107 $register_new_implementation=generate(
108     <<'END_OF_REGISTER_NEW_IMPLEMENTATION','','');
109 unsigned function::register_new(char const * nm, eval_funcp_${N} e,
110                                  evalf_funcp_${N} ef, diff_funcp_${N} d, series_funcp_${N} s)
111 {
112     registered_function_info rfi={nm,${N},0,eval_funcp(e),
113                                   evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
114     registered_functions().push_back(rfi);
115     return registered_functions().size()-1;
116 }
117 END_OF_REGISTER_NEW_IMPLEMENTATION
118
119 $interface=<<END_OF_INTERFACE;
120 /** \@file function.h
121  *
122  *  Interface to abstract class function (new function concept).
123  *
124  *  This file was generated automatically by function.pl.
125  *  Please do not modify it directly, edit the perl script instead!
126  *  function.pl options: \$maxargs=${maxargs} */
127
128 #ifndef _FUNCTION_H_
129 #define _FUNCTION_H_
130
131 #include <string>
132 #include <vector>
133 #include "config.h"
134
135 class function;
136
137 #include "exprseq.h"
138
139 // the following lines have been generated for max. ${maxargs} parameters
140 $declare_function_macro
141 // end of generated lines
142
143 #define REGISTER_FUNCTION(NAME,E,EF,D,S) \\
144 unsigned function_index_##NAME=function::register_new(#NAME,E,EF,D,S);
145
146 #define BEGIN_TYPECHECK \\
147 bool automatic_typecheck=true;
148
149 #define TYPECHECK(VAR,TYPE) \\
150 if (!is_ex_exactly_of_type(VAR,TYPE)) { \\
151     automatic_typecheck=false; \\
152 } else
153
154 #define TYPECHECK_INTEGER(VAR) \\
155 if (!(VAR).info(info_flags::integer)) { \\
156     automatic_typecheck=false; \\
157 } else
158
159 #define END_TYPECHECK(RV) \\
160 {} \\
161 if (!automatic_typecheck) { \\
162     return RV.hold(); \\
163 }
164
165 typedef ex (* eval_funcp)();
166 typedef ex (* evalf_funcp)();
167 typedef ex (* diff_funcp)();
168 typedef ex (* series_funcp)();
169
170 // the following lines have been generated for max. ${maxargs} parameters
171 $typedef_eval_funcp
172 $typedef_evalf_funcp
173 $typedef_diff_funcp
174 $typedef_series_funcp
175 // end of generated lines
176
177 struct registered_function_info {
178     char const * name;
179     unsigned nparams;
180     unsigned options;
181     eval_funcp e;
182     evalf_funcp ef;
183     diff_funcp d;
184     series_funcp s;
185 };
186
187 /** The class function is used to implement builtin functions like sin, cos...
188     and user defined functions */
189 class function : public exprseq
190 {
191     friend void ginsh_get_ginac_functions(void);
192
193 // member functions
194
195     // default constructor, destructor, copy constructor assignment operator and helpers
196 public:
197     function();
198     ~function();
199     function(function const & other);
200     function const & operator=(function const & other);
201 protected:
202     void copy(function const & other);
203     void destroy(bool call_parent);
204
205     // other constructors
206 public:
207     function(unsigned ser);
208     // the following lines have been generated for max. ${maxargs} parameters
209 $constructors_interface
210     // end of generated lines
211     function(unsigned ser, exprseq const & es);
212     function(unsigned ser, exvector const & v, bool discardable=0);
213     function(unsigned ser, exvector * vp); // vp will be deleted
214
215     // functions overriding virtual functions from bases classes
216 public:
217     basic * duplicate() const;
218     void printraw(ostream & os) const; 
219     void print(ostream & os, unsigned upper_precedence=0) const;
220     void printtree(ostream & os, unsigned indent) const;
221     void printcsrc(ostream & os, unsigned type, unsigned upper_precedence=0) const;
222     ex expand(unsigned options=0) const;
223     ex eval(int level=0) const;
224     ex evalf(int level=0) const;
225     ex diff(symbol const & s) const;
226     ex series(symbol const & s, ex const & point, int order) const;
227     ex thisexprseq(exvector const & v) const;
228     ex thisexprseq(exvector * vp) const;
229 protected:
230     int compare_same_type(basic const & other) const;
231     bool is_equal_same_type(basic const & other) const;
232     unsigned return_type(void) const;
233     unsigned return_type_tinfo(void) const;
234     
235     // new virtual functions which can be overridden by derived classes
236     // none
237     
238     // non-virtual functions in this class
239 protected:
240     ex pdiff(unsigned diff_param) const; // partial differentiation
241     static vector<registered_function_info> & registered_functions(void);
242 public:
243     // the following lines have been generated for max. ${maxargs} parameters
244 $register_new_interface
245     // end of generated lines
246     unsigned getserial(void) const {return serial;}
247     
248 // member variables
249
250 protected:
251     unsigned serial;
252 };
253
254 // utility macros
255
256 #define is_ex_the_function(OBJ, FUNCNAME) \\
257     (is_ex_exactly_of_type(OBJ, function) && static_cast<function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
258
259 // global constants
260
261 extern const function some_function;
262 extern type_info const & typeid_function;
263
264 #endif // ndef _FUNCTION_H_
265
266 END_OF_INTERFACE
267
268 $implementation=<<END_OF_IMPLEMENTATION;
269 /** \@file function.cpp
270  *
271  *  Implementation of class function.
272  *
273  *  This file was generated automatically by function.pl.
274  *  Please do not modify it directly, edit the perl script instead!
275  *  function.pl options: \$maxargs=${maxargs} */
276
277 #include <string>
278 #include <stdexcept>
279
280 #include "ginac.h"
281
282 //////////
283 // default constructor, destructor, copy constructor assignment operator and helpers
284 //////////
285
286 // public
287
288 function::function() : serial(0)
289 {
290     debugmsg("function default constructor",LOGLEVEL_CONSTRUCT);
291     tinfo_key = TINFO_FUNCTION;
292 }
293
294 function::~function()
295 {
296     debugmsg("function destructor",LOGLEVEL_DESTRUCT);
297     destroy(0);
298 }
299
300 function::function(function const & other)
301 {
302     debugmsg("function copy constructor",LOGLEVEL_CONSTRUCT);
303     copy(other);
304 }
305
306 function const & function::operator=(function const & other)
307 {
308     debugmsg("function operator=",LOGLEVEL_ASSIGNMENT);
309     if (this != &other) {
310         destroy(1);
311         copy(other);
312     }
313     return *this;
314 }
315
316 // protected
317
318 void function::copy(function const & other)
319 {
320     exprseq::copy(other);
321     serial=other.serial;
322 }
323
324 void function::destroy(bool call_parent)
325 {
326     if (call_parent) exprseq::destroy(call_parent);
327 }
328
329 //////////
330 // other constructors
331 //////////
332
333 // public
334
335 function::function(unsigned ser) : serial(ser)
336 {
337     debugmsg("function constructor from unsigned",LOGLEVEL_CONSTRUCT);
338     tinfo_key = TINFO_FUNCTION;
339 }
340
341 // the following lines have been generated for max. ${maxargs} parameters
342 $constructors_implementation
343 // end of generated lines
344
345 function::function(unsigned ser, exprseq const & es) : exprseq(es), serial(ser)
346 {
347     debugmsg("function constructor from unsigned,exprseq",LOGLEVEL_CONSTRUCT);
348     tinfo_key = TINFO_FUNCTION;
349 }
350
351 function::function(unsigned ser, exvector const & v, bool discardable) 
352     : exprseq(v,discardable), serial(ser)
353 {
354     debugmsg("function constructor from string,exvector,bool",LOGLEVEL_CONSTRUCT);
355     tinfo_key = TINFO_FUNCTION;
356 }
357
358 function::function(unsigned ser, exvector * vp) 
359     : exprseq(vp), serial(ser)
360 {
361     debugmsg("function constructor from unsigned,exvector *",LOGLEVEL_CONSTRUCT);
362     tinfo_key = TINFO_FUNCTION;
363 }
364
365 //////////
366 // functions overriding virtual functions from bases classes
367 //////////
368
369 // public
370
371 basic * function::duplicate() const
372 {
373     debugmsg("function duplicate",LOGLEVEL_DUPLICATE);
374     return new function(*this);
375 }
376
377 void function::printraw(ostream & os) const
378 {
379     debugmsg("function printraw",LOGLEVEL_PRINT);
380
381     ASSERT(serial<registered_functions().size());
382
383     os << "function(name=" << registered_functions()[serial].name;
384     for (exvector::const_iterator it=seq.begin(); it!=seq.end(); ++it) {
385         os << ",";
386         (*it).bp->print(os);
387     }
388     os << ")";
389 }
390
391 void function::print(ostream & os, unsigned upper_precedence) const
392 {
393     debugmsg("function print",LOGLEVEL_PRINT);
394
395     ASSERT(serial<registered_functions().size());
396
397     os << registered_functions()[serial].name;
398     printseq(os,'(',',',')',exprseq::precedence,function::precedence);
399 }
400
401 void function::printtree(ostream & os, unsigned indent) const
402 {
403     debugmsg("function printtree",LOGLEVEL_PRINT);
404
405     ASSERT(serial<registered_functions().size());
406
407     os << string(indent,' ') << "function "
408        << registered_functions()[serial].name
409        << ", hash=" << hashvalue << " (0x" << hex << hashvalue << dec << ")"
410        << ", flags=" << flags
411        << ", nops=" << nops() << endl;
412     for (int i=0; i<nops(); ++i) {
413         seq[i].printtree(os,indent+delta_indent);
414     }
415     os << string(indent+delta_indent,' ') << "=====" << endl;
416 }
417
418 void function::printcsrc(ostream & os, unsigned type, unsigned upper_precedence) const
419 {
420     debugmsg("function print csrc",LOGLEVEL_PRINT);
421
422     ASSERT(serial<registered_functions().size());
423
424         // Print function name in lowercase
425     string lname;
426     lname=registered_functions()[serial].name;
427     for (unsigned i=0; i<lname.size(); i++)
428         lname[i] = tolower(lname[i]);
429     os << lname << "(";
430
431         // Print arguments, separated by commas
432     exvector::const_iterator it = seq.begin();
433     exvector::const_iterator itend = seq.end();
434     while (it != itend) {
435         it->bp->printcsrc(os, type, 0);
436         it++;
437         if (it != itend)
438             os << ",";
439     }
440     os << ")";
441 }
442
443 ex function::expand(unsigned options) const
444 {
445     return this->setflag(status_flags::expanded);
446 }
447
448 ex function::eval(int level) const
449 {
450     ASSERT(serial<registered_functions().size());
451
452     exvector eseq=evalchildren(level);    
453
454     if (registered_functions()[serial].e==0) {
455         return function(serial,eseq).hold();
456     }
457     switch (registered_functions()[serial].nparams) {
458         // the following lines have been generated for max. ${maxargs} parameters
459 ${eval_switch_statement}
460         // end of generated lines
461     }
462     throw(std::logic_error("function::eval(): invalid nparams"));
463 }
464
465 ex function::evalf(int level) const
466 {
467     ASSERT(serial<registered_functions().size());
468
469     exvector eseq=evalfchildren(level);
470     
471     if (registered_functions()[serial].ef==0) {
472         return function(serial,eseq).hold();
473     }
474     switch (registered_functions()[serial].nparams) {
475         // the following lines have been generated for max. ${maxargs} parameters
476 ${evalf_switch_statement}
477         // end of generated lines
478     }
479     throw(std::logic_error("function::evalf(): invalid nparams"));
480 }
481
482 ex function::thisexprseq(exvector const & v) const
483 {
484     return function(serial,v);
485 }
486
487 ex function::thisexprseq(exvector * vp) const
488 {
489     return function(serial,vp);
490 }
491
492 /** Implementation of ex::series for functions.
493  *  \@see ex::series */
494 ex function::series(symbol const & s, ex const & point, int order) const
495 {
496     ASSERT(serial<registered_functions().size());
497
498     if (registered_functions()[serial].s==0) {
499         return basic::series(s, point, order);
500     }
501     switch (registered_functions()[serial].nparams) {
502         // the following lines have been generated for max. ${maxargs} parameters
503 ${series_switch_statement}
504         // end of generated lines
505     }
506     throw(std::logic_error("function::series(): invalid nparams"));
507 }
508
509 // protected
510
511 int function::compare_same_type(basic const & other) const
512 {
513     ASSERT(is_of_type(other, function));
514     function const & o=static_cast<function &>(const_cast<basic &>(other));
515
516     if (serial!=o.serial) {
517         return serial < o.serial ? -1 : 1;
518     }
519     return exprseq::compare_same_type(o);
520 }
521
522 bool function::is_equal_same_type(basic const & other) const
523 {
524     ASSERT(is_of_type(other, function));
525     function const & o=static_cast<function &>(const_cast<basic &>(other));
526
527     if (serial!=o.serial) return false;
528     return exprseq::is_equal_same_type(o);
529 }
530
531 unsigned function::return_type(void) const
532 {
533     if (seq.size()==0) {
534         return return_types::commutative;
535     }
536     return (*seq.begin()).return_type();
537 }
538    
539 unsigned function::return_type_tinfo(void) const
540 {
541     if (seq.size()==0) {
542         return tinfo_key;
543     }
544     return (*seq.begin()).return_type_tinfo();
545 }
546
547 //////////
548 // new virtual functions which can be overridden by derived classes
549 //////////
550
551 // none
552
553 //////////
554 // non-virtual functions in this class
555 //////////
556
557 // protected
558
559 ex function::pdiff(unsigned diff_param) const // partial differentiation
560 {
561     ASSERT(serial<registered_functions().size());
562     
563     if (registered_functions()[serial].d==0) {
564         throw(std::logic_error(string("function::pdiff(") + registered_functions()[serial].name + "): no diff function defined"));
565     }
566     switch (registered_functions()[serial].nparams) {
567         // the following lines have been generated for max. ${maxargs} parameters
568 ${diff_switch_statement}
569         // end of generated lines
570     }        
571     throw(std::logic_error("function::pdiff(): no diff function defined"));
572 }
573
574 vector<registered_function_info> & function::registered_functions(void)
575 {
576     static vector<registered_function_info> * rf=new vector<registered_function_info>;
577     return *rf;
578 }
579
580 // public
581
582 // the following lines have been generated for max. ${maxargs} parameters
583 $register_new_implementation
584 // end of generated lines
585
586 //////////
587 // static member variables
588 //////////
589
590 // none
591
592 //////////
593 // global constants
594 //////////
595
596 const function some_function;
597 type_info const & typeid_function=typeid(some_function);
598
599 END_OF_IMPLEMENTATION
600
601 print "Creating interface file function.h...";
602 open OUT,">function.h" or die "cannot open function.h";
603 print OUT $interface;
604 close OUT;
605 print "ok.\n";
606
607 print "Creating implementation file function.cpp...";
608 open OUT,">function.cpp" or die "cannot open function.cpp";
609 print OUT $implementation;
610 close OUT;
611 print "ok.\n";
612
613 print "done.\n";