From 9df145c8bfa8ce9f2cbe6c05673481b6ca4c4c22 Mon Sep 17 00:00:00 2001 From: Richard Kreckel Date: Wed, 26 Jul 2000 00:49:22 +0000 Subject: [PATCH] - Made determinant_algo (in flags.h) really work. - Fixed minor bugs in matrix.cpp. - Small Documantation updates. --- INSTALL | 1 + check/check_matrices.cpp | 114 ++++++++++++------ check/exam_lsolve.cpp | 37 +++++- config.guess | 13 +- doc/tutorial/ginac.texi | 2 +- ginac/flags.h | 6 +- ginac/inifcns.cpp | 110 ++++++++++++----- ginac/inifcns.h | 7 +- ginac/inifcns_gamma.cpp | 30 ++--- ginac/matrix.cpp | 250 ++++++++++++++++++++------------------- ginac/matrix.h | 16 +-- ginac/numeric.h | 1 - 12 files changed, 358 insertions(+), 229 deletions(-) diff --git a/INSTALL b/INSTALL index 3730e91c..10e0b58f 100644 --- a/INSTALL +++ b/INSTALL @@ -113,3 +113,4 @@ to compile, install and work properly: < 5.14.39 | `VERBOTEN' by license (please bite your favorite lawyer) < 5.14.39,40 | compiles but does not feel happy at all (inconsistent!) 5.14.41 | tested on egcs 1.1.1, gcc 2.95.2: only minor weirdnesses + 5.14.44 | G__cpp_ginaccint.C needs manual fixes, doesn't work well diff --git a/check/check_matrices.cpp b/check/check_matrices.cpp index c1fa6257..3e702b8e 100644 --- a/check/check_matrices.cpp +++ b/check/check_matrices.cpp @@ -31,15 +31,13 @@ static unsigned integdom_matrix_determinants(void) for (int size=3; size<20; ++size) { matrix A(size,size); - for (int r=0; r&2 diff --git a/doc/tutorial/ginac.texi b/doc/tutorial/ginac.texi index 536bf897..bc330c7d 100644 --- a/doc/tutorial/ginac.texi +++ b/doc/tutorial/ginac.texi @@ -2075,7 +2075,7 @@ negative real axis where the points on the axis itself belong to the upper part (i.e. continuous with quadrant II). The inverse trigonometric and hyperbolic functions are not defined for complex arguments by the C++ standard, however. Here, we follow the conventions -used by CLN, which in turn follow the carefully structured definitions +used by CLN, which in turn follow the carefully designed definitions in the Common Lisp standard. Hopefully, future revisions of the C++ standard incorporate these functions in the complex domain in a manner compatible with Common Lisp. diff --git a/ginac/flags.h b/ginac/flags.h index 77e3ec01..41a890b1 100644 --- a/ginac/flags.h +++ b/ginac/flags.h @@ -39,9 +39,11 @@ public: }; }; -class determinant_options { +class determinant_algo { public: - enum { laplace, + enum { automatic, + gauss, + laplace, bareiss }; }; diff --git a/ginac/inifcns.cpp b/ginac/inifcns.cpp index e0d1e91e..b560100f 100644 --- a/ginac/inifcns.cpp +++ b/ginac/inifcns.cpp @@ -45,21 +45,21 @@ namespace GiNaC { // absolute value ////////// -static ex abs_evalf(const ex & x) +static ex abs_evalf(const ex & arg) { BEGIN_TYPECHECK - TYPECHECK(x,numeric) - END_TYPECHECK(abs(x)) + TYPECHECK(arg,numeric) + END_TYPECHECK(abs(arg)) - return abs(ex_to_numeric(x)); + return abs(ex_to_numeric(arg)); } -static ex abs_eval(const ex & x) +static ex abs_eval(const ex & arg) { - if (is_ex_exactly_of_type(x, numeric)) - return abs(ex_to_numeric(x)); + if (is_ex_exactly_of_type(arg, numeric)) + return abs(ex_to_numeric(arg)); else - return abs(x).hold(); + return abs(arg).hold(); } REGISTER_FUNCTION(abs, eval_func(abs_eval). @@ -70,41 +70,41 @@ REGISTER_FUNCTION(abs, eval_func(abs_eval). // Complex sign ////////// -static ex csgn_evalf(const ex & x) +static ex csgn_evalf(const ex & arg) { BEGIN_TYPECHECK - TYPECHECK(x,numeric) - END_TYPECHECK(csgn(x)) + TYPECHECK(arg,numeric) + END_TYPECHECK(csgn(arg)) - return csgn(ex_to_numeric(x)); + return csgn(ex_to_numeric(arg)); } -static ex csgn_eval(const ex & x) +static ex csgn_eval(const ex & arg) { - if (is_ex_exactly_of_type(x, numeric)) - return csgn(ex_to_numeric(x)); + if (is_ex_exactly_of_type(arg, numeric)) + return csgn(ex_to_numeric(arg)); - else if (is_ex_exactly_of_type(x, mul)) { - numeric oc = ex_to_numeric(x.op(x.nops()-1)); + else if (is_ex_exactly_of_type(arg, mul)) { + numeric oc = ex_to_numeric(arg.op(arg.nops()-1)); if (oc.is_real()) { if (oc > 0) // csgn(42*x) -> csgn(x) - return csgn(x/oc).hold(); + return csgn(arg/oc).hold(); else // csgn(-42*x) -> -csgn(x) - return -csgn(x/oc).hold(); + return -csgn(arg/oc).hold(); } if (oc.real().is_zero()) { if (oc.imag() > 0) // csgn(42*I*x) -> csgn(I*x) - return csgn(I*x/oc).hold(); + return csgn(I*arg/oc).hold(); else // csgn(-42*I*x) -> -csgn(I*x) - return -csgn(I*x/oc).hold(); + return -csgn(I*arg/oc).hold(); } } - return csgn(x).hold(); + return csgn(arg).hold(); } static ex csgn_series(const ex & arg, @@ -113,13 +113,10 @@ static ex csgn_series(const ex & arg, unsigned options) { const ex arg_pt = arg.subs(rel); - if (arg_pt.info(info_flags::numeric)) { - if (ex_to_numeric(arg_pt).real().is_zero()) - throw (std::domain_error("csgn_series(): on imaginary axis")); - epvector seq; - seq.push_back(expair(csgn(arg_pt), _ex0())); - return pseries(rel,seq); - } + if (arg_pt.info(info_flags::numeric) && + ex_to_numeric(arg_pt).real().is_zero()) + throw (std::domain_error("csgn_series(): on imaginary axis")); + epvector seq; seq.push_back(expair(csgn(arg_pt), _ex0())); return pseries(rel,seq); @@ -129,6 +126,61 @@ REGISTER_FUNCTION(csgn, eval_func(csgn_eval). evalf_func(csgn_evalf). series_func(csgn_series)); + +////////// +// Eta function: log(x*y) == log(x) + log(y) + eta(x,y). +////////// + +static ex eta_evalf(const ex & x, const ex & y) +{ + BEGIN_TYPECHECK + TYPECHECK(x,numeric) + TYPECHECK(y,numeric) + END_TYPECHECK(eta(x,y)) + + numeric xim = imag(ex_to_numeric(x)); + numeric yim = imag(ex_to_numeric(y)); + numeric xyim = imag(ex_to_numeric(x*y)); + return evalf(I/4*Pi)*((csgn(-xim)+1)*(csgn(-yim)+1)*(csgn(xyim)+1)-(csgn(xim)+1)*(csgn(yim)+1)*(csgn(-xyim)+1)); +} + +static ex eta_eval(const ex & x, const ex & y) +{ + if (is_ex_exactly_of_type(x, numeric) && + is_ex_exactly_of_type(y, numeric)) { + // don't call eta_evalf here because it would call Pi.evalf()! + numeric xim = imag(ex_to_numeric(x)); + numeric yim = imag(ex_to_numeric(y)); + numeric xyim = imag(ex_to_numeric(x*y)); + return (I/4)*Pi*((csgn(-xim)+1)*(csgn(-yim)+1)*(csgn(xyim)+1)-(csgn(xim)+1)*(csgn(yim)+1)*(csgn(-xyim)+1)); + } + + return eta(x,y).hold(); +} + +static ex eta_series(const ex & arg1, + const ex & arg2, + const relational & rel, + int order, + unsigned options) +{ + const ex arg1_pt = arg1.subs(rel); + const ex arg2_pt = arg2.subs(rel); + if (ex_to_numeric(arg1_pt).imag().is_zero() || + ex_to_numeric(arg2_pt).imag().is_zero() || + ex_to_numeric(arg1_pt*arg2_pt).imag().is_zero()) { + throw (std::domain_error("eta_series(): on discontinuity")); + } + epvector seq; + seq.push_back(expair(eta(arg1_pt,arg2_pt), _ex0())); + return pseries(rel,seq); +} + +REGISTER_FUNCTION(eta, eval_func(eta_eval). + evalf_func(eta_evalf). + series_func(eta_series)); + + ////////// // dilogarithm ////////// diff --git a/ginac/inifcns.h b/ginac/inifcns.h index 9781d935..95ed15a1 100644 --- a/ginac/inifcns.h +++ b/ginac/inifcns.h @@ -36,6 +36,9 @@ DECLARE_FUNCTION_1P(abs) /** Complex sign. */ DECLARE_FUNCTION_1P(csgn) +/** Eta function: log(a*b) == log(a) + log(b) + eta(a, b). */ +DECLARE_FUNCTION_2P(eta) + /** Sine. */ DECLARE_FUNCTION_1P(sin) @@ -87,7 +90,7 @@ DECLARE_FUNCTION_1P(Li2) /** Trilogarithm. */ DECLARE_FUNCTION_1P(Li3) -// overloading at work: we cannot use the macros +// overloading at work: we cannot use the macros here /** Riemann's Zeta-function. */ extern const unsigned function_index_zeta1; inline function zeta(const ex & p1) { @@ -106,7 +109,7 @@ DECLARE_FUNCTION_1P(tgamma) /** Beta-function. */ DECLARE_FUNCTION_2P(beta) -// overloading at work: we cannot use the macros +// overloading at work: we cannot use the macros here /** Psi-function (aka digamma-function). */ extern const unsigned function_index_psi1; inline function psi(const ex & p1) { diff --git a/ginac/inifcns_gamma.cpp b/ginac/inifcns_gamma.cpp index bf60c1e5..aa1cab4c 100644 --- a/ginac/inifcns_gamma.cpp +++ b/ginac/inifcns_gamma.cpp @@ -63,11 +63,10 @@ static ex lgamma_eval(const ex & x) // trap integer arguments: if (x.info(info_flags::integer)) { // lgamma(n) -> log((n-1)!) for postitive n - if (x.info(info_flags::posint)) { + if (x.info(info_flags::posint)) return log(factorial(x.exadd(_ex_1()))); - } else { + else throw (pole_error("lgamma_eval(): logarithmic pole",0)); - } } // lgamma_evalf should be called here once it becomes available } @@ -98,15 +97,16 @@ static ex lgamma_series(const ex & arg, // from which follows // series(lgamma(x),x==-m,order) == // series(lgamma(x+m+1)-log(x)...-log(x+m)),x==-m,order); - // This, however, seems to fail utterly because you run into branch-cut - // problems. Somebody ought to implement it some day using an asymptotic - // series for tgamma: const ex arg_pt = arg.subs(rel); if (!arg_pt.info(info_flags::integer) || arg_pt.info(info_flags::positive)) throw do_taylor(); // caught by function::series() // if we got here we have to care for a simple pole of tgamma(-m): - throw (std::overflow_error("lgamma_series: please implement my at the poles")); - return _ex0(); // not reached + numeric m = -ex_to_numeric(arg_pt); + ex recur; + for (numeric p; p<=m; ++p) + recur += log(arg+p); + cout << recur << endl; + return (lgamma(arg+m+_ex1())-recur).series(rel, order, options); } @@ -202,7 +202,7 @@ static ex tgamma_series(const ex & arg, ex ser_denom = _ex1(); for (numeric p; p<=m; ++p) ser_denom *= arg+p; - return (tgamma(arg+m+_ex1())/ser_denom).series(rel, order+1); + return (tgamma(arg+m+_ex1())/ser_denom).series(rel, order+1, options); } @@ -299,21 +299,21 @@ static ex beta_series(const ex & arg1, throw do_taylor(); // caught by function::series() // trap the case where arg1 is on a pole: if (arg1.info(info_flags::integer) && !arg1.info(info_flags::positive)) - arg1_ser = tgamma(arg1+*s).series(rel,order); + arg1_ser = tgamma(arg1+*s).series(rel, order, options); else arg1_ser = tgamma(arg1).series(rel,order); // trap the case where arg2 is on a pole: if (arg2.info(info_flags::integer) && !arg2.info(info_flags::positive)) - arg2_ser = tgamma(arg2+*s).series(rel,order); + arg2_ser = tgamma(arg2+*s).series(rel, order, options); else arg2_ser = tgamma(arg2).series(rel,order); // trap the case where arg1+arg2 is on a pole: if ((arg1+arg2).info(info_flags::integer) && !(arg1+arg2).info(info_flags::positive)) - arg1arg2_ser = tgamma(arg2+arg1+*s).series(rel,order); + arg1arg2_ser = tgamma(arg2+arg1+*s).series(rel, order, options); else arg1arg2_ser = tgamma(arg2+arg1).series(rel,order); // compose the result (expanding all the terms): - return (arg1_ser*arg2_ser/arg1arg2_ser).series(rel,order).expand(); + return (arg1_ser*arg2_ser/arg1arg2_ser).series(rel, order, options).expand(); } @@ -410,7 +410,7 @@ static ex psi1_series(const ex & arg, ex recur; for (numeric p; p<=m; ++p) recur += power(arg+p,_ex_1()); - return (psi(arg+m+_ex1())-recur).series(rel, order); + return (psi(arg+m+_ex1())-recur).series(rel, order, options); } const unsigned function_index_psi1 = @@ -536,7 +536,7 @@ static ex psi2_series(const ex & n, for (numeric p; p<=m; ++p) recur += power(arg+p,-n+_ex_1()); recur *= factorial(n)*power(_ex_1(),n); - return (psi(n, arg+m+_ex1())-recur).series(rel, order); + return (psi(n, arg+m+_ex1())-recur).series(rel, order, options); } const unsigned function_index_psi2 = diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp index feae32fe..52b4de36 100644 --- a/ginac/matrix.cpp +++ b/ginac/matrix.cpp @@ -152,7 +152,7 @@ void matrix::archive(archive_node &n) const exvector::const_iterator i = m.begin(), iend = m.end(); while (i != iend) { n.add_ex("m", *i); - i++; + ++i; } } @@ -174,15 +174,13 @@ void matrix::print(std::ostream & os, unsigned upper_precedence) const os << "[[ "; for (unsigned r=0; r=0); + GINAC_ASSERT(isetflag(status_flags::dynallocated | status_flags::evaluated ); @@ -291,11 +288,10 @@ ex matrix::evalf(int level) const // evalf() entry by entry exvector m2(row*col); --level; - for (unsigned r=0; rm); exvector::iterator i; exvector::const_iterator ci; - for (i=sum.begin(), ci=other.m.begin(); - i!=sum.end(); - ++i, ++ci) { + for (i=sum.begin(), ci=other.m.begin(); i!=sum.end(); ++i, ++ci) (*i) += (*ci); - } + return matrix(row,col,sum); } @@ -363,11 +357,9 @@ matrix matrix::sub(const matrix & other) const exvector dif(this->m); exvector::iterator i; exvector::const_iterator ci; - for (i=dif.begin(), ci=other.m.begin(); - i!=dif.end(); - ++i, ++ci) { + for (i=dif.begin(), ci=other.m.begin(); i!=dif.end(); ++i, ++ci) (*i) -= (*ci); - } + return matrix(row,col,dif); } @@ -438,7 +430,7 @@ matrix matrix::transpose(void) const /** Determinant of square matrix. This routine doesn't actually calculate the * determinant, it only implements some heuristics about which algorithm to - * call. If all the elements of the matrix are elements of an integral domain + * run. If all the elements of the matrix are elements of an integral domain * the determinant is also in that integral domain and the result is expanded * only. If one or more elements are from a quotient field the determinant is * usually also in that quotient field and the result is normalized before it @@ -446,85 +438,105 @@ matrix matrix::transpose(void) const * [[a/(a-b),1],[b/(a-b),1]] is returned as unity. (In this respect, it * behaves like MapleV and unlike Mathematica.) * + * @param algo allows to chose an algorithm * @return the determinant as a new expression - * @exception logic_error (matrix not square) */ -ex matrix::determinant(void) const + * @exception logic_error (matrix not square) + * @see determinant_algo */ +ex matrix::determinant(unsigned algo) const { if (row!=col) throw (std::logic_error("matrix::determinant(): matrix not square")); GINAC_ASSERT(row*col==m.capacity()); if (this->row==1) // continuation would be pointless return m[0]; - - // Gather some information about the matrix: + + // Gather some statistical information about this matrix: bool numeric_flag = true; bool normal_flag = false; - unsigned sparse_count = 0; // count non-zero elements + unsigned sparse_count = 0; // counts non-zero elements for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r) { - if (!(*r).is_zero()) + lst srl; // symbol replacement list + ex rtest = (*r).to_rational(srl); + if (!rtest.is_zero()) ++sparse_count; - if (!(*r).info(info_flags::numeric)) + if (!rtest.info(info_flags::numeric)) numeric_flag = false; - if ((*r).info(info_flags::rational_function) && - !(*r).info(info_flags::crational_polynomial)) + if (!rtest.info(info_flags::crational_polynomial) && + rtest.info(info_flags::rational_function)) normal_flag = true; } - // Purely numeric matrix handled by Gauss elimination - if (numeric_flag) { - ex det = 1; - matrix tmp(*this); - int sign = tmp.gauss_elimination(); - for (int d=0; d uintpair; // # of zeros, column - std::vector c_zeros; // number of zeros in column - for (unsigned c=0; c can't be used for permutation_sign. - std::vector pre_sort; - for (std::vector::iterator i=c_zeros.begin(); i!=c_zeros.end(); ++i) - pre_sort.push_back(i->second); - int sign = permutation_sign(pre_sort); - exvector result(row*col); // represents sorted matrix - unsigned c = 0; - for (std::vector::iterator i=pre_sort.begin(); - i!=pre_sort.end(); - ++i,++c) { - for (unsigned r=0; r uintpair; + std::vector c_zeros; // number of zeros in column + for (unsigned c=0; c pre_sort; + for (std::vector::iterator i=c_zeros.begin(); i!=c_zeros.end(); ++i) + pre_sort.push_back(i->second); + int sign = permutation_sign(pre_sort); + exvector result(row*col); // represents sorted matrix + unsigned c = 0; + for (std::vector::iterator i=pre_sort.begin(); + i!=pre_sort.end(); + ++i,++c) { + for (unsigned r=0; rn) { // row consists only of zeroes, corresponding rhs must be 0 as well - if (!b(r,0).is_zero()) { + if (!b.m[r*b.cols()].is_zero()) { throw (std::runtime_error("matrix::fraction_free_elim(): singular matrix")); } } else { // assign solutions for vars between first_non_zero+1 and // last_assigned_sol-1: free parameters for (unsigned c=first_non_zero; c need not be included: - class range_error; -} - #ifndef NO_NAMESPACE_GINAC namespace GiNaC { #endif // ndef NO_NAMESPACE_GINAC @@ -82,9 +77,9 @@ protected: // non-virtual functions in this class public: - unsigned rows(void) const //! get number of rows. + unsigned rows(void) const //! Get number of rows. { return row; } - unsigned cols(void) const //! get number of columns. + unsigned cols(void) const //! Get number of columns. { return col; } matrix add(const matrix & other) const; matrix sub(const matrix & other) const; @@ -92,7 +87,7 @@ public: const ex & operator() (unsigned ro, unsigned co) const; matrix & set(unsigned ro, unsigned co, ex value); matrix transpose(void) const; - ex determinant(void) const; + ex determinant(unsigned options = determinant_algo::automatic) const; ex trace(void) const; ex charpoly(const symbol & lambda) const; matrix inverse(void) const; @@ -105,7 +100,6 @@ protected: int division_free_elimination(void); int fraction_free_elimination(bool det = false); int pivot(unsigned ro, bool symbolic=true); - void swap(unsigned r1, unsigned c1, unsigned r2 ,unsigned c2); // member variables protected: @@ -147,8 +141,8 @@ inline unsigned cols(const matrix & m) inline matrix transpose(const matrix & m) { return m.transpose(); } -inline ex determinant(const matrix & m) -{ return m.determinant(); } +inline ex determinant(const matrix & m, unsigned options = determinant_algo::automatic) +{ return m.determinant(options); } inline ex trace(const matrix & m) { return m.trace(); } diff --git a/ginac/numeric.h b/ginac/numeric.h index d55e1d13..c5086f43 100644 --- a/ginac/numeric.h +++ b/ginac/numeric.h @@ -83,7 +83,6 @@ class numeric : public basic friend const numeric atanh(const numeric & x); friend const numeric Li2(const numeric & x); friend const numeric zeta(const numeric & x); - // friend const numeric bernoulli(const numeric & n); friend const numeric fibonacci(const numeric & n); friend numeric abs(const numeric & x); friend numeric mod(const numeric & a, const numeric & b); -- 2.45.0