This file records noteworthy changes.
+1.1.1 (<date>)
+* lst (and exprseq) provide iterators for read-only element access. For
+ sequential access this is one order faster than using op().
+
1.1.0 (3 April 2003)
* Removed deprecated macros is_ex_a, is_ex_exactly_a and friends for good.
* The scalar_products mechanism allows the specification of an index dimension.
GINACLIB_MAJOR_VERSION=1
GINACLIB_MINOR_VERSION=1
-GINACLIB_MICRO_VERSION=0
+GINACLIB_MICRO_VERSION=1
GINACLIB_INTERFACE_AGE=0
GINACLIB_BINARY_AGE=0
GINACLIB_VERSION=$GINACLIB_MAJOR_VERSION.$GINACLIB_MINOR_VERSION.$GINACLIB_MICRO_VERSION
...
@end example
+As with the standard @code{list<T>} container, accessing random elements of a
+@code{lst} is generally an operation of order @math{O(N)}. Faster read-only
+sequential access to the elements of a list is possible with the
+iterator types provided by the @code{lst} class:
+
+@example
+typedef ... lst::const_iterator;
+typedef ... lst::const_reverse_iterator;
+lst::const_iterator lst::begin() const;
+lst::const_iterator lst::end() const;
+lst::const_reverse_iterator lst::rbegin() const;
+lst::const_reverse_iterator lst::rend() const;
+@end example
+
+For example, to print the elements of a list individually you can use:
+
+@example
+ ...
+ // O(N)
+ for (lst::const_iterator i = l.begin(); i != l.end(); ++i)
+ cout << *i << endl;
+ ...
+@end example
+
+which is one order faster than
+
+@example
+ ...
+ // O(N^2)
+ for (size_t i = 0; i < l.nops(); ++i)
+ cout << l.op(i) << endl;
+ ...
+@end example
+
+These iterators also allow you to use some of the algorithms provided by
+the C++ standard library:
+
+@example
+ ...
+ // sum up the elements of the list (requires #include <numeric>)
+ ex sum = accumulate(l.begin(), l.end(), ex(0));
+ cout << sum << endl; // prints '2+2*x+2*y'
+ ...
+@end example
+
@code{lst} is one of the few GiNaC classes that allow in-place modifications
(the only other one is @code{matrix}). You can modify single elements:
// Wildcard matches anything, but check whether we already have found
// a match for that wildcard first (if so, it the earlier match must
// be the same expression)
- for (size_t i=0; i<repl_lst.nops(); i++) {
- if (repl_lst.op(i).op(0).is_equal(pattern))
- return is_equal(ex_to<basic>(repl_lst.op(i).op(1)));
+ for (lst::const_iterator it = repl_lst.begin(); it != repl_lst.end(); ++it) {
+ if (it->op(0).is_equal(pattern))
+ return is_equal(ex_to<basic>(it->op(1)));
}
repl_lst.append(pattern == *this);
return true;
{
GINAC_ASSERT(ls.nops() == lr.nops());
+ lst::const_iterator its, itr;
+
if (options & subs_options::subs_no_pattern) {
- for (size_t i=0; i<ls.nops(); i++) {
- if (is_equal(ex_to<basic>(ls.op(i))))
- return lr.op(i);
+ for (its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
+ if (is_equal(ex_to<basic>(*its)))
+ return *itr;
}
} else {
- for (size_t i=0; i<ls.nops(); i++) {
+ for (its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
lst repl_lst;
- if (match(ex_to<basic>(ls.op(i)), repl_lst))
- return lr.op(i).subs(repl_lst, options | subs_options::subs_no_pattern); // avoid infinite recursion when re-substituting the wildcards
+ if (match(ex_to<basic>(*its), repl_lst))
+ return itr->subs(repl_lst, options | subs_options::subs_no_pattern); // avoid infinite recursion when re-substituting the wildcards
}
}
if (!e.info(info_flags::list)) {
throw(std::invalid_argument("basic::subs(ex): argument must be a list"));
}
+
+ // Split list into two
lst ls;
lst lr;
- for (size_t i=0; i<e.nops(); i++) {
- ex r = e.op(i);
+ GINAC_ASSERT(is_a<lst>(e));
+ for (lst::const_iterator it = ex_to<lst>(e).begin(); it != ex_to<lst>(e).end(); ++it) {
+ ex r = *it;
if (!r.info(info_flags::relation_equal)) {
throw(std::invalid_argument("basic::subs(ex): argument must be a list of equations"));
}
ex aux = e.to_rational(srl);
for (size_t i=0; i<srl.nops(); i++) {
- ex lhs = srl.op(i).lhs();
- ex rhs = srl.op(i).rhs();
+ ex o = srl.op(i);
+ ex lhs = o.lhs();
+ ex rhs = o.rhs();
if (is_exactly_a<ncmul>(rhs)
&& rhs.return_type() == return_types::noncommutative
{
GINAC_DECLARE_REGISTERED_CLASS(${CONTAINER}, basic)
+public:
+ typedef ${STLT}::const_iterator const_iterator;
+ typedef ${STLT}::const_reverse_iterator const_reverse_iterator;
+
public:
${CONTAINER}(${STLT} const & s, bool discardable = false);
${CONTAINER}(${STLT} * vp); // vp will be deleted
virtual ex this${CONTAINER}(${STLT} const & v) const;
virtual ex this${CONTAINER}(${STLT} * vp) const;
+ // non-virtual functions in this class
+public:
+ const_iterator begin() const {return seq.begin();}
+ const_iterator end() const {return seq.end();}
+ const_reverse_iterator rbegin() const {return seq.rbegin();}
+ const_reverse_iterator rend() const {return seq.rend();}
+
protected:
bool is_canonical() const;
${STLT} evalchildren(int level) const;
for (size_t i=0; i<num; i++)
vp->push_back(split_ex_to_pair(ops[i]));
ex rest = thisexpairseq(vp, default_overall_coeff());
- for (size_t i=0; i<repl_lst.nops(); i++) {
- if (repl_lst.op(i).op(0).is_equal(global_wildcard))
- return rest.is_equal(repl_lst.op(i).op(1));
+ for (lst::const_iterator it = repl_lst.begin(); it != repl_lst.end(); ++it) {
+ if (it->op(0).is_equal(global_wildcard))
+ return rest.is_equal(it->op(1));
}
repl_lst.append(global_wildcard == rest);
return true;
// is a product or power. In this case we have to recombine the pairs
// because the numeric coefficients may be part of the search pattern.
bool complex_subs = false;
- for (size_t i=0; i<ls.nops(); ++i) {
- if (is_exactly_a<mul>(ls.op(i)) || is_exactly_a<power>(ls.op(i))) {
+ for (lst::const_iterator it = ls.begin(); it != ls.end(); ++it) {
+ if (is_exactly_a<mul>(*it) || is_exactly_a<power>(*it)) {
complex_subs = true;
break;
}
GINAC_ASSERT(ls.nops() == lr.nops());
// First look for index substitutions
- for (size_t i=0; i<ls.nops(); i++) {
- if (is_equal(ex_to<basic>(ls.op(i)))) {
+ lst::const_iterator its, itr;
+ for (its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
+ if (is_equal(ex_to<basic>(*its))) {
// Substitution index->index
- if (is_a<idx>(lr.op(i)))
- return lr.op(i);
+ if (is_a<idx>(*itr))
+ return *itr;
// Otherwise substitute value
idx *i_copy = static_cast<idx *>(duplicate());
- i_copy->value = lr.op(i);
+ i_copy->value = *itr;
i_copy->clearflag(status_flags::hash_calculated);
return i_copy->setflag(status_flags::dynallocated);
}
void scalar_products::add_vectors(const lst & l, const ex & dim)
{
// Add all possible pairs of products
- size_t num = l.nops();
- for (size_t i=0; i<num; i++) {
- ex a = l.op(i);
- for (size_t j=0; j<num; j++) {
- ex b = l.op(j);
- add(a, b, dim, a*b);
- }
- }
+ for (lst::const_iterator it1 = l.begin(); it1 != l.end(); ++it1)
+ for (lst::const_iterator it2 = l.begin(); it2 != l.end(); ++it2)
+ add(*it1, *it2, *it1 * *it2);
}
void scalar_products::clear(void)
#include "lst.h"
#include "idx.h"
#include "indexed.h"
+#include "add.h"
#include "power.h"
#include "symbol.h"
#include "operators.h"
{
m.resize(r*c, _ex0);
- for (size_t i=0; i<l.nops(); i++) {
+ size_t i = 0;
+ for (lst::const_iterator it = l.begin(); it != l.end(); ++it, ++i) {
size_t x = i % c;
size_t y = i / c;
if (y >= r)
break; // matrix smaller than list: throw away excessive elements
- m[y*c+x] = l.op(i);
+ m[y*c+x] = *it;
}
}
// trapped and we use Leverrier's algorithm which goes as row^3 for
// every coefficient. The expensive part is the matrix multiplication.
if (numeric_flag) {
+
matrix B(*this);
ex c = B.trace();
ex poly = power(lambda,row)-c*power(lambda,row-1);
for (unsigned j=0; j<row; ++j)
B.m[j*col+j] -= c;
B = this->mul(B);
- c = B.trace()/ex(i+1);
+ c = B.trace() / ex(i+1);
poly -= c*power(lambda,row-i-1);
}
if (row%2)
return -poly;
else
return poly;
- }
+
+ } else {
- matrix M(*this);
- for (unsigned r=0; r<col; ++r)
- M.m[r*col+r] -= lambda;
+ matrix M(*this);
+ for (unsigned r=0; r<col; ++r)
+ M.m[r*col+r] -= lambda;
- return M.determinant().collect(lambda);
+ return M.determinant().collect(lambda);
+ }
}
ex lst_to_matrix(const lst & l)
{
+ lst::const_iterator itr, itc;
+
// Find number of rows and columns
- size_t rows = l.nops(), cols = 0, i, j;
- for (i=0; i<rows; i++)
- if (l.op(i).nops() > cols)
- cols = l.op(i).nops();
+ size_t rows = l.nops(), cols = 0;
+ for (itr = l.begin(); itr != l.end(); ++itr) {
+ if (!is_a<lst>(*itr))
+ throw (std::invalid_argument("lst_to_matrix: argument must be a list of lists"));
+ if (itr->nops() > cols)
+ cols = itr->nops();
+ }
// Allocate and fill matrix
matrix &M = *new matrix(rows, cols);
M.setflag(status_flags::dynallocated);
- for (i=0; i<rows; i++)
- for (j=0; j<cols; j++)
- if (l.op(i).nops() > j)
- M(i, j) = l.op(i).op(j);
- else
- M(i, j) = _ex0;
+
+ unsigned i;
+ for (itr = l.begin(), i = 0; itr != l.end(); ++itr, ++i) {
+ unsigned j;
+ for (itc = ex_to<lst>(*itr).begin(), j = 0; itc != ex_to<lst>(*itr).end(); ++itc, ++j)
+ M(i, j) = *itc;
+ }
+
return M;
}
ex diag_matrix(const lst & l)
{
+ lst::const_iterator it;
size_t dim = l.nops();
- matrix &m = *new matrix(dim, dim);
- m.setflag(status_flags::dynallocated);
- for (size_t i=0; i<dim; i++)
- m(i, i) = l.op(i);
+ // Allocate and fill matrix
+ matrix &M = *new matrix(dim, dim);
+ M.setflag(status_flags::dynallocated);
- return m;
+ unsigned i;
+ for (it = l.begin(), i = 0; it != l.end(); ++it, ++i)
+ M(i, i) = *it;
+
+ return M;
}
ex unit_matrix(unsigned r, unsigned c)
std::vector<bool> subsed(seq.size(), false);
exvector subsresult(seq.size());
- for (size_t i=0; i<ls.nops(); i++) {
+ lst::const_iterator its, itr;
+ for (its = ls.begin(), itr != lr.begin(); its != ls.end(); ++its, ++itr) {
- if (is_exactly_a<mul>(ls.op(i))) {
+ if (is_exactly_a<mul>(*its)) {
int nummatches = std::numeric_limits<int>::max();
std::vector<bool> currsubsed(seq.size(), false);
bool succeed = true;
lst repls;
- for (size_t j=0; j<ls.op(i).nops(); j++) {
+ for (size_t j=0; j<its->nops(); j++) {
bool found=false;
for (size_t k=0; k<nops(); k++) {
if (currsubsed[k] || subsed[k])
continue;
- if (tryfactsubs(op(k), ls.op(i).op(j), nummatches, repls)) {
+ if (tryfactsubs(op(k), its->op(j), nummatches, repls)) {
currsubsed[k] = true;
found = true;
break;
subsresult[j] = op(j);
else {
foundfirstsubsedfactor = true;
- subsresult[j] = op(j) * power(lr.op(i).subs(ex(repls), subs_options::subs_no_pattern) / ls.op(i).subs(ex(repls), subs_options::subs_no_pattern), nummatches);
+ subsresult[j] = op(j) * power(itr->subs(ex(repls), subs_options::subs_no_pattern) / its->subs(ex(repls), subs_options::subs_no_pattern), nummatches);
}
subsed[j] = true;
}
lst repls;
for (size_t j=0; j<this->nops(); j++) {
- if (!subsed[j] && tryfactsubs(op(j), ls.op(i), nummatches, repls)) {
+ if (!subsed[j] && tryfactsubs(op(j), *its, nummatches, repls)) {
subsed[j] = true;
- subsresult[j] = op(j) * power(lr.op(i).subs(ex(repls), subs_options::subs_no_pattern) / ls.op(i).subs(ex(repls), subs_options::subs_no_pattern), nummatches);
+ subsresult[j] = op(j) * power(itr->subs(ex(repls), subs_options::subs_no_pattern) / its->subs(ex(repls), subs_options::subs_no_pattern), nummatches);
}
}
}
if ((is_exactly_a<mul>(e)&&(e.return_type()!=return_types::commutative))||
(is_exactly_a<ncmul>(e))) {
for (size_t i=0; i<e.nops(); i++)
- append_factors(v,e.op(i));
+ append_factors(v, e.op(i));
} else
v.push_back(e);
}
static ex replace_with_symbol(const ex &e, lst &sym_lst, lst &repl_lst)
{
// Expression already in repl_lst? Then return the assigned symbol
- for (size_t i=0; i<repl_lst.nops(); i++)
- if (repl_lst.op(i).is_equal(e))
- return sym_lst.op(i);
+ lst::const_iterator its, itr;
+ for (its = sym_lst.begin(), itr = repl_lst.begin(); itr != repl_lst.end(); ++its, ++itr)
+ if (itr->is_equal(e))
+ return *its;
// Otherwise create new symbol and add to list, taking care that the
// replacement expression doesn't contain symbols from the sym_lst
static ex replace_with_symbol(const ex &e, lst &repl_lst)
{
// Expression already in repl_lst? Then return the assigned symbol
- for (size_t i=0; i<repl_lst.nops(); i++)
- if (repl_lst.op(i).op(1).is_equal(e))
- return repl_lst.op(i).op(0);
+ for (lst::const_iterator it = repl_lst.begin(); it != repl_lst.end(); ++it)
+ if (it->op(1).is_equal(e))
+ return it->op(0);
// Otherwise create new symbol and add to list, taking care that the
// replacement expression doesn't contain symbols from the sym_lst
return (new power(ebasis, eexponent))->setflag(status_flags::dynallocated);
}
+// from mul.cpp
extern bool tryfactsubs(const ex &, const ex &, int &, lst &);
ex power::subs(const lst & ls, const lst & lr, unsigned options) const
if(!(options & subs_options::subs_algebraic))
return basic::subs(ls, lr, options);
- for (size_t i=0; i<ls.nops(); i++) {
+ lst::const_iterator its, itr;
+ for (its = ls.begin(), itr = lr.begin(); its != ls.end(); ++its, ++itr) {
int nummatches = std::numeric_limits<int>::max();
lst repls;
- if (tryfactsubs(*this, ls.op(i), nummatches, repls))
- return (ex_to<basic>((*this) * power(lr.op(i).subs(ex(repls), subs_options::subs_no_pattern) / ls.op(i).subs(ex(repls), subs_options::subs_no_pattern), nummatches))).basic::subs(ls, lr, options);
+ if (tryfactsubs(*this, *its, nummatches, repls))
+ return (ex_to<basic>((*this) * power(itr->subs(ex(repls), subs_options::subs_no_pattern) / its->subs(ex(repls), subs_options::subs_no_pattern), nummatches))).basic::subs(ls, lr, options);
}
ex result=basic::subs(ls, lr, options);
ex s = (new symbol(n, sym_lst))->setflag(status_flags::dynallocated);
// If symbol is in sym_lst, return the existing symbol
- for (size_t i=0; i<sym_lst.nops(); i++) {
- if (is_a<symbol>(sym_lst.op(i)) && (ex_to<symbol>(sym_lst.op(i)).name == ex_to<symbol>(s).name))
- return sym_lst.op(i);
+ for (lst::const_iterator it = sym_lst.begin(); it != sym_lst.end(); ++it) {
+ if (is_a<symbol>(*it) && (ex_to<symbol>(*it).name == ex_to<symbol>(s).name))
+ return *it;
}
// Otherwise add new symbol to list and return it
/** Symmetrize expression over a list of objects (symbols, indices). */
ex ex::symmetrize(const lst & l) const
{
- exvector v;
- v.reserve(l.nops());
- for (size_t i=0; i<l.nops(); i++)
- v.push_back(l.op(i));
+ exvector v(l.begin(), l.end());
return symm(*this, v.begin(), v.end(), false);
}
/** Antisymmetrize expression over a list of objects (symbols, indices). */
ex ex::antisymmetrize(const lst & l) const
{
- exvector v;
- v.reserve(l.nops());
- for (size_t i=0; i<l.nops(); i++)
- v.push_back(l.op(i));
+ exvector v(l.begin(), l.end());
return symm(*this, v.begin(), v.end(), true);
}
* (symbols, indices). */
ex ex::symmetrize_cyclic(const lst & l) const
{
- exvector v;
- v.reserve(l.nops());
- for (size_t i=0; i<l.nops(); i++)
- v.push_back(l.op(i));
+ exvector v(l.begin(), l.end());
return GiNaC::symmetrize_cyclic(*this, v.begin(), v.end());
}