New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ccode: Add capability to _print_Indexed() to use user-defined strided schemes and offsets #12490
Conversation
Values of 0 & 1 for EDIT: the default should then be |
@bjodah Sorry for the late reply. Last week was quite hectic. |
@ArifAhmed1995 no worries. You don't need to worry about
or more general:
|
7002e30
to
dd04a7b
Compare
@bjodah Can you please review again ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is starting to look really good. I left some minor comments.
sympy/printing/ccode.py
Outdated
if offset is None: | ||
offset = "" | ||
return "%s[%s]" % (self._print(expr.base.label), | ||
str(sum([x[0]*x[1] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of str
you can use self._print
here too (it is most probably safe to use str
, but better safe than sorry if the user calculates indices in some fancy way)
sympy/printing/ccode.py
Outdated
|
||
if offset is None: | ||
offset = "" | ||
return "%s[%s]" % (self._print(expr.base.label), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of having a separate return statement we can calculate the missing strides
here and let the method use the same logic further down as when strides is given explicitly.
sympy/printing/ccode.py
Outdated
self._print(elem) + str(offset)) | ||
elif isinstance(strides, tuple): | ||
if offset is None: | ||
offset = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can let offset be 0 by default and add it to the sum, i.e. sum(...) + offset
@bjodah I've made the required changes. |
Oh, I was just suggesting to abolish |
I agree that What I do like about |
I was actually thinking about it. They could be either stored in Take into account that If you give a symbolic index to an |
@Upabjojr I didn't know that Strides and offset are really specific to code-generation so perhaps the functionality should reside in a |
Printing code of an I think that Maybe just a global attribute dictionary? I don't like having so many specific arguments in the single classes. Also, I wouldn't create a class and inheritance-of-such-class just for these two parameters. All other CAS's have attribute support for their objects, SymPy does not. |
@Upabjojr for high performance code strides are used all over the place. Mainly for one of two reasons:
Attribute support for objects would definitely be one way to solve these kinds of problems. |
+1, what about a global attribute dictionary in |
In that case I would actually like to see some mechanism to set attributes already during initialization. e.g. intercepting an "attributes" kwarg from assumptions:
or
This would be major change so perhaps we should open a separate issue for it and discuss it on the mailing list? |
Yes, I'd suggest the forum. |
Just wait. Let's ask on the mailing list about attributes. |
https://groups.google.com/forum/#!topic/sympy/VVaDc-yFtlQ I asked the opinion on introducing attributes. |
Also, I have a recurrent thought about experimenting on |
What about just having some static dict in Something like: class Indexed(...):
...
_instance_offsets = {}
_instance_strided = {}
@property
def offset(self):
return self._instance_offsets.get(self, 0)
...
def set_offset(self, offset):
self._instance_offsets[self] = offset So we can set the value after creation without clumbering the arguments too much. |
759d473
to
8f1e5f2
Compare
I fail to see why this is better than what we had from the start (simple attributes), @Upabjojr could you explain the benefits? EDIT: @ArifAhmed1995: 8f1e5f2 is not quite what Francesco meant, but I think you can wait with adding changes until we agree on a good way forward. EDIT2: @Upabjojr I now see how this would allow us to add this information to
Adding strides to |
We don't put those arguments in the defining arguments of the object, which is good because they are not defining arguments. Plus, we solve the issue of having
Yes, I meant for the static dictionaries to be in Though, I am favorable to restore the |
@Upabjojr I disagree. Adding this to |
I mean, add strides to IndexedBase but store the strides info in Indexed. My previous code snippet is a bad example. The strides and offset properties in Indexed should not interact with IndexedBase but find the info in Indexed. |
@Upabjojr oh, I see. Yes that would work. Thanks for explaining. @ArifAhmed1995 do you follow? |
In e79cc4b expressions may change behavior if rebuilt or if they undergo rewriting rules, as strides and offset are not stored in a persistent manner. It's the reason why I proposed a static dict. |
I see. Could you provide a minimal example where this might occur? (I think we should add a test to guard against it) |
In [1]: A = IndexedBase("A")
In [2]: A.test = "This is a test"
In [3]: As = A.subs(Symbol("A"), Symbol("B")).subs(Symbol("B"), Symbol("A"))
In [4]: A.test
Out[4]: 'This is a test'
In [7]: As.test
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-7-3680e7e751f7> in <module>()
----> 1 As .test
AttributeError: 'IndexedBase' object has no attribute 'test' |
Thanks, since it works for shape:
I was thinking that we could add But to my surprise I can't get that to work (see: 57ae527):
I've compared how shape and strides are handled in that commit of mine line by line, but I fail to see how they differ, any clue? One of the strengths of SymPy (and Python projects in general) is that the source code is rather accessible, but with these things there is quite a bit of "magic" going on, so that so called "local reasoning" fails. |
That commit ( 57ae527 ) does not preserve the positional order of args. That is, when the object is reconstructed, the arguments may be inserted in a different order.
That's why I'm a bit skeptical about putting too many arguments in a single object. I think we should just put the essential information the the args and leave extra info somewhere else. |
Thank you. I started sketching out an API for attributes, but I still need to make the super class ( This is trickier than I expected. |
I believe we shouldn't make this PR too long. Modifying Also, attributes don't need to be subclasses of |
I introduced the static dictionary approach exactly to solve this issue. The static dictionary is a permanent data structure that is not affected by the rewriting rules.
We can merge if you want. Maybe we can open another issue to remember to fix the reconstruction problem. Anyway, I would like to eventually get rid of |
@Upabjojr OK, so I opened #12593. EDIT: I'm fine with giving up on |
This discussion was quite valuable. I learnt quite a bit more about Python. |
As mentioned in #12464 ,
ccode
unrolled 2DIndexed
objects in row-major format. This PR adds support for unrolling in column-major format as well.Example :
UPDATE : Now support for strided schemes and offset have been added
Fixes #12464