-
Notifications
You must be signed in to change notification settings - Fork 68
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
updates to 'dp' optimizer #119
Conversation
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.
A few quick comments, I need to think a bit about the logic here.
opt_einsum/paths.py
Outdated
|
||
# only if s1 and s2 are disjoint | ||
if s1 & s2 == 0: | ||
if not s1 & s2: |
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.
Can we collapse this and the below if to a single line to help with the indention?
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.
Ah yes nice.
@@ -197,6 +197,59 @@ def test_greedy_edge_cases(): | |||
assert check_path(path, [(0, 1), (0, 2), (0, 1)]) | |||
|
|||
|
|||
def test_dp_edge_cases_dimension_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.
Awesome, thanks for the extra tests!
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.
Good idea to add these tests.
opt_einsum/paths.py
Outdated
i_r = set() | ||
|
||
# contraction indices: | ||
i_cntrct = i1_cut_i2_wo_output - i_r |
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.
Can we write out cntrct
(is it contract?), will help with readability.
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 it is (I didn't write these variable names originally), but yes can update.
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.
Yes, it stands for contract. Don't know why I named it that way.. Maybe some line length issue..
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.
Overall LGTM with a few more docs.
@mrader1248 Do you have time to comment here?
docs/source/dp_path.rst
Outdated
import opt_einsum as oe | ||
|
||
optimizer = oe.DynamicProgramming( | ||
minimize='size', # optimize for size (rather than FLOPs) |
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 may want to define size
here.
|
||
>>> list(_bitmapset_indices(0b1001011)) | ||
[0, 1, 3, 6] | ||
def _dp_calc_legs(g, all_tensors, s, inputs, i1_cut_i2_wo_output, i1_union_i2): |
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.
Can we add short doc strings for these two functions.
opt_einsum/paths.py
Outdated
else: | ||
# if the input has any index reductions, add single contraction | ||
inputs.append(i_reduced) | ||
inputs_contractions.append((j,) if i_reduced != i else j) |
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 see that my original code did not work if there was nothing more to optimise at this point. However, I find this reassignment of inputs
in combination with the loop rather confusing.. I guess the original code could be fixed, if the zip
would only be unpacked if the list constructed inside the zip
is not empty.
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.
Yes this seemed liked the simplest way to solve the 'nothing left to do' bug and also not iterate and filter the inputs twice in the same way. But certainly open to suggestions for making it more readable. Maybe just renaming the new inputs -> inputs_parsed
or something?
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.
To be honest, for me list comprehensions are much more expressive compared to list constructions using loops. However, at least the variable inputs
should be renamed.
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.
Of course generally I agree! But when for loops can do the same thing more efficiently... I think they are the correct tool to use. I've renamed the parsed inputs
to inputs_contract
.
Can you give me an example, where it is beneficial to construct outer products? |
Sorry, it took me a while to have a look at this. Overall, LGTM. And especially thanks for fixing this stupid smallest dimension 1 bug. |
I've put this example in the tests (taken from you in another thread I think!): def test_custom_dp_can_optimize_for_outer_products():
eq = "a,b,abc->c"
da, db, dc = 2, 2, 3
shapes = [(da,), (db,), (da, db, dc)]
opt1 = oe.DynamicProgramming(search_outer=False)
opt2 = oe.DynamicProgramming(search_outer=True)
info1 = oe.contract_path(eq, *shapes, shapes=True, optimize=opt1)[1]
info2 = oe.contract_path(eq, *shapes, shapes=True, optimize=opt2)[1]
assert info2.opt_cost < info1.opt_cost Of course in practice I imagine it's almost never useful. However I think it would make sense for @dgasmith do you have any thoughts on pointing |
@dgasmith Also happy to have a go a adding more docs (e.g. each variable etc) if you think necessary. |
@jcmgray I see, I thought you found an example where constructing outer products first leads to a better solution even in the asymptotic limit. Maybe it would be good to mention in the docs that allowing for intermediate outer products can lead to horrible optimisation times? |
Well in the asymptotic limit where
I've mentioned this in the docstring for the |
OK, so I've added a warning to the |
Description
These updates the
'dp'
optimizer in a few ways:cost_cap
iterate strategy (on, off or manual)DynamicProgrammingOptimizer->DynamicProgramming
and add it to the top namespaceI think with these, it would make sense to make the
'optimal'
algorithm point at'dp'
since with the outer product search it should now find all the same contractions, and with thecost_cap
turned off it's as fast for small contractions as well. This would fix #99. Thoughts @dgasmith? Also cc @mrader1248.Todos
DynamicProgramming
'dp'
for'optimal'
?'auto'
value for thecost_cap
that simply turns it off til the contraction is quite bigStatus