Differences between revisions 1 and 2
Revision 1 as of 2010-07-02 16:29:16
Size: 756
Editor: RyanHinton
Comment: preliminary save, work in progress
Revision 2 as of 2010-07-02 17:12:26
Size: 4704
Editor: RyanHinton
Comment: complete initial revision
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
This page discusses an interface for implementing indexed GiNaC expressions in Sage/Pynac.

== Background ==
Line 7: Line 10:
My best idea is to use Python's indexing notation and hook ``__getitem__()`` for Pynac expressions. (Is this already done?) So the following GiNaC C++ and Sage Python code should do essentially the same thing. == General idea ==
My best idea is to use Python's indexing notation and hook {{{__getitem__()}}} for Pynac expressions. (Is this already done?) So the following GiNaC C++ and Sage Python code should do essentially the same thing.
Line 10: Line 14:
idx i_idx(i_sym, 3), j_idx(j_sym, 3); idx i_idx(i_sym, 3), j_idx(j_sym, 4);
Line 16: Line 20:
s = A[i,j].sum(3,3) s = A[i,j].sum(3,4)
Line 18: Line 22:

== Detailed ideas ==
=== Index dimensions ===
I like the {{{A[...]}}} indexing syntax, but the dimensions are missing. There are three obvious approaches for specifying dimensions.
* Cram them into the indexing syntax, e.g. {{{A[(i,3), (j,4)]}}}. RWH does *not* like this option.
* Specify the dimensions in a separate method call, e.g. {{{A[i,j].dimension(3,4)}}}. The final result should be the same as a GiNaC indexed expression.
* Specify them when they are used, e.g. {{{A[i,j].sum(3,4)}}}.
RWH does *not* like cramming the dimensions into the indexing expression. Instead, specifying the dimensions when they are used seems most natural to RWH, but he has a shallow understanding and no experience with the GiNaC approach.

In fact, the method call and specify-on-use approaches can coexist. Since GiNaC requires the dimension to be specified when the indexed expression is created, both cases require defining *implicit* dimensions. So {{{A[i,j]}}} might translate to the following C++ code.
{{{
symbol i_dim("__stmt627_A_dim_i"), j_dim("__stmt627_A_dim_j"); // unique symbol names
idx i_idx(i_sym, i_dim), j_idx(j_sym, j_dim);
return indexed(A, i_idx, j_idx);
}}}
Later, when we know the desired dimensions (e.g. in the {{{dimension()}}} or {{{sum()}}} method), we can substitute the actual dimensions. We can use the indexed expression whether or not the indixes are explicitly dimensioned. For example, {{{A[i,j].sum()}}} would return the 2-D sum over the implicit dimensions. We could even give the implicit dimensions nice LaTeX names, e.g. the GiNaC equivalent of the Sage pseudocode
{{{
var('__stmt627_A_dim_i', latex_name='N_{%s,%s}'%(A._latex_(), i_sym._latex_()))
}}}

=== Specifying index dimensions ===
There are several options for the syntax specifying the index dimensions.
{{{
A[i,j].dimension(3, 4}) # positional syntax is simple, but not always clear
A[i,j].dimension({i:3, j:4}) # hash syntax allows specifying the index
        # expression to be dimensioned
A[i,j].dimension(i=3, j=4) # keyword syntax is similar, but may have problems
        # with general expression indexes
A[i,j].dimension(i==3, j==4) # relation syntax is similar to substitution
        # syntax; perhaps confusingly, this would sum ``i`` over 0,1,2 and
        # *not* 3 -- so i==3 is the first value that is *not* included in the
        # sum
A[i,j].dimension(0<=i<3, 0<=j<4) # more complex relation syntax shows exactly
        # which values are included in the sum, but not sure if GiNaC can
        # handle general dimension ranges
}}}
We should probably include the positional syntax at a minimum. It will do just fine for only one index, and will probably be easier when trying to specifying the dimensions of a non-trivial index expression. RWH's next favorite option is the hash syntax. In all of the non-positional cases there will be issues of figuring out which string/expression matches which index. RWH assumes facilities exist so this will not be a significant obstacle.

== Operations ==
Indexed expressions should already support addition, multiplication, etc. with other expressions. Below are ideas for operations specific to indexed expressions.
* Of course, we should define {{{sum}} and {{{prod}}} methods to form sums and products, respectively.
* (Other operations that use indices?)
* We could use indexed expressions to create vectors and matrices. This would probably require new vector and matrix classes to support symbolic dimensions.
* We could use indexed expressions to create polynomials (over {{{SR}}}).
* (Other constructions that use indices?)
* By allowing an infinite dimension, we can take limits of sequences, (sums of) series, etc. Sequences of functions may fit in the same framework.

This page discusses an interface for implementing indexed GiNaC expressions in Sage/Pynac.

Background

See the thread

http://groups.google.com/group/sage-devel/browse_thread/thread/69ab50fe11672111

for the impetus of this page. I will repeat here that the original author of this page (Ryan Hinton) is *not* an expert at Sage or GiNaC. Consequently, there are likely syntactic and semantic errors below. Feel free to edit, comment, or discuss any of my mistakes.

General idea

My best idea is to use Python's indexing notation and hook __getitem__() for Pynac expressions. (Is this already done?) So the following GiNaC C++ and Sage Python code should do essentially the same thing.

symbol A("A"), i_sym("i"), j_sym("j");
idx i_idx(i_sym, 3), j_idx(j_sym, 4);
ex s = indexed(A, i, j).sum();

vs.

var('A i j')
s = A[i,j].sum(3,4)

Detailed ideas

Index dimensions

I like the A[...] indexing syntax, but the dimensions are missing. There are three obvious approaches for specifying dimensions. * Cram them into the indexing syntax, e.g. A[(i,3), (j,4)]. RWH does *not* like this option. * Specify the dimensions in a separate method call, e.g. A[i,j].dimension(3,4). The final result should be the same as a GiNaC indexed expression. * Specify them when they are used, e.g. A[i,j].sum(3,4). RWH does *not* like cramming the dimensions into the indexing expression. Instead, specifying the dimensions when they are used seems most natural to RWH, but he has a shallow understanding and no experience with the GiNaC approach.

In fact, the method call and specify-on-use approaches can coexist. Since GiNaC requires the dimension to be specified when the indexed expression is created, both cases require defining *implicit* dimensions. So A[i,j] might translate to the following C++ code.

symbol i_dim("__stmt627_A_dim_i"), j_dim("__stmt627_A_dim_j");  // unique symbol names
idx i_idx(i_sym, i_dim), j_idx(j_sym, j_dim);
return indexed(A, i_idx, j_idx);

Later, when we know the desired dimensions (e.g. in the dimension() or sum() method), we can substitute the actual dimensions. We can use the indexed expression whether or not the indixes are explicitly dimensioned. For example, A[i,j].sum() would return the 2-D sum over the implicit dimensions. We could even give the implicit dimensions nice LaTeX names, e.g. the GiNaC equivalent of the Sage pseudocode

var('__stmt627_A_dim_i', latex_name='N_{%s,%s}'%(A._latex_(), i_sym._latex_()))

Specifying index dimensions

There are several options for the syntax specifying the index dimensions.

A[i,j].dimension(3, 4})  # positional syntax is simple, but not always clear
A[i,j].dimension({i:3, j:4})  # hash syntax allows specifying the index 
        # expression to be dimensioned
A[i,j].dimension(i=3, j=4)  # keyword syntax is similar, but may have problems 
        # with general expression indexes
A[i,j].dimension(i==3, j==4)  # relation syntax is similar to substitution 
        # syntax; perhaps confusingly, this would sum ``i`` over 0,1,2 and 
        # *not* 3 -- so i==3 is the first value that is *not* included in the 
        # sum
A[i,j].dimension(0<=i<3, 0<=j<4)  # more complex relation syntax shows exactly 
        # which values are included in the sum, but not sure if GiNaC can 
        # handle general dimension ranges

We should probably include the positional syntax at a minimum. It will do just fine for only one index, and will probably be easier when trying to specifying the dimensions of a non-trivial index expression. RWH's next favorite option is the hash syntax. In all of the non-positional cases there will be issues of figuring out which string/expression matches which index. RWH assumes facilities exist so this will not be a significant obstacle.

Operations

Indexed expressions should already support addition, multiplication, etc. with other expressions. Below are ideas for operations specific to indexed expressions. * Of course, we should define sum}} and {{{prod methods to form sums and products, respectively. * (Other operations that use indices?) * We could use indexed expressions to create vectors and matrices. This would probably require new vector and matrix classes to support symbolic dimensions. * We could use indexed expressions to create polynomials (over SR). * (Other constructions that use indices?) * By allowing an infinite dimension, we can take limits of sequences, (sums of) series, etc. Sequences of functions may fit in the same framework.

symbolics/Indexed expressions (last edited 2010-07-02 17:26:00 by RyanHinton)