Expression defined by a long string

Asked by Yi Jiang

Hi all,

I am trying to generate an Expression from a very long string, something like

for i in range(N):
    Str += "sqrt( (x[0]-%g)*(x[0]-%g) + (x[1]-%g)*(x[1]-%g) )"%(X[i], X[i], Y[i], Y[i])

where N could be 1000 or even bigger. When I compile it by

Exp = Expression(Str)

I still can get a result, but it may take a very long time, say 1 hour. I need this Expression to define a weak form, and to interpolate it into a finite element space, which also takes a lot of time. Is there a more efficient way to define such a function/Expression? Any hint would be highly appreciated.

Question information

Language:
English Edit question
Status:
Solved
For:
DOLFIN Edit question
Assignee:
No assignee Edit question
Solved by:
Yi Jiang
Solved:
Last query:
Last reply:
Revision history for this message
Martin Sandve Alnæs (martinal) said :
#1

Your expression here is not compilable, and the answer would also depend on
what e.g. X,Y are, an how you intend to use the expression afterwards.

Martin
Den 8. juni 2012 03:11 skrev "Yi Jiang" <
<email address hidden>> følgende:

> New question #199782 on DOLFIN:
> https://answers.launchpad.net/dolfin/+question/199782
>
> Hi all,
>
> I am trying to generate an Expression from a very long string, something
> like
>
> for i in range(N):
> Str += "sqrt( (x[0]-%g)*(x[0]-%g) + (x[1]-%g)*(x[1]-%g) )"%(X[i], X[i],
> Y[i], Y[i])
>
> where N could be 1000 or even bigger. When I compile it by
>
> Exp = Expression(Str)
>
> I still can get a result, but it may take a very long time, say 1 hour. I
> need this Expression to define a weak form, and to interpolate it into a
> finite element space, which also takes a lot of time. Is there a more
> efficient way to define such a function/Expression? Any hint would be
> highly appreciated.
>
> --
> You received this question notification because you are a member of
> DOLFIN Team, which is an answer contact for DOLFIN.
>

Revision history for this message
Johan Hake (johan-hake) said :
#2

On 06/08/2012 03:11 AM, Yi Jiang wrote:
> New question #199782 on DOLFIN:
> https://answers.launchpad.net/dolfin/+question/199782
>
> Hi all,
>
> I am trying to generate an Expression from a very long string, something like
>
> for i in range(N):
> Str += "sqrt( (x[0]-%g)*(x[0]-%g) + (x[1]-%g)*(x[1]-%g) )"%(X[i], X[i], Y[i], Y[i])
>
> where N could be 1000 or even bigger. When I compile it by
>
> Exp = Expression(Str)
>
> I still can get a result, but it may take a very long time, say 1 hour. I need this Expression to define a weak form, and to interpolate it into a finite element space, which also takes a lot of time. Is there a more efficient way to define such a function/Expression? Any hint would be highly appreciated.
>

This sounds like abuse of the Expression interface :) That line will be
put on a single line of code in C++ and they compiler prob have a hard
time getting this efficient.

You can try to define it using UFL Expression. A not very well know
feature of FEniCS. Something like:

   x = triangle.x
   expr = reduce(lambda x, y : x + y, [sqrt((x[0]-X[ind])*(x[0]-X[ind])
+ (x[1]-Y[ind])*(x[1]-Y[ind])) for ind in range(N)], 0)

Not sure this will be faster, and I am not sure the form compiler like
such a large expression.

The last resort is to split the evaluation of the Expression string into
several lines, one for each iteration maybe? Then you need to construct
the whole derived C++ Expression class as a string and pass to
Expression. See docstring of Expression for more info.

Johan

Revision history for this message
Anders Logg (logg) said :
#3

On Fri, Jun 08, 2012 at 06:11:08AM -0000, Johan Hake wrote:
> Question #199782 on DOLFIN changed:
> https://answers.launchpad.net/dolfin/+question/199782
>
> Johan Hake proposed the following answer:
> On 06/08/2012 03:11 AM, Yi Jiang wrote:
> > New question #199782 on DOLFIN:
> > https://answers.launchpad.net/dolfin/+question/199782
> >
> > Hi all,
> >
> > I am trying to generate an Expression from a very long string, something like
> >
> > for i in range(N):
> > Str += "sqrt( (x[0]-%g)*(x[0]-%g) + (x[1]-%g)*(x[1]-%g) )"%(X[i], X[i], Y[i], Y[i])
> >
> > where N could be 1000 or even bigger. When I compile it by
> >
> > Exp = Expression(Str)
> >
> > I still can get a result, but it may take a very long time, say 1 hour. I need this Expression to define a weak form, and to interpolate it into a finite element space, which also takes a lot of time. Is there a more efficient way to define such a function/Expression? Any hint would be highly appreciated.
> >
>
>
> This sounds like abuse of the Expression interface :) That line will be
> put on a single line of code in C++ and they compiler prob have a hard
> time getting this efficient.
>
> You can try to define it using UFL Expression. A not very well know
> feature of FEniCS. Something like:
>
> x = triangle.x
> expr = reduce(lambda x, y : x + y, [sqrt((x[0]-X[ind])*(x[0]-X[ind])
> + (x[1]-Y[ind])*(x[1]-Y[ind])) for ind in range(N)], 0)
>
> Not sure this will be faster, and I am not sure the form compiler like
> such a large expression.
>
> The last resort is to split the evaluation of the Expression string into
> several lines, one for each iteration maybe? Then you need to construct
> the whole derived C++ Expression class as a string and pass to
> Expression. See docstring of Expression for more info.

Looks like it should be possible to express the computation as a C++
loop, rather than completely unrolling everything into one long line.

Express it like a subclass of the C++ Expression class and pass it
like a string to the Python Expression class with the cppcode argument.

--
Anders

Revision history for this message
Joachim Haga (jobh) said :
#4

Just to cover the final issues:

> for i in range(N):
> Str += "sqrt( (x[0]-%g)*(x[0]-%g) + (x[1]-%g)*(x[1]-%g) )"%(X[i], X[i],
Y[i], Y[i])

This loop has quadratic time complexity, when N is large you should make a
list of strings and do a final join instead.

Furthermore, the string will have to be rebuild and recompiled every time X
or Y change. You may want to make those coordinates into arguments to the
expression somehow (unless they are fixed).

-j.

On 8 June 2012 03:11, Yi Jiang <email address hidden> wrote:

> New question #199782 on DOLFIN:
> https://answers.launchpad.net/dolfin/+question/199782
>
> Hi all,
>
> I am trying to generate an Expression from a very long string, something
> like
>
> for i in range(N):
> Str += "sqrt( (x[0]-%g)*(x[0]-%g) + (x[1]-%g)*(x[1]-%g) )"%(X[i], X[i],
> Y[i], Y[i])
>
> where N could be 1000 or even bigger. When I compile it by
>
> Exp = Expression(Str)
>
> I still can get a result, but it may take a very long time, say 1 hour. I
> need this Expression to define a weak form, and to interpolate it into a
> finite element space, which also takes a lot of time. Is there a more
> efficient way to define such a function/Expression? Any hint would be
> highly appreciated.
>
> --
> You received this question notification because you are a member of
> DOLFIN Team, which is an answer contact for DOLFIN.
>

Revision history for this message
Yi Jiang (yijiang) said :
#5

Thank you guys for help, I will do some tests and give my feedback later.

Revision history for this message
Yi Jiang (yijiang) said :
#6

I just tested the subclassing case, it looks working very well, following are my code to get such an instance:

import numpy as np
# A is a 2D numpy array

class LongExp(Expression):
    def __init__(self, A):
        self._A = A
    def eval(self, values, x):
        val = 0.0
        for i in self._A:
            val += np.sqrt( (x[0]-i[0])**2+(x[1]-i[1])**2 )
        values[0] = val

longexp = LongExp(A=A)

Thank you guys a lot, I guess this problem has been solved.

Revision history for this message
Johan Hake (johan-hake) said :
#7

On 06/08/2012 07:20 PM, Yi Jiang wrote:
> Question #199782 on DOLFIN changed:
> https://answers.launchpad.net/dolfin/+question/199782
>
> Status: Answered => Solved
>
> Yi Jiang confirmed that the question is solved:
> I just tested the subclassing case, it looks working very well,
> following are my code to get such an instance:
>
> import numpy as np
> # A is a 2D numpy array
>
> class LongExp(Expression):
> def __init__(self, A):
> self._A = A
> def eval(self, values, x):
> val = 0.0
> for i in self._A:
> val += np.sqrt( (x[0]-i[0])**2+(x[1]-i[1])**2 )
> values[0] = val
>
> longexp = LongExp(A=A)
>
> Thank you guys a lot, I guess this problem has been solved.
>

Great!

However, what I think both me and Anders actually suggested was to
create a string where you subclass a a whole C++ Expression. This should
be much faster than doing it in Python.

 >>> help Expression

will give you some hints of how to do that.

Johan