Finally figured this all out (at least for everything I've tried it works). Option #3 described above was almost correct. Instead of setting the `_assumptions` attributes equal between the alias and the expression though, the `_assumptions` attribute should be cleared for the alias. If it has anything in it, the `prop_handler` won't be used, and it will just invoke the methods of the alias instead. Which is not what I want. Further, there was some funny behavior with using `lambda` functions to do the aliasing. It may be (probably was) coder error, but works now using full methods instead. That's what I get for trying to do things the easy way :/
Anyway, problem is *tentatively* solved. Still need to do the same for `MatrixExpr` types, this only works for `Expr`. Can't imagine it will be that different though. - Jim On Thursday, September 25, 2014 12:07:51 PM UTC-5, James Crist wrote: > > 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> wrote: >> > On Fri, Sep 19, 2014 at 9:20 AM, James Crist <cris...@umn.edu> 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> >> 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. >> >>> To post to this group, send email to sy...@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/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. >> >> To post to this group, send email to sy...@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/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/9d3a52a2-b53c-4c32-a0e1-0f1a2c94f146%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.