-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Code Printing refactor, matrix support #7823
Conversation
Works for C code only, with input and input/output args of matrices. Expression to be codegen'ed must be an Eq(MatrixSymbol, Matrix). Still need to work through codegen code to see if there is an easier (less hackish) way, but it currently "works".
Now supports automatic output variable creation for Matrices not originally wrapped in an `Eq`. This means that the following now works: mat = Matrix([a, b, c]) codegen(('mat', mat), 'c', 'mat) Also did some code cleanup to prior work on matrices.
On WIPs it may be useful to check this out: http://docs.travis-ci.com/user/how-to-skip-a-build/ You can prevent Travis from building when you don't need it to. |
Ah, good to know. I can't cancel them directly as I don't have push access. I'll try that next time. |
You can also ask @asmeurer for push access. You should get it by now. |
Start of refactor to codeprinters to make adding new features simpler. The main purpose behind this is to make support for matrices and matrix expressions easier, and remove bugs in Piecewise and looping. - Added Assignment node, to represent assignment rather than Equality (which should be used for equality testing, resulting in a bool). - Refactored ccode `doprint` method to move most of the control flow to a _print_Assignment method, called like all other print methods by the _print method in Printer. This makes more sense, and sticks with the original design of the Printer class. - Some variable name cleanups to improve readability of the CodePrinter class.
Refactored fcode similar to how ccode was changed in the last commit. Also changed doprint to accept assign_to as a kwarg, as ccode does, rather than store it as a setting.
Fortran code printing now supports 2 dimensional arrays. Also added (possible) efficiency improvement by reordering declaration order of C code array elements to be in-memory order. gcc probably optimizes this already, but it was an easy fix.
- Moved common methods onto CodePrinter class - We now check if either the lhs or rhs of an expression has IndexedBase objects to see if loops are needed. This is necessary because sometimes the accumulator isn't an Indexed Object. There were two thoughts on how to set this up: 1. Call _doprint_a_piece (now _doprint_loops) on *all* Assignment expressions: - Expressions w/o loops: 2 tree traversals before being printed - Expressions w/ loops: 2 tree traversals before being printed 2. Check for IndexedBase in lhs first, then rhs: - Expressions w/o loops: 1 tree traversal before being printed - Expressions w/ loops: 3 tree traversals before being printed (worst case. Most cases will be only 2). Note that most Indexed expressions tend to be short and concises, as well as have a lhs which contains Indexed objects (will result in *fast* method call, because lhs trees are small). In contrast, most users do not use Indexed, and many expressions are rather large. Hence it is more beneficial for the user to be cheaper on loopless expressions, while increasing the worst-case time for looped expressions (most looped expressions will have a negligible time increase).
Continuation of the codegen refactor. jscode now in same format as ccode and fcode. jscode now also supports matrices.
- Moved all common methods into CodePrinter - Added methods that need to be defined by anything subclassed from `CodePrinter` to `CodePrinter` with a `NotImplementedError`. This should help anyone out looking to create a new code printer, as it shows what needs to be defined by the subclass so that everything just *works* - Small fix to the mathematic printing so it has it's own doprint method. I don't know anything about mathematica. This keeps everything the same as before for this refactoring. - Small formatting cleanups
Now Piecewise lacking a default condition (i.e. an (expr, True) term) will throw an error. This is because without such a statement, the generated code may not return anything. Other options were to return NaN in such a situation, but this was turned down due to lack of support by all languages/compilers, and that this is unexpected behavior. Added tests for the conditional printing.
Rewrote `Assignment` operator to subclass Relational, not Equality. This reduces object creation time, allowed more types to be used as the rhs, and makes more sense in the end. Added tests for Assignment. This class should probably go in a different file, but is in codeprinter for now. Added tests for matrix code printing to ccode, fcode and jscode.
I set out just to get matrix printing working, but ended up finding so many bugs in the existing codebase that I ended up doing a substantial refactor. This PR now only has to do with codeprinting (and a little fix to the codegen stuff), but nothing with autowrap. Instead I rewrote a good chunk of the codeprinting code. What's in this PR:
Changes in codeprinting philosophyIn the past, we'd print expressions haphazardly, doing assignment on some, and not on others. It seemed messy and inconsistent to me, so I rewrote it. The new philosophy is as follows:
This means that we will no longer be printing code that looks like this:
as this in practice doesn't do anything. It may be a translation of Changes in codeprinting implementationThe new implementation moves almost all complicated code to the User facing changesBesides the added functionality, the only user facing changes are as follows:
In this form, there would be garbage output if a < 0. By not allowing Moving ForwardI'm sure there will be little things I'll have to fix to get this merged, but this is all the functionality I'd like to have in this PR. In its current state this provides many needed bugfixes to codeprinting, cleans up and simplifies the codebase, and adds support for Matrices and MatrixSymbols in expressions. After this is merged I'll submit another PR adding support for |
- Fixed formatting to work with python 2.6 - Fixed error in immutable eval_Eq - Added test for Assignment in test_args
@moorepants, @srjoglekar246: please review. @bjodah: I reworked a good portion of the code printing, but left all the Indexed stuff the same. It should be more extensible in its new form though. Will this work with what you're doing? |
@@ -239,6 +214,10 @@ def jscode(expr, assign_to=None, **settings): | |||
|
|||
expr : sympy.core.Expr | |||
a sympy expression to be converted | |||
assign_to : optional |
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.
Maybe write the expected type?
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.
This was just copied from another docstring. Really all the docs need improvement. Will fix.
I really like this PR - I think it's a good improvement to the codeprinters. I do not use the tensor contraction functionality of Indexed so I cannot comment on that but as long as the tests still pass I see no reason to why this wouldn't be a nice improvement even in that case. |
"else {\n" | ||
" A[1][0] = y;\n" | ||
"}\n" | ||
"A[2][0] = sin(z);") |
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.
Very nice!
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.
Yeah, I'm really happy about this. You can also do Piecewise inline in a matrix element definition using the ternary operators, so you don't even have to apply piecewise_fold
. I'm seeing all sorts of uses for this, mainly in the evaluation of a linearized system matrix where the choice of independent/dependent coordinates is the conditional (dealing with the singularities). Would help with stability analysis throughout an entire range of motion.
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.
Totally. This is gonna open lots of possibilities.
- Added improved docstrings to fcode, ccode, and jscode - Standardized implementation of all three code printing functions, they now all take the same kwargs (except for standard and source_format, which are fortran specific). - Standardized implementation of Function printing, moved this to codeprinter. There was a bug in that some functions that weren't standard C/Fortran/JS were getting through without being marked. This was because of the old method of "unless it's stated to be bad, it's good". The new printing works the opposite: only functions that are known to be standard are whitelisted. This catches the issues in a much more standard and clean way, and allows for reuse of the print_Function implementation. - As part of standardizing Function printing, the fix for sympy#6814 was changed. Previously we were printing `log(10d0)` for `log(10)` in fortran, because this function only accepts floats. The new implementation evaluates this to the required precision (default 15) in sympy, and just prints a number. If the function doesn't evaluate fully (suppose atan2(2, x) -> atan2(2.0000, x)), then the numeric constants are still printed as doubles, so everything works fine.
I have updated the docstrings with tons of examples (and made them consistent between the three functions). In the process found a few inconsistencies/bugs in ccode, jscode, and fcode, mainly dealing with how user-functions/functions are printed. Because this is already a mammoth of a PR dealing with pretty much an overhaul of the printing I added this in here as well. If you're interested in the specifics, read the latest commit message. Once this passes travis I think it's good to go. |
Looks like all tests passed. What are people's thoughts on this? @moorepants, @srjoglekar246. |
It looks good to me. Seems like the only major change that people need to be aware of is the conditionals, but that seems to be an improvement to get correct behavior. I guess you could send out a warning if people don't add the default to their Piecewise. My only comment is that the sphinx docs only include API references which will have your examples, but it would be nice to have some prose to explain things a bit. But not a requirement for merging this. +1 |
Right now we error if people don't add the default. Previously if people didn't add the default it would result in uncompilable code (bracket mismatches), so I don't think anyone was using this behavior anyway. All other changes were fixing broken things as well, so I don't think anything needs to be deprecated. I'll give people the day to look this over, and if no one objects I'll merge it tonight. |
It'd be nice to get @mrocklin's opinion. |
Probably won't have the time to look at this until later tonight, around 10 hours from now. Even then it's dubious. |
@mrocklin: This is mainly about code generation, and has little to do with other things. The only thing I'm really concerned about is the small change I had to make to the matrix stuff to get |
In principle that doesn't cause any blocks or -1s from me. I wouldn't be surprised if it caused trouble down the line. For the time being though it seems like a decent path forward. If issues arise in the future it might make sense to create a matrix equality class. |
In reality the need is just a bandaid on a bigger issue that I plan on tackling soon. The only reason |
@@ -75,6 +75,9 @@ def _eval_Eq(self, other): | |||
""" | |||
if not hasattr(other, 'shape') or self.shape != other.shape: | |||
return S.false | |||
if isinstance(other, MatrixExpr) and not isinstance( | |||
other, ImmutableMatrix): |
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.
Are there classes that are instances of both?
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.
ImmutableMatrix
is an instance of both.
If there are no objections, I'll merge this tomorrow morning. |
👍 |
Code Printing refactor, matrix support
@jcrist thanks for this work! Shouldn't we add tests for more than one condition?
To make sure this will continue working. The same for:
|
** Edit **
This started out as just adding support for
Matrix
in codeprinting/codegen, but turned into a fairly substantial refactor of the existing codebase. I have updated this to reflect that. The TODO list is a trimmed down version of the original TODO,autowrap
support should come in a later PR, this only has to do with printing now.See my mammoth sized comment below for what's inside this PR now
** end edit **
TODO:
MatrixSymbol
input in ccode and CCodeGenMatrixSymbol
input in fcode and FCodeGen