From Chris.Dams at mi.infn.it Fri Sep 9 16:44:49 2005 From: Chris.Dams at mi.infn.it (Chris Dams) Date: Fri, 9 Sep 2005 16:44:49 +0200 (CEST) Subject: [GiNaC-devel] patch for power::expand_mul Message-ID: Dear developers, Could you change the line if (get_all_dummy_indices(m).size() > 0) { that occurs in the function power::expand_mul in power.cpp into if (get_all_dummy_indices(m).size() > 0 && n.is_positive()) { Reason: I sometimes use algebraic substitution for expressions involving indices. For instance using the pattern indexed(UL1inv,wildgen,wildgen2)*indexed(UL1,wildgen2,wildgen3) ==delta_tensor(wildgen,wildgen3) to cancel a matrix multiplied with its inverse. Internally, algebraic subsitution divides by the factors it wants to get rid of but since Vladimir Kisils patch this goes wrong if these factors contain a contraction. Best wishes, Chris From kreckel at ginac.de Mon Sep 12 22:16:27 2005 From: kreckel at ginac.de (Richard B. Kreckel) Date: Mon, 12 Sep 2005 22:16:27 +0200 (CEST) Subject: [GiNaC-devel] Numerical integration in GiNaC Message-ID: Hi Chris! I was playing with the adaptive Simpson function and found some problems evaluating numerically a (well-behaved) integral. I've a couple of questions: 1) Why the decision to *not* couple the precision to the value of Digits? Coupling it to Digits would make it available in Ginsh. Wouldn't it do the right thing in almost all cases? 2) Are variations of Simpson's rule really attractive for numerical evaluation? Have you considered/tried something funkier (maybe Romberg's method) or is that a particularly smart implementation? 3) Probably an oversight: the last argument to the adaptivesimpson function is unused. Instead, the code always uses the default. Best wishes -richy. -- Richard B. Kreckel From kreckel at ginac.de Mon Sep 12 23:19:50 2005 From: kreckel at ginac.de (Richard B. Kreckel) Date: Mon, 12 Sep 2005 23:19:50 +0200 (CEST) Subject: [GiNaC-devel] Numerical integration in GiNaC In-Reply-To: Message-ID: On Mon, 12 Sep 2005, Richard B. Kreckel wrote: > I was playing with the adaptive Simpson function and found some problems > evaluating numerically a (well-behaved) integral. I've a couple of > questions: [...] 4) The lookup table does not seem to discriminate among different precisions. Presuming the last argument to adaptivesimpson() would be used or the precision be coupled to Digits. Then the lookup map would have to hold the precision as well (on the key side, not the value side). Otherwise it becomes impossible to re-run an integration with a higher precision goal. Best wishes -richy. -- Richard B. Kreckel From C.Dams at science.ru.nl Tue Sep 13 12:13:11 2005 From: C.Dams at science.ru.nl (Chris Dams) Date: Tue, 13 Sep 2005 12:13:11 +0200 Subject: [GiNaC-devel] Numerical integration in GiNaC In-Reply-To: References: Message-ID: <1126606391.3901.19.camel@gamow.sci.kun.nl> Dear Richy, On Mon, 2005-09-12 at 22:16 +0200, Richard B. Kreckel wrote: > 1) Why the decision to *not* couple the precision to the value of Digits? > Coupling it to Digits would make it available in Ginsh. Wouldn't it do > the right thing in almost all cases? It depends on what coupling you have in mind. As different users may have different preferences, I thought it was best to leave it up to the user. Note that it would be a highly dangerous idea to make the precision of integration equal to the precision of the other numerical calculations. This is because the last few digits of a calculated number may not be very trustworthy and all kind of artifacts could be in them. A continuous function could look non-continuous depending on the algorithm used for calculation. Then the adaptive simpson method would go *boink*. > 2) Are variations of Simpson's rule really attractive for numerical > evaluation? Have you considered/tried something funkier (maybe > Romberg's method) or is that a particularly smart implementation? I thought it was quite nice. Convergence as 1/N^4 and adaptivity. It has been some time that I looked at this, so I forgot why I took the adaptive Simpson algorithm. Presumably there was something in the book by Burden and Faires that made me go for the adaptive Simpson algorithm. Unfortunately I do not have that book now that I am in Milan and the library seems to be reorganizing until december or so :-(. Of course, there could also be an integral::integration_method to give the user a choice what method to use. > 3) Probably an oversight: the last argument to the adaptivesimpson > function is unused. Instead, the code always uses the default. Yes, the obvious fix for this is to turn all occurances of integral::relative_integration_error into error. Could you do this in CVS? Best wishes, Chris From C.Dams at science.ru.nl Tue Sep 13 12:18:00 2005 From: C.Dams at science.ru.nl (Chris Dams) Date: Tue, 13 Sep 2005 12:18:00 +0200 Subject: [GiNaC-devel] Numerical integration in GiNaC In-Reply-To: References: Message-ID: <1126606680.3901.23.camel@gamow.sci.kun.nl> Hello again, On Mon, 2005-09-12 at 23:19 +0200, Richard B. Kreckel wrote: > 4) The lookup table does not seem to discriminate among different > precisions. Presuming the last argument to adaptivesimpson() would > be used or the precision be coupled to Digits. Then the lookup map > would have to hold the precision as well (on the key side, not the > value side). Otherwise it becomes impossible to re-run an > integration with a higher precision goal. Yes, this seems a good idea. I think, I will write a path for that when I have some time. Best wishes, Chris From Chris.Dams at mi.infn.it Thu Sep 15 18:46:22 2005 From: Chris.Dams at mi.infn.it (Chris Dams) Date: Thu, 15 Sep 2005 18:46:22 +0200 (CEST) Subject: [GiNaC-devel] Patch for adaptivesimpson. Message-ID: Dear developers, Could you apply the attached patch to integral.cpp? It adds some checks to adaptivesimpson to see whether the boundaries of integration and the integration error really are numbers and, as discussed with Richy, it makes the lookup table take into account that adaptivesimpson may be called with the same integral but different precision. Best wishes, Chris -------------- next part -------------- Index: ginac/integral.cpp =================================================================== RCS file: /home/cvs/GiNaC/ginac/integral.cpp,v retrieving revision 1.6 diff -c -r1.6 integral.cpp *** ginac/integral.cpp 13 Sep 2005 20:41:25 -0000 1.6 --- ginac/integral.cpp 15 Sep 2005 16:39:04 -0000 *************** *** 213,218 **** --- 213,241 ---- throw logic_error("integrant does not evaluate to numeric"); } + struct error_and_integral + { + error_and_integral(const ex &err, const ex &integ) + :error(err), integral(integ){} + ex error; + ex integral; + }; + + struct error_and_integral_is_less + { + bool operator()(const error_and_integral &e1,const error_and_integral &e2) + { + int c = e1.integral.compare(e2.integral); + if(c < 0) + return true; + if(c > 0) + return false; + return ex_is_less()(e1.error, e2.error); + } + }; + + typedef map lookup_map; + /** Numeric integration routine based upon the "Adaptive Quadrature" one * in "Numerical Analysis" by Burden and Faires. Parameters are integration * variable, left boundary, right boundary, function to be integrated and *************** *** 220,232 **** * after substituting the integration variable by a number. Another thing * to note is that this implementation is no good at integrating functions * with discontinuities. */ ! ex adaptivesimpson(const ex & x, const ex & a, const ex & b, const ex & f, const ex & error) { ! // use lookup table to be potentially much faster. ! static exmap lookup; static symbol ivar("ivar"); ex lookupex = integral(ivar,a,b,f.subs(x==ivar)); ! exmap::iterator emi = lookup.find(lookupex); if (emi!=lookup.end()) return emi->second; --- 243,263 ---- * after substituting the integration variable by a number. Another thing * to note is that this implementation is no good at integrating functions * with discontinuities. */ ! ex adaptivesimpson(const ex & x, const ex & a_in, const ex & b_in, const ex & f, const ex & error) { ! // Check whether boundaries and error are numbers. ! ex a = is_exactly_a(a_in) ? a_in : a_in.evalf(); ! ex b = is_exactly_a(b_in) ? b_in : b_in.evalf(); ! if(!is_exactly_a(a) || !is_exactly_a(b)) ! throw std::runtime_error("For numerical integration the boundaries of the integral should evalf into numbers."); ! if(!is_exactly_a(error)) ! throw std::runtime_error("For numerical integration the error should be a number."); ! ! // Use lookup table to be potentially much faster. ! static lookup_map lookup; static symbol ivar("ivar"); ex lookupex = integral(ivar,a,b,f.subs(x==ivar)); ! lookup_map::iterator emi = lookup.find(error_and_integral(error, lookupex)); if (emi!=lookup.end()) return emi->second; *************** *** 291,297 **** } } ! lookup[lookupex]=app; return app; } --- 322,328 ---- } } ! lookup[error_and_integral(error, lookupex)]=app; return app; } From kisilv at maths.leeds.ac.uk Mon Sep 26 23:32:43 2005 From: kisilv at maths.leeds.ac.uk (Vladimir Kisil) Date: Mon, 26 Sep 2005 22:32:43 +0100 Subject: [GiNaC-devel] Function & Power patch Message-ID: Dear All, There are many functions (abs, Heaviside, exp) which possess some power-simplification rules. I propose a patch to power.cpp and function.pl which allows to defines such rules in a way similar to derivative rules of functions. With the help of this I slightly improve the definition of abs() and it work now in this way: #include using namespace GiNaC; int main(){ realsymbol a("a"); cout << pow(abs(a), 2) << endl; // -> a^2 cout << pow(abs(a), 3) << endl; // -> abs(a)^3 symbol r("r"); cout << pow(abs(r), 2) << endl; // -> abs(r)^2 cout << pow(abs(r), 3) << endl; // -> abs(r)^3 } i.e. pow(abs(a), 2*n) is simplified to pow(a, 2*n) for real a. I also delete a duplicated line from ginac.texi. If it will be useful to add a definition of Heaviside function to the GiNaC core, I can send a patch as well. Best wishes, Vladimir -- Vladimir V. Kisil email: kisilv at maths.leeds.ac.uk -- www: http://maths.leeds.ac.uk/~kisilv/ -------------- next part -------------- A non-text attachment was scrubbed... Name: ginac.diff Type: text/x-c Size: 3988 bytes Desc: Diff file of the patch URL: From Chris.Dams at mi.infn.it Fri Sep 30 16:56:33 2005 From: Chris.Dams at mi.infn.it (Chris Dams) Date: Fri, 30 Sep 2005 16:56:33 +0200 (CEST) Subject: [GiNaC-devel] patch for simplify_indexed. Message-ID: Dear developers, When simplify_indexed() is called two symmetrizations w.r.t dummy indices are performed. In these two cases symmetrization w.r.t. all dummy indices is done. However, it is also possible to do symmetrization with respect to ordinary idx-es, varidx-es and spinidx-es seperately. The latter is potentially much faster. E.g. Today I had an example where some terms contained 5 ordinary dummy indices and 2 dummy indices with variance. In this case a factor of 21 fewer terms are generated by the latter option. (I.e. 7!/5!/2!=21). Therefore symmetrizing seperately can be much faster. A patch is attached. Best wishes, Chris -------------- next part -------------- Index: ginac/indexed.cpp =================================================================== RCS file: /home/cvs/GiNaC/ginac/indexed.cpp,v retrieving revision 1.96 diff -c -r1.96 indexed.cpp *** ginac/indexed.cpp 19 May 2005 14:10:40 -0000 1.96 --- ginac/indexed.cpp 30 Sep 2005 14:43:59 -0000 *************** *** 557,563 **** int remaining = local_size - global_size; exvector::const_iterator it = local_dummy_indices.begin(), itend = local_dummy_indices.end(); while (it != itend && remaining > 0) { ! if (find_if(global_dummy_indices.begin(), global_dummy_indices.end(), bind2nd(op0_is_equal(), *it)) == global_dummy_indices.end()) { global_dummy_indices.push_back(*it); global_size++; remaining--; --- 557,563 ---- int remaining = local_size - global_size; exvector::const_iterator it = local_dummy_indices.begin(), itend = local_dummy_indices.end(); while (it != itend && remaining > 0) { ! if (find_if(global_dummy_indices.begin(), global_dummy_indices.end(), bind2nd(idx_is_equal_ignore_dim(), *it)) == global_dummy_indices.end()) { global_dummy_indices.push_back(*it); global_size++; remaining--; *************** *** 704,709 **** --- 704,721 ---- } } + template ex idx_symmetrization(const ex& r,const exvector& local_dummy_indices) + { exvector dummy_syms; + dummy_syms.reserve(r.nops()); + for (exvector::const_iterator it = local_dummy_indices.begin(); it != local_dummy_indices.end(); ++it) + if(is_exactly_a(*it)) + dummy_syms.push_back(it->op(0)); + if(dummy_syms.size() < 2) + return r; + ex q=symmetrize(r, dummy_syms); + return q; + } + /** Simplify product of indexed expressions (commutative, noncommutative and * simple squares), return list of free indices. */ ex simplify_indexed_product(const ex & e, exvector & free_indices, exvector & dummy_indices, const scalar_products & sp) *************** *** 864,878 **** // The result should be symmetric with respect to exchange of dummy // indices, so if the symmetrization vanishes, the whole expression is // zero. This detects things like eps.i.j.k * p.j * p.k = 0. ! if (local_dummy_indices.size() >= 2) { ! exvector dummy_syms; ! dummy_syms.reserve(local_dummy_indices.size()); ! for (exvector::const_iterator it = local_dummy_indices.begin(); it != local_dummy_indices.end(); ++it) ! dummy_syms.push_back(it->op(0)); ! if (symmetrize(r, dummy_syms).is_zero()) { ! free_indices.clear(); ! return _ex0; ! } } // Dummy index renaming --- 876,895 ---- // The result should be symmetric with respect to exchange of dummy // indices, so if the symmetrization vanishes, the whole expression is // zero. This detects things like eps.i.j.k * p.j * p.k = 0. ! ex q = idx_symmetrization(r, local_dummy_indices); ! if (q.is_zero()) { ! free_indices.clear(); ! return _ex0; ! } ! q = idx_symmetrization(q, local_dummy_indices); ! if (q.is_zero()) { ! free_indices.clear(); ! return _ex0; ! } ! q = idx_symmetrization(q, local_dummy_indices); ! if (q.is_zero()) { ! free_indices.clear(); ! return _ex0; } // Dummy index renaming *************** *** 1015,1032 **** if (num_terms_orig < 2 || dummy_indices.size() < 2) return sum; - // Yes, construct vector of all dummy index symbols - exvector dummy_syms; - dummy_syms.reserve(dummy_indices.size()); - for (exvector::const_iterator it = dummy_indices.begin(); it != dummy_indices.end(); ++it) - dummy_syms.push_back(it->op(0)); - // Chop the sum into terms and symmetrize each one over the dummy // indices std::vector terms; for (size_t i=0; i terms; for (size_t i=0; i(term, dummy_indices); ! term_symm = idx_symmetrization(term_symm, dummy_indices); ! term_symm = idx_symmetrization(term_symm, dummy_indices); if (term_symm.is_zero()) continue; terms.push_back(terminfo(term, term_symm));