Dear All, The method power::eval() contains the following rules: // ^(*(...,x;c1),c2) -> *(^(*(...,x;1),c2),c1^c2) (c1, c2 numeric(), c1>0) // ^(*(...,x;c1),c2) -> *(^(*(...,x;-1),c2),(-c1)^c2) (c1, c2 numeric(), c1<0) Is there a good reason why c1 here shall be numeric? Cannot we simply check the positive/negative info flag for c1 for that simplification? Shall I prepare a patch for this? Currently we have: possymbol n("n"), m("m"); cout << "e=" << pow(pow(n,2),half) << endl; // -> n cout << "e=" << pow(pow(n*m,2),half) << endl; // -> sqrt(m^2*n^2) Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk www: http://www.maths.leeds.ac.uk/~kisilv/ Book: Geometry of Mobius Transformations http://www.worldscientific.com/worldscibooks/10.1142/p835
Dear All, I propose a patch to power::expand(). It does not affect power::eval() and automatic rewriting rules. The patch expand expressions like (a*b*p)^c to (a*b)^c*p^c if p is positive and c is real. A simple check is added as well. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk www: http://www.maths.leeds.ac.uk/~kisilv/ Book: Geometry of Mobius Transformations http://www.worldscientific.com/worldscibooks/10.1142/p835
Hi again,
+ ex e1 = pow(5*pow(3*a*b*x*y*p*q,2),7*half*c).expand(); + ex e2 = pow(p,7*c)*pow(q,7*c)*pow(pow(a*b*x*y,2),numeric(7,2)*c)*pow(45,numeric(7,2)*c);
The idea looks good...
diff --git a/ginac/power.cpp b/ginac/power.cpp index 9a8f7d5..d01a88f 100644 --- a/ginac/power.cpp +++ b/ginac/power.cpp @@ -824,11 +824,38 @@ ex power::expand(unsigned options) const
if (!is_exactly_a<numeric>(expanded_exponent) || !ex_to<numeric>(expanded_exponent).is_integer()) { - if (are_ex_trivially_equal(basis,expanded_basis) && are_ex_trivially_equal(exponent,expanded_exponent)) { - return this->hold(); - } else { + if (is_exactly_a<mul>(expanded_basis) && expanded_exponent.info(info_flags::real)) {
... however the implementation is a bit inefficient. Even worse -- it makes power::expand() slower even if the above transformation is not applicable. Consider the following expression: ((1+x)^(2*eps)*(1+2*x)^(1+2*eps)*...(1+100*x)^(1+100*eps))^(4-2*eps)
+ const mul &m = ex_to<mul>(expanded_basis); + exvector prodseq, powseq; + prodseq.reserve(m.seq.size() + 1); + powseq.reserve(m.seq.size() + 1); + epvector::const_iterator last = m.seq.end(); + epvector::const_iterator cit = m.seq.begin(); + bool possign=true; + + while (cit!=last) { + ex e=m.recombine_pair_to_ex(*cit); + if (e.info(info_flags::positive)) + prodseq.push_back(power(e, expanded_exponent)); + else if (e.info(info_flags::negative)) { + prodseq.push_back(power(-e, expanded_exponent)); + possign = !possign;
So we check every term here (which might be quite expensive)...
+ } else + powseq.push_back(m.recombine_pair_to_ex(*cit));
This conversion is useless (mul(powseq) converts the exvector back to epvector). Perhaps powseq should be a epvector.
+ ++cit; + } + + if (m.overall_coeff.info(info_flags::positive)) + prodseq.push_back(power(m.overall_coeff, expanded_exponent)); + else if (m.overall_coeff.info(info_flags::negative)) { + prodseq.push_back(power(-m.overall_coeff, expanded_exponent)); + possign = !possign; + } else + powseq.push_back(m.overall_coeff); + + return (new mul(prodseq))->setflag(status_flags::dynallocated)*(new power((possign? _ex1 : _ex_1)*mul(powseq), expanded_exponent))->setflag(status_flags::dynallocated);
Eventually the loop constructs the same expression, but it needs to be evaluated once again.
+ } else return (new power(expanded_basis,expanded_exponent))->setflag(status_flags::dynallocated | (options == 0 ? status_flags::expanded : 0)); - } }
Therefore I think the patch should be improved. In particular, - info_flags::{positive,negative} should be cached (add yet another status_flags and maintain them) - the trivial case should be handled more carefully (i.e. the code should detect that the transformation is not applicable as early as possible, and return the original expression). Best regards, Alexei
Dear Richy and Alexei, Many thanks for the commments, I will try to implement them. Meanwhile, here is another small proposition: to allow GiNaC the rewriting rule of exponents: (x^c1)^c2 -> x^(c1 * c2) for the additional case of c1=-1 and c2>0. It was explicitly forbidden in exam_powerlaws.cpp, but it seems to be a rudiment of old times, when GiNaC was not aware of positiveness. I am including the respective patch. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk www: http://www.maths.leeds.ac.uk/~kisilv/ Book: Geometry of Mobius Transformations http://www.worldscientific.com/worldscibooks/10.1142/p835
Dear All, Following Alexei's advises I rewrite the expansion of powers. The block is moved up, since it is more sensible to do this type of expansion before the basis of exponent was expanded. There is no other place in the code which check that *all* factors are sign-indefinite. Thus the respective flag is set within this block. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk www: http://www.maths.leeds.ac.uk/~kisilv/ Book: Geometry of Mobius Transformations http://www.worldscientific.com/worldscibooks/10.1142/p835
Vladimir, On 07/29/2013 09:12 PM, Vladimir V. Kisil wrote:
Following Alexei's advises I rewrite the expansion of powers. The block is moved up, since it is more sensible to do this type of expansion before the basis of exponent was expanded. There is no other place in the code which check that *all* factors are sign-indefinite. Thus the respective flag is set within this block.
This patch does not compile. Have you tried it? (There are no status_flags::is_positive and status_flags::is_negative.) Best regards -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Dear Richy,
On Mon, 29 Jul 2013 23:22:13 +0200, "Richard B. Kreckel" <kreckel@ginac.de> said: RK> This patch does not compile. Have you tried it?
Yes, but in ginac-1.6.2 distro. For some reasons I cannot compile the current git depository. The problems are with tutorial.info and building debian packages. RK> (There are no RK> status_flags::is_positive and status_flags::is_negative.) I moved modified files to git directory manually and forget to include flags.h. The correct patch is attached now. On my computer I can compile all three commits together, then all GiNaC checks are passed as well as all exercises from my book. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk www: http://www.maths.leeds.ac.uk/~kisilv/ Book: Geometry of Mobius Transformations http://www.worldscientific.com/worldscibooks/10.1142/p835
Hi, On Mon, Jul 29, 2013 at 10:41:01PM +0100, Vladimir V. Kisil wrote:
Subject: [PATCH 3/3] Add an expansion law in power::expand(). The expansion (x*p)^c -> x^c*p^c is done for a positive expression p and a real exponent c. The corresponding check is added to exam_powerlaws.
diff --git a/ginac/flags.h b/ginac/flags.h index 8f8f25d..f4f0f6b 100644 --- a/ginac/flags.h +++ b/ginac/flags.h @@ -197,6 +197,9 @@ public: not_shareable = 0x0010, ///< don't share instances of this object between different expressions unless explicitly asked to (used by ex::compare()) has_indices = 0x0020, has_no_indices = 0x0040 // ! (has_indices || has_no_indices) means "don't know" + is_positive = 0x0080, + is_negative = 0x0100, + purely_indefinite = 0x0200, // If set in a mul, then it does not contains any terms with determined signs, used in power::expand() }; };
The `purely_idefinite' flag is redundant (that is !(is_positive || is_negative) is equivalent to purely_indefinite). Also status_flags is quite a scarce resource (there are only 32 of them). Could you please skip that flag? Best regards, Alexei
Hi,
On Tue, 30 Jul 2013 13:09:32 +0300, Alexei Sheplyakov <alexei.sheplyakov@gmail.com> said:
ASh> The `purely_idefinite' flag is redundant ASh> (that is !(is_positive || is_negative) is equivalent to purely_indefinite). Not quite so, the former is "contains some indefinite factors" (possibly, along with some positive/negative), the later is "consists of only indefinite factors" (so, no positive/negative factors inside). ASh> status_flags is quite a scarce resource (there are only 32 of ASh> them). It is true, for this reason I did not create flags for nonnegative/nonpositive. May be 64 flags can be possible at same later point? Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk www: http://www.maths.leeds.ac.uk/~kisilv/ Book: Geometry of Mobius Transformations http://www.worldscientific.com/worldscibooks/10.1142/p835
Hi, Vladimir,
Yes, but in ginac-1.6.2 distro. For some reasons I cannot compile the current git depository. The problems are with tutorial.info and building debian packages.
Could you elaborate please? (The problem is not going to be fixed unless someone complains). Best regards, Alexei
Hi, On 07/30/2013 09:23 PM, Alexei Sheplyakov wrote:
Hi, Vladimir,
Yes, but in ginac-1.6.2 distro. For some reasons I cannot compile the current git depository. The problems are with tutorial.info and building debian packages.
Could you elaborate please? (The problem is not going to be fixed unless someone complains).
I can reproduce it: ginac.texi:8682: raising the section level of @subsection which is too low I am going to research this tomorrow. (Texinfo 5.0 and 5.1 did break a couple of packages, unfortunately.) -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
On 07/30/2013 09:55 PM, Richard B. Kreckel wrote:
Yes, but in ginac-1.6.2 distro. For some reasons I cannot compile the current git depository. The problems are with tutorial.info and building debian packages.
Could you elaborate please? (The problem is not going to be fixed unless someone complains).
I can reproduce it: ginac.texi:8682: raising the section level of @subsection which is too low I am going to research this tomorrow. (Texinfo 5.0 and 5.1 did break a couple of packages, unfortunately.)
This is fixed now. -richy. -- Richard B. Kreckel
On Tue, 30 Jul 2013 22:23:26 +0300, Alexei Sheplyakov <alexei.sheplyakov@gmail.com> said: Ash> Could you elaborate please? (The problem is not going to be Ash> fixed unless someone complains).
I did: git clone git://www.ginac.de/ginac.git cd ginac zcat ../ginac_1.6.2-1.diff.gz | patch -p 1 autoreconf -i ./configure make That breaks with the following error: make[1]: Entering directory `/tmp/ginac/ginsh' /usr/bin/python ./ginsh_op_help.py -o ginsh_op_help.h ginsh.1 make[1]: *** No rule to make target `ginsh_parser.h', needed by `ginsh_parser.o'. Stop. Maybe, something crucial is missing from my installation, but I cannot see what it is exactly. If I copy ginsh_parser.h from ginac-1.6.2 distro the next error will be: make[2]: Entering directory `/tmp/ginac/doc/tutorial' ... ginac.texi:8682: raising the section level of @subsection which is too low make[2]: *** [ginac.info] Error 1 If I copy *.info files (with the updated time-stamp) from the distro make finishes fine. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk www: http://www.maths.leeds.ac.uk/~kisilv/ Book: Geometry of Mobius Transformations http://www.worldscientific.com/worldscibooks/10.1142/p835
On Tue, 30 Jul 2013 22:23:26 +0300, Alexei Sheplyakov <alexei.sheplyakov@gmail.com> said: ASh> Could you elaborate please? (The problem is not going to be ASh> fixed unless someone complains).
One more observation, which may be not important, however. I am playing with functions.pl. After a serious modification command make && make check produce SegFault in many checks. However, after "make clean", everything compile and run without an error. Probably, my modifications introduced some binary incompatibilities, but changed functions.h did not call to recompile all pieces which are using it. I am not sure if this is an issue at all. -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk www: http://www.maths.leeds.ac.uk/~kisilv/ Book: Geometry of Mobius Transformations http://www.worldscientific.com/worldscibooks/10.1142/p835
On 07/30/2013 10:03 PM, Vladimir V. Kisil wrote:
make[1]: Entering directory `/tmp/ginac/ginsh' /usr/bin/python ./ginsh_op_help.py -o ginsh_op_help.h ginsh.1 make[1]: *** No rule to make target `ginsh_parser.h', needed by `ginsh_parser.o'. Stop.
Fixed now, too. -richy. -- Richard B. Kreckel
On Wed, 31 Jul 2013 23:43:08 +0200, "Richard B. Kreckel" <kreckel@ginac.de> said:
RK> Fixed now, too. Everything works for me now, thanks. -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk -- www: http://maths.leeds.ac.uk/~kisilv/
Hi, Richard, On Wed, Jul 31, 2013 at 11:43:08PM +0200, Richard B. Kreckel wrote:
On 07/30/2013 10:03 PM, Vladimir V. Kisil wrote:
make[1]: Entering directory `/tmp/ginac/ginsh' /usr/bin/python ./ginsh_op_help.py -o ginsh_op_help.h ginsh.1 make[1]: *** No rule to make target `ginsh_parser.h', needed by `ginsh_parser.o'. Stop.
Fixed now, too.
It's the other way around for me: there were no problems before the patch, and now I get make[2]: Entering directory `/home/pc7135/varg/work/sw/ginac/ginsh' /usr/bin/python ./ginsh_fcn_help.py -o ginsh_fcn_help.h ginsh.1.in /usr/bin/python ./ginsh_op_help.py -o ginsh_op_help.h ginsh.1 ccache g++-4.7 -DHAVE_CONFIG_H -I. -I../config -I./../ginac -I../ginac -DIN_GINAC -I/home/pc7135/varg/target/x86_64-linux-gnu/include -O2 -g -Wall -pipe -MT ginsh_lexer.o -MD -MP -MF .deps/ginsh_lexer.Tpo -c -o ginsh_lexer.o ginsh_lexer.cpp ccache g++-4.7 -DHAVE_CONFIG_H -I. -I../config -I./../ginac -I../ginac -DIN_GINAC -I/home/pc7135/varg/target/x86_64-linux-gnu/include -O2 -g -Wall -pipe -MT ginsh_parser.o -MD -MP -MF .deps/ginsh_parser.Tpo -c -o ginsh_parser.o ginsh_parser.cpp ginsh_lexer.lpp:37:28: fatal error: ginsh_parser.hpp: No such file or directory compilation terminated. make[2]: *** [ginsh_lexer.o] Error 1 make[2]: *** Waiting for unfinished jobs.... mv -f .deps/ginsh_parser.Tpo .deps/ginsh_parser.Po make[2]: Leaving directory `/home/pc7135/varg/work/sw/ginac/ginsh' make[1]: *** [all] Error 2 make[1]: Leaving directory `/home/pc7135/varg/work/sw/ginac/ginsh' make: *** [all-recursive] Error 1 config.log is attached. Best regards, Alexei
Hi again,
make[1]: Entering directory `/tmp/ginac/ginsh' /usr/bin/python ./ginsh_op_help.py -o ginsh_op_help.h ginsh.1 make[1]: *** No rule to make target `ginsh_parser.h', needed by `ginsh_parser.o'. Stop.
Fixed now, too.
It's the other way around for me: there were no problems before the patch, and now I get
make[2]: Entering directory `/home/pc7135/varg/work/sw/ginac/ginsh' /usr/bin/python ./ginsh_fcn_help.py -o ginsh_fcn_help.h ginsh.1.in /usr/bin/python ./ginsh_op_help.py -o ginsh_op_help.h ginsh.1 ccache g++-4.7 -DHAVE_CONFIG_H -I. -I../config -I./../ginac -I../ginac -DIN_GINAC -I/home/pc7135/varg/target/x86_64-linux-gnu/include -O2 -g -Wall -pipe -MT ginsh_lexer.o -MD -MP -MF .deps/ginsh_lexer.Tpo -c -o ginsh_lexer.o ginsh_lexer.cpp ccache g++-4.7 -DHAVE_CONFIG_H -I. -I../config -I./../ginac -I../ginac -DIN_GINAC -I/home/pc7135/varg/target/x86_64-linux-gnu/include -O2 -g -Wall -pipe -MT ginsh_parser.o -MD -MP -MF .deps/ginsh_parser.Tpo -c -o ginsh_parser.o ginsh_parser.cpp ginsh_lexer.lpp:37:28: fatal error: ginsh_parser.hpp: No such file or directory compilation terminated. make[2]: *** [ginsh_lexer.o] Error 1 make[2]: *** Waiting for unfinished jobs.... mv -f .deps/ginsh_parser.Tpo .deps/ginsh_parser.Po make[2]: Leaving directory `/home/pc7135/varg/work/sw/ginac/ginsh' make[1]: *** [all] Error 2 make[1]: Leaving directory `/home/pc7135/varg/work/sw/ginac/ginsh' make: *** [all-recursive] Error 1
Apparently automake 1.11 and 1.13 (or rather the Makefiles they generate) use different conventions regarding the naming of the header files built by bison/yacc. Automake 1.11 uses *.h for both C and C++ headers, and automake 1.13 names C headers as *.h and C++ ones as *.hpp. By the way, renaming the sources (*.yy -> *.ypp) seems to have no effect at all (I guess the change which actually fixed the automake 1.13 build was `#include "ginsh_parser.hpp"'). Hence we need to convince automake 1.13 to produce ginsh_parser.h from ginsh_parser.{yy,ypp}, or the other way around -- convince the older versions of automake to produce ginsh_parser.hpp file. Best regards, Alexei
Hi, On 08/01/2013 04:09 PM, Alexei Sheplyakov wrote:
Apparently automake 1.11 and 1.13 (or rather the Makefiles they generate) use different conventions regarding the naming of the header files built by bison/yacc. Automake 1.11 uses *.h for both C and C++ headers, and automake 1.13 names C headers as *.h and C++ ones as *.hpp. By the way, renaming the sources (*.yy -> *.ypp) seems to have no effect at all (I guess the change which actually fixed the automake 1.13 build was `#include "ginsh_parser.hpp"').
Hence we need to convince automake 1.13 to produce ginsh_parser.h from ginsh_parser.{yy,ypp}, or the other way around -- convince the older versions of automake to produce ginsh_parser.hpp file.
Confirmed: It works with automake 1.13 now, but fails with 1.11. I thought this had been broken before - strange. I was referring to <http://www.gnu.org/software/automake/manual/html_node/Yacc-and-Lex.html> when I renamed the files. Was this an intentional change in automake? Is it worth retaining 1.11? -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Hi, Vladimir, I've got a few comments regarding the mul::info() patches.
diff --git a/ginac/mul.cpp b/ginac/mul.cpp index cee5cd7..3ec279d 100644 --- a/ginac/mul.cpp +++ b/ginac/mul.cpp @@ -307,6 +307,11 @@ bool mul::info(unsigned inf) const } case info_flags::positive: case info_flags::negative: { + if ((inf==info_flags::positive) && (flags & status_flags::is_positive)) + return true; + else if ((inf==info_flags::negative) && (flags & status_flags::is_negative)) + return true; +
Perhaps we can add if (flags & status_flags::purely_indefinite) return false;
bool pos = true; epvector::const_iterator i = seq.begin(), end = seq.end(); while (i != end) { @@ -320,9 +325,12 @@ bool mul::info(unsigned inf) const } if (overall_coeff.info(info_flags::negative)) pos = !pos; + flags |= (pos? status_flags::is_positive : status_flags::is_negative); return (inf ==info_flags::positive? pos : !pos); } case info_flags::nonnegative: { + if (flags & status_flags::is_positive) + return true; bool pos = true; epvector::const_iterator i = seq.begin(), end = seq.end(); while (i != end) { @@ -373,6 +381,9 @@ bool mul::info(unsigned inf) const return false; return pos; } + case info_flags::indefinite: { + return (flags & status_flags::purely_indefinite);
The proper calculation of purely_indefinite flag is missing (the flag is set only by power::expand()), so mul::info(info_flags::indefinite) returns false more often than not. For instance symbol x("x"), y("y"); ex e = x*y; if (!e.info(info_flags::indefinite)) { std::cerr << "Oops" << std::endl; } Best regards, Alexei
Dear Alexei,
On Wed, 7 Aug 2013 22:44:19 +0300, Alexei Sheplyakov <alexei.sheplyakov@gmail.com> said: AShlexei> I've got a few comments regarding the mul::info() patches.
Thanks for suggestions, I am attaching a patch implementing them. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk www: http://www.maths.leeds.ac.uk/~kisilv/ Book: Geometry of Mobius Transformations http://www.worldscientific.com/worldscibooks/10.1142/p835
Hello, On Fri, Sep 6, 2013 at 4:16 PM, Vladimir V. Kisil <kisilv@maths.leeds.ac.uk> wrote:
Thanks for suggestions, I am attaching a patch implementing them.
It looks like I've got lost. Could you please send a complete patchset (i.e. the patch being improved by this patch, and so on) Best regards, Alexei P.S. Sorry for a late reply.
Dear Alexei, Sorry for delay, I was travelling.
On Thu, 19 Sep 2013 09:55:35 +0300, Alexei Sheplyakov <alexei.sheplyakov@gmail.com> said: ASh> It looks like I've got lost. Could you please send a complete ASh> patchset (i.e. the patch being improved by this patch, and so ASh> on)
I am attaching the complete stack of patches on my computer, numbering starts from 2. The corrections in patch 0008 are my response to your comments om patch 0002. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv@maths.leeds.ac.uk www: http://www.maths.leeds.ac.uk/~kisilv/ Book: Geometry of Mobius Transformations http://www.worldscientific.com/worldscibooks/10.1142/p835
On 07/27/2013 12:51 AM, Vladimir V. Kisil wrote:
The method power::eval() contains the following rules:
// ^(*(...,x;c1),c2) -> *(^(*(...,x;1),c2),c1^c2) (c1, c2 numeric(), c1>0) // ^(*(...,x;c1),c2) -> *(^(*(...,x;-1),c2),(-c1)^c2) (c1, c2 numeric(), c1<0)
Is there a good reason why c1 here shall be numeric? Cannot we simply check the positive/negative info flag for c1 for that simplification?
The way it is written, these rewriting rules apply to expairseq. The c1 and c2 stand for overall_coeff, which is of type numeric by definition.
Shall I prepare a patch for this?
You may try. -richy. -- Richard B. Kreckel <http://www.ginac.de/~kreckel/>
Hello, Vladimir,
The method power::eval() contains the following rules:
// ^(*(...,x;c1),c2) -> *(^(*(...,x;1),c2),c1^c2) (c1, c2 numeric(), c1>0) // ^(*(...,x;c1),c2) -> *(^(*(...,x;-1),c2),(-c1)^c2) (c1, c2 numeric(), c1<0)
Is there a good reason why c1 here shall be numeric?
The idea is to pull the numeric factor out (so some cancellation can happen). Also this transformation is fast enough -- basically one need to replace the overall_coeff (of the mul object) with 1 (or -1), and multiply the result by a number (c1^c2, or (-c1)^c2).
Cannot we simply check the positive/negative info flag for c1 for that simplification?
Because such a check is *much* slower. Say, if x in the above expression is a sum, one need to check every term (which is possibly recursive). To make it reasonably efficient we need to cache info_flags::positive. That is, introduce status_flags::positive and status_flags::negative, and set/reset them properly in eval(), expand() (and possibly other methods).
Shall I prepare a patch for this?
You are welcome. Best regards, Alexei
participants (3)
-
Alexei Sheplyakov
-
Richard B. Kreckel
-
Vladimir V. Kisil