On 10/22/2014 01:22 PM, smohamm...@gmail.com wrote:
> Hello to every one,
> I am a *primitive *sage user and I want to produce a function of n
> variables (|x[1],x[2],...,x[n]|), in nested 'for' loops. I've searched
> in sage's documentation, but I have still 2 problems:
> 1. How to define a list of variables, such that I can use its items, as
> independent variables, in loops. The loops are needed because the
> function is made up of sums of multiplications of clauses of these
> variables?

This isn't built in, but you can use the attached file to do it. There
are detailed examples in the docstring, but basically you load the file
and then create a SymbolSequence object with the name you want:

  sage: load('symbol_sequence.py')
  sage: x = SymbolSequence('x')
  sage: x[0]
  x_0
  sage: x[1]
  x_1
  sage: x[10]
  x_10

Multiple subscripts and slices also work the way you'd want them to (I
hope).


> 2. How to simplify the result of loops according to some extra
> conditions, such as |x[i]^2==1| ?

We have the "assume" function, which can do things like,

  sage: assume(x^2 == 1)

but I don't want to get your hopes up. Even with that assumption, the
expression x^2 won't simplify:

  sage: (x^2).simplify_full()
  x^2

For other equations, it might help though.

-- 
You received this message because you are subscribed to the Google Groups 
"sage-support" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-support+unsubscr...@googlegroups.com.
To post to this group, send email to sage-support@googlegroups.com.
Visit this group at http://groups.google.com/group/sage-support.
For more options, visit https://groups.google.com/d/optout.
from sage.all import *

class SymbolSequence:
    """
    An iterable object which acts like a sequence of symbolic
    expressions (variables).

    INPUT:

      - ``name`` -- The sequence name. For example, if you name the
        sequence `x`, the variables will be called `x_0`, `x_1`,...

      - ``latex_name`` -- An optional latex expression (string) to
        use instead of `name` when converting the symbols to latex.

      - ``domain`` -- A string representing the domain of the symbol,
        either 'real', 'complex', or 'positive'.

    OUTPUT:

    An iterable object containing symbolic expressions.

    EXAMPLES:

    The simplest use case::

        sage: a = SymbolSequence('a')
        sage: a[0]
        a_0
        sage: a[1]
        a_1

    Create polynomials with symbolic coefficients of arbitrary
    degree::

        sage: a = SymbolSequence('a')
        sage: p = sum([ a[i]*x^i for i in range(0,5)])
        sage: p
        a_4*x^4 + a_3*x^3 + a_2*x^2 + a_1*x + a_0

    Using a different latex name since 'lambda' is reserved::

        sage: l = SymbolSequence('l', '\lambda')
        sage: l[0]
        l_0
        sage: latex(l[0])
        \lambda_{0}

    Using multiple indices::

        sage: a = SymbolSequence('a')
        sage: a[0,1,2]
        a_0_1_2
        sage: latex(a[0,1,2])
        a_{0}_{1}_{2}
        sage: [ a[i,j] for i in range(0,2) for j in range(0,2) ]
        [a_0_0, a_0_1, a_1_0, a_1_1]

    You can pass slices instead of integers to obtain a list of
    symbols::

        sage: a = SymbolSequence('a')
        sage: a[5:7]
        [a_5, a_6]

    This even works for the second, third, etc. indices::

        sage: a = SymbolSequence('a')
        sage: a[0:2, 0:2]
        [a_0_0, a_0_1, a_1_0, a_1_1]

    TESTS:

    We shouldn't overwrite variables in the global namespace::

        sage: a = SymbolSequence('a')
        sage: a_0 = 4
        sage: a[0]
        a_0
        sage: a_0
        4

    The symbol at a given index should always be the same, even when
    the symbols themselves are unnamed. We store the string
    representation and compare because the output is unpredictable::

        sage: a = SymbolSequence()
        sage: a0str = str(a[0])
        sage: str(a[0]) == a0str
        True

    Slices and single indices work when combined::

        sage: a = SymbolSequence('a')
        sage: a[3, 0:2]
        [a_3_0, a_3_1]
        sage: a[0:2, 3]
        [a_0_3, a_1_3]

    """

    def __init__(self, name=None, latex_name=None, domain=None):
        # We store a dict of already-created symbols so that we don't
        # recreate a symbol which already exists. This is especially
        # helpful when using unnamed variables, if you want e.g. a[0]
        # to return the same variable each time.
        self._symbols = {}

        self._name = name
        self._latex_name = latex_name
        self._domain = domain


    def _create_symbol_(self, subscript):
        """
        Return a symbol with the given subscript. Creates the
        appropriate name and latex_name before delegating to
        SR.symbol().

        EXAMPLES::

            sage: a = SymbolSequence('a', 'alpha', 'real')
            sage: a_1 = a._create_symbol_(1)
            sage: a_1
            a_1
            sage: latex(a_1)
            alpha_{1}

        """
        # Allow creating unnamed symbols, for consistency with
        # SR.symbol().
        name = None
        if self._name is not None:
            name = '%s_%d' % (self._name, subscript)

        latex_name = None
        if self._latex_name is not None:
            latex_name = r'%s_{%d}' % (self._latex_name, subscript)

        return SR.symbol(name, latex_name, self._domain)


    def _flatten_list_(self, l):
        """
        Recursively flatten the given list, allowing for some elements
        to be non-iterable. This is slow, but also works, which is
        more than can be said about some of the snappier solutions of
        lore.

        EXAMPLES::

            sage: a = SymbolSequence('a')
            sage: a._flatten_list_([1,2,3])
            [1, 2, 3]
            sage: a._flatten_list_([1,[2,3]])
            [1, 2, 3]
            sage: a._flatten_list_([1,[2,[3]]])
            [1, 2, 3]
            sage: a._flatten_list_([[[[[1,[2,[3]]]]]]])
            [1, 2, 3]

        """
        result = []

        for item in l:
            if isinstance(item, list):
                result += self._flatten_list_(item)
            else:
                result += [item]

        return result


    def __getitem__(self, key):
        """
        This handles individual integer arguments, slices, and
        tuples. It just hands off the real work to
        self._subscript_foo_().

        EXAMPLES:

        An integer argument::

            sage: a = SymbolSequence('a')
            sage: a.__getitem__(1)
            a_1

        A tuple argument::

            sage: a = SymbolSequence('a')
            sage: a.__getitem__((1,2))
            a_1_2

        A slice argument::

            sage: a = SymbolSequence('a')
            sage: a.__getitem__(slice(1,4))
            [a_1, a_2, a_3]

        """
        if isinstance(key, tuple):
            return self._subscript_tuple_(key)

        if isinstance(key, slice):
            return self._subscript_slice_(key)

        # This is the most common case so it would make sense to have
        # this test first. But there are too many different "integer"
        # classes that you have to check for.
        return self._subscript_integer_(key)


    def _subscript_integer_(self, n):
        """
        The subscript is a single integer, or something that acts like
        one.

        EXAMPLES::

            sage: a = SymbolSequence('a')
            sage: a._subscript_integer_(123)
            a_123

        """
        if n < 0:
            # Cowardly refuse to create a variable named "a-1".
            raise IndexError('Indices must be nonnegative')

        try:
            return self._symbols[n]
        except KeyError:
            self._symbols[n] = self._create_symbol_(n)
            return self._symbols[n]


    def _subscript_slice_(self, s):
        """
        We were given a slice. Clean up some of its properties
        first. The start/step are default for lists. We make
        copies of these because they're read-only.

        EXAMPLES::

            sage: a = SymbolSequence('a')
            sage: a._subscript_slice_(slice(1,3))
            [a_1, a_2]

        """
        (start, step) = (s.start, s.step)
        if start is None:
            start = 0
        if s.stop is None:
            # Would otherwise loop forever since our "length" is
            # undefined.
            raise ValueError('You must supply an terminal index')
        if step is None:
            step = 1

        # If the user asks for a slice, we'll be returning a list
        # of symbols.
        return [ self._subscript_integer_(idx)
                 for idx in range(start, s.stop, step) ]



    def _subscript_tuple_(self, args):
        """
        When we have more than one level of subscripts, we pick off
        the first one and generate the rest recursively.

        EXAMPLES:

        A simple two-tuple::

            sage: a = SymbolSequence('a')
            sage: a._subscript_tuple_((1,8))
            a_1_8

        Nested tuples::

            sage: a._subscript_tuple_(( (1,2), (3,(4,5,6)) ))
            a_1_2_3_4_5_6

        """

        # We never call this method without an argument.
        key = args[0]
        args = args[1:] # Peel off the first arg, which we've called 'key'

        # We don't know the type of 'key', but __getitem__ will figure
        # it out and dispatch properly.
        v = self[key]
        if len(args) == 0:
            # There was only one element left in the tuple.
            return v

        # At this point, we know we were given at least a two-tuple.
        # The symbols corresponding to the first entry are already
        # computed, in 'v'. Here we recursively compute the symbols
        # corresponding to the second coordinate, with the first
        # coordinate(s) fixed.
        if isinstance(key, slice):
            ss = [ SymbolSequence(w._repr_(), w._latex_(), self._domain)
                   for w in v ]

            # This might be nested...
            maybe_nested_list = [ s._subscript_tuple_(args) for s in ss ]
            return self._flatten_list_(maybe_nested_list)

        else:
            # If it's not a slice, it's an integer.
            ss = SymbolSequence(v._repr_(), v._latex_(), self._domain)
            return ss._subscript_tuple_(args)

Reply via email to