On Oct 22, 2012, at 9:32 PM, Robert Bradshaw wrote:
> On Mon, Oct 22, 2012 at 9:18 AM, Jon Guyer <
gu...@nist.gov> wrote:
>> I am unable to write an iteration loop in
>> Cython because I cannot initialize any of these iterators on the stack.
>
>> but that doesn't address the fact that the the equivalent initialization is legal C++.
>
> The problem with the one-line solution is that it requires careful
> control over the scope in which variables are declared vs.
> initialized. Every bracket in C++ defines a new scope, which is not
> the case in Python/Cython, hence the restriction (e.g. variables
> assigned in a loop body can be used outside of it). Though it's simple
> to make it work by manually tweaking the C in this case, the generic
> case is much more complicated (and potentially ends up leaking the
> scope constraints to the Python level).
Thanks very much for your thorough explanation. I had not appreciated the broader issue you were tangling with. I guess my inclination would be to generate legal C++ code, limiting the scope of the variables from what Python would otherwise allow. This is a hybrid language after all and some constraints are inevitable. You see the implications of these choices much more clearly than I do, though.
> Of course, this is a bug that should be fixed, but in the meantime
> you'll have to allocate this as a pointer (which is what we'd have to
> do under the hood to support this).
OK, I had tried that, but wasn't getting it right. libMesh only returns its iterators by value and I was having trouble figuring out how to get a pointer out of that. I had tried to do things like
{{{
cdef A *a_ptr = &self.thisptr.my_A()
}}}
and
{{{
cdef A *a_ptr
deref(a_ptr) = self.thisptr.my_A()
}}}
neither of which I really expected to work, and which I knew were dangerous constructs in C++ if they did.
I now see that
{{{
cdef A *a_ptr = new A(self.thisptr.my_A())
}}}
seems to do the trick.
Unfortunately, I'm then stymied by the "'Mesh' is not a cimported module" issue below when I try to do it for real.
> BTW, in Cython 0.17 you can iterate over C++ iterators using "for x in
> myInstance: ..." which is much cleaner.
I agree that that's a much nicer, more Pythonic way to do it. Unfortunately, the libMesh API doesn't support it.
I initially tried
{{{
for it in self.thisptr.active_nodes_begin():
}}}
but that raises
{{{
libMeshMesh.pyx:121:18: missing begin() on node_iterator
}}}
I then realized that you said myInstance and not myIterator, but the problem is that a libMesh Mesh has multiple iterators over both its nodes and its elements:
{{{
virtual element_iterator elements_begin () = 0;
virtual element_iterator elements_end () = 0;
virtual element_iterator active_elements_begin () = 0;
virtual element_iterator active_elements_end () = 0;
virtual element_iterator ancestor_elements_begin () = 0;
virtual element_iterator ancestor_elements_end () = 0;
virtual element_iterator subactive_elements_begin () = 0;
virtual element_iterator subactive_elements_end () = 0;
virtual element_iterator not_active_elements_begin () = 0;
virtual element_iterator not_active_elements_end () = 0;
virtual element_iterator not_ancestor_elements_begin () = 0;
virtual element_iterator not_ancestor_elements_end () = 0;
:
:
virtual node_iterator nodes_begin () = 0;
virtual node_iterator nodes_end () = 0;
virtual node_iterator active_nodes_begin () = 0;
virtual node_iterator active_nodes_end () = 0;
virtual node_iterator local_nodes_begin () = 0;
virtual node_iterator local_nodes_end () = 0;
virtual node_iterator pid_nodes_begin (const unsigned int proc_id) = 0;
virtual node_iterator pid_nodes_end (const unsigned int proc_id) = 0;
}}}
A Mesh has no explicit begin() and end() and they would be completely ambiguous if it did. I realize that the semantics might not be quite right, but for this use case, I'd really like to be able to write:
{{{
for it in self.thisptr.active_nodes_begin():
}}}
>> More significantly, in the actual code, where `node_iterator` is declared as
>> a subclass of `Mesh`
>> {{{
>> #!python
>> cdef Mesh.node_iterator it = self.thisptr.active_nodes_begin()
>> }}}
>> results in
>> {{{
>> libMeshMesh.pyx:117:13: 'Mesh' is not a cimported module
>> }}}
>
> How did you declare Mesh?
{{{
cdef extern from "node.h" namespace "libMesh":
cdef cppclass Node:
Node()
cdef extern from "mesh.h" namespace "libMesh":
cdef cppclass Mesh:
cppclass node_iterator:
Node* operator*()
node_iterator operator++()
bint operator==(node_iterator)
bint operator!=(node_iterator)
Mesh(unsigned int dim)
node_iterator active_nodes_begin()
node_iterator active_nodes_end()
}}}