So I've spent some time trying to get this to work, and am still struggling. Here's what I've tried:
1.) Subclass from `Expr`. Define `__getattr__`, and alias calls over to the base expr. Unfortunately, `__getattr__` is only called for attributes that are missing, and since all the `is_*` attributes already exist, this doesn't actually work. 2.) Subclass from `Symbol`, and store the corresponding routine not in `args`. When creating the symbol, pass in the underlying expr.assumptions0 as assumptions. This is wrong on so many levels. Things that aren't known absolutely beforehand will be completely ignored. Also, while the `routine` itself shouldn't be messed with by things like subs, the calling args should be. So having the `RoutineCallResult` type as an atom isn't correct. It should be closer to a function. 3.) Subclass from `Expr`. After creation, assign the _assumptions dict of the underlying expr to RoutineCallResult._assumptions. Define methods in RoutineCallResult._prop_handler for everything in sympy.core.assumptions._assume_defined that reference the appropriate `is_*` method in the underlying expression. This resulted in really weird things happening when querying assumptions that weren't *known*. All sorts of wrong responses for queries on both the underlying expression and the RoutineCallResult object. Basically broke sympy. 4.) Subclass from `Expr`. Define explicit methods in the RoutineCallResult class for every `is_*` attribute, that call self.expr.is_* and return the result. This *worked*, but is super hackish, and I'd hope there'd be a better way. That's like 30+ methods that I had to manually add, and if SymPy adds more, then I'd have to do the same. There's probably a magic way to go about this, but I'd still prefer something else if possible. Anyone have any thoughts? This is just for scalar return objects, those that are Matrices will have another type that handles the same issue for them. -Jim On Friday, September 19, 2014 1:54:04 PM UTC-5, Aaron Meurer wrote: > > On Fri, Sep 19, 2014 at 1:52 PM, Aaron Meurer <asme...@gmail.com > <javascript:>> wrote: > > On Fri, Sep 19, 2014 at 9:20 AM, James Crist <cris...@umn.edu > <javascript:>> wrote: > >>> it looks like in the first example that the expression is returned > >>> directly while in the second case it is not(?) > >> > >> > >> Ideally, for routines with one expr, `routine` and `routine[0]` will be > >> identical. Not sure if this is possible, and I may decide that's too > much > >> magic. The main purpose behind all this is to make a more composable > way of > >> combining underlying compiled code. > > > > I don't think that's a good idea. To me, Routine((a, b, c), expr) and > > Routine((a, b, c), (expr,)) should be different. > > > >> > >> After playing around for a bit, it looks like this is going to be > >> complicated. Even combinatorial operations (add, mul, etc...) call > methods > >> that refer to the underlying expression being computed. I'm not sure of > the > >> best way to do it, but right now I'm thinking I'll make a list of > operations > >> I want to be aliased to the underlying expression. Then I'll redefine > >> `__getattribute__`, and redirect requests to the expression if they're > in > >> that list. That still may end up being too complicated, and I may have > to > >> rethink my approach. > > > > __getattr__, not __getattribute__. Don't override __getattribute__ > > unless you really know what you are doing. > > > > Something like > > > > def __getattr__(self, attr): > > if attr.startswith('_eval_is_'): > > return getattr(self.expr, attr) > > Oops, there should be a raise AttributeError here. Otherwise all other > attributes will give None. > > Aaron Meurer > > > > > For an applied routine, you probably want to substitute the values in > > first as that can affect the assumptions. > > > > Aaron Meurer > > > >> > >> On Fri, Sep 19, 2014 at 9:00 AM, Chris Smith <smi...@gmail.com > <javascript:>> wrote: > >>> > >>> The assumptions system will try to call `_eval_is_foo` if it exists > for > >>> the object. So if you add definitions for ``_eval_is_integer` to your > >>> Routine object you can return the value of `is_integer` for the return > >>> value. I suspect there will be issues with how you define Routine, > however, > >>> since it looks like in the first example that the expression is > returned > >>> directly while in the second case it is not(?). > >>> > >>> > >>> On Thursday, September 18, 2014 10:32:01 PM UTC-5, James Crist wrote: > >>>> > >>>> I have a new SymPy type that serves to represent a unit of > computation > >>>> (contains an expression/expressions that is/are being computed). I'd > like to > >>>> be able to alias queries on the assumptions of the element to > assumptions of > >>>> the underlying expression it represents. Example: > >>>> > >>>> >>> a, b, c = symbols('a, b, c', integer=True) > >>>> >>> expr = a + b + c > >>>> > >>>> # Create the tree element > >>>> >>> r = Routine((a, b, c), (expr)) > >>>> > >>>> # r now represents a computational routine. > >>>> # We can use this as a function in other expressions. > >>>> >>> new_expr = 1 + 2 + r(a, b, c) > >>>> >>> new_expr > >>>> 1 + 2 + r(a, b, c) > >>>> > >>>> # The following should work > >>>> >>> new_expr.is_integer > >>>> True > >>>> >>> r(1, 2, 3).is_integer > >>>> True > >>>> > >>>> For `Routine` objects with multiple returns, the results are indexed > to > >>>> select the output element: > >>>> > >>>> >>> exprs = (a + b + c, a*b*c + 4.1) > >>>> >>> r = Routine((a, b, c), exprs) > >>>> > >>>> # Use it in a new expression > >>>> >>> (1 + r(1, 2, 3)[0]).is_integer > >>>> True > >>>> >>> (1 + r(1, 2, 3)[1]).is_integer > >>>> False > >>>> > >>>> Any idea how to go about doing this? I have little to no > understanding of > >>>> the assumption system, so before I start digging through the code I > thought > >>>> I'd ask if anyone had thoughts on how to tackle this. The `Routine` > type, > >>>> the `AppliedRoutine` type, and the results/arguments are all done. I > just > >>>> need to figure out (if possible) how I can make this play well with > the > >>>> assumption system. > >>>> > >>>> -Jim > >>> > >>> -- > >>> You received this message because you are subscribed to a topic in the > >>> Google Groups "sympy" group. > >>> To unsubscribe from this topic, visit > >>> https://groups.google.com/d/topic/sympy/XX4K-OhvqTU/unsubscribe. > >>> To unsubscribe from this group and all its topics, send an email to > >>> sympy+un...@googlegroups.com <javascript:>. > >>> To post to this group, send email to sy...@googlegroups.com > <javascript:>. > >>> Visit this group at http://groups.google.com/group/sympy. > >>> To view this discussion on the web visit > >>> > https://groups.google.com/d/msgid/sympy/7c9a540b-7661-40ab-8f99-39ddeef19f9c%40googlegroups.com. > > > >>> > >>> For more options, visit https://groups.google.com/d/optout. > >> > >> > >> -- > >> You received this message because you are subscribed to the Google > Groups > >> "sympy" group. > >> To unsubscribe from this group and stop receiving emails from it, send > an > >> email to sympy+un...@googlegroups.com <javascript:>. > >> To post to this group, send email to sy...@googlegroups.com > <javascript:>. > >> Visit this group at http://groups.google.com/group/sympy. > >> To view this discussion on the web visit > >> > https://groups.google.com/d/msgid/sympy/CAJ2L7mdh7ObsxOv_rmiH8NaF%3Di6kNnoX5jq2f2XLBYs6uzaDQQ%40mail.gmail.com. > > > >> > >> For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "sympy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sympy+unsubscr...@googlegroups.com. To post to this group, send email to sympy@googlegroups.com. Visit this group at http://groups.google.com/group/sympy. To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/c53a49ab-5503-4f61-9d03-3c0a9f3a4f33%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.