Next: , Previous: Fundamental containers, Up: Basic concepts


4.9 Lists of expressions

The GiNaC class lst serves for holding a list of arbitrary expressions. They are not as ubiquitous as in many other computer algebra packages, but are sometimes used to supply a variable number of arguments of the same type to GiNaC methods such as subs() and some matrix constructors, so you should have a basic understanding of them.

Lists can be constructed by assigning a comma-separated sequence of expressions:

     {
         symbol x("x"), y("y");
         lst l;
         l = x, 2, y, x+y;
         // now, l is a list holding the expressions 'x', '2', 'y', and 'x+y',
         // in that order
         ...

There are also constructors that allow direct creation of lists of up to 16 expressions, which is often more convenient but slightly less efficient:

         ...
         // This produces the same list 'l' as above:
         // lst l(x, 2, y, x+y);
         // lst l = lst(x, 2, y, x+y);
         ...

Use the nops() method to determine the size (number of expressions) of a list and the op() method or the [] operator to access individual elements:

         ...
         cout << l.nops() << endl;                // prints '4'
         cout << l.op(2) << " " << l[0] << endl;  // prints 'y x'
         ...

As with the standard list<T> container, accessing random elements of a lst is generally an operation of order O(N). Faster read-only sequential access to the elements of a list is possible with the iterator types provided by the lst class:

     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;

For example, to print the elements of a list individually you can use:

         ...
         // O(N)
         for (lst::const_iterator i = l.begin(); i != l.end(); ++i)
             cout << *i << endl;
         ...

which is one order faster than

         ...
         // O(N^2)
         for (size_t i = 0; i < l.nops(); ++i)
             cout << l.op(i) << endl;
         ...

These iterators also allow you to use some of the algorithms provided by the C++ standard library:

         ...
         // print the elements of the list (requires #include <iterator>)
         std::copy(l.begin(), l.end(), ostream_iterator<ex>(cout, "\n"));
     
         // sum up the elements of the list (requires #include <numeric>)
         ex sum = std::accumulate(l.begin(), l.end(), ex(0));
         cout << sum << endl;  // prints '2+2*x+2*y'
         ...

lst is one of the few GiNaC classes that allow in-place modifications (the only other one is matrix). You can modify single elements:

         ...
         l[1] = 42;       // l is now {x, 42, y, x+y}
         l.let_op(1) = 7; // l is now {x, 7, y, x+y}
         ...

You can append or prepend an expression to a list with the append() and prepend() methods:

         ...
         l.append(4*x);   // l is now {x, 7, y, x+y, 4*x}
         l.prepend(0);    // l is now {0, x, 7, y, x+y, 4*x}
         ...

You can remove the first or last element of a list with remove_first() and remove_last():

         ...
         l.remove_first();   // l is now {x, 7, y, x+y, 4*x}
         l.remove_last();    // l is now {x, 7, y, x+y}
         ...

You can remove all the elements of a list with remove_all():

         ...
         l.remove_all();     // l is now empty
         ...

You can bring the elements of a list into a canonical order with sort():

         ...
         lst l1, l2;
         l1 = x, 2, y, x+y;
         l2 = 2, x+y, x, y;
         l1.sort();
         l2.sort();
         // l1 and l2 are now equal
         ...

Finally, you can remove all but the first element of consecutive groups of elements with unique():

         ...
         lst l3;
         l3 = x, 2, 2, 2, y, x+y, y+x;
         l3.unique();        // l3 is now {x, 2, y, x+y}
     }