-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Adds new broadcast_to atom for nd broadcasting #2724
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
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.
I think this is ready for a first round of reviews. I have still yet to add backend specific tests which could help understand the operator (although it is mostly about duplicating existing tensors along the rows).
Things that are open for discussion, do we want to support broadcasting for both operands? (i.e. cp.multiply((3,1), (5)) is allowed and will give an (3,5) expression)
this means we will need to broadcast both the constant data and the variable/expr which differs from the current behavior (although matches the NumPy API for broadcasting)
cvxpy/tests/test_expressions.py
Outdated
| @pytest.mark.parametrize("shapes", [((5),(3, 1)), | ||
| ((15, 1),(8)), | ||
| ((3), (2, 1))]) | ||
| def test_segfault_multiply(self, shapes) -> None: |
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 you say more about this test? Would these shapes be compatible with numpy broadcasting rules?
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 they are compatible with numpy broadcasting. And these tests would pass for the SCIPY backend. However, I was not able to enforce the SCIPY backend to be used in these cases. (CPP would raise errors because it doesn't have the broadcast_to atom implemented).
|
This is a really elegant solution for the backend! To be clear, in this MR we are not handling cases such as (5) + (5,1) -> (5,5)? We should still handle these cases but it can be in a separate MR. |
| def _supports_cpp(self) -> bool: | ||
| return False |
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've added this method, but I was still getting tests going through the CPP backend.
I think it's because the broadcast_to atom is being called from another atom (i.e. multiply), but not sure.
Ideally we should fix this, but maybe for another PR.
|
There is a bug in |
* adding some initial ideas to fix broadcasting * reverting changes and adding new tests/broadcast atoms * add more boilerplate for broadcasting operator * updating methods for the broadcast_to atom * some improvements * add more tests for broadcasting, raise exception * update shape from args and validate args * fixing some tests, but still issues with CPP backend not implemented * adding test from eric's code snippet * fixing all tests and adding new ones for multiply broadcast * revert these changes and remove failing case as separate test * reverting changes to typing * some updates and progress towards a truly working backend * truly reverting np.typing issue now * fixing implementation for broadcast_to atom, and cleaning up tests * final changes for broadcasting to be fully working in nd * adding hypothesis tests and renaming some other stuff * fix bug * maybe fixed all the tests? * remove breakpoint * final touches, changing test name and case in expr.broadcast * revert changes to expr.broadcast --------- Co-authored-by: William Zijie Zhang <[email protected]> Co-authored-by: Steven Diamond <[email protected]>
* patch empty breaking empty rownames for xpress>=9.5 (#2745) Co-authored-by: Marc Bataillou Almagro <[email protected]> * Adds new broadcast_to atom for nd broadcasting (#2724) * adding some initial ideas to fix broadcasting * reverting changes and adding new tests/broadcast atoms * add more boilerplate for broadcasting operator * updating methods for the broadcast_to atom * some improvements * add more tests for broadcasting, raise exception * update shape from args and validate args * fixing some tests, but still issues with CPP backend not implemented * adding test from eric's code snippet * fixing all tests and adding new ones for multiply broadcast * revert these changes and remove failing case as separate test * reverting changes to typing * some updates and progress towards a truly working backend * truly reverting np.typing issue now * fixing implementation for broadcast_to atom, and cleaning up tests * final changes for broadcasting to be fully working in nd * adding hypothesis tests and renaming some other stuff * fix bug * maybe fixed all the tests? * remove breakpoint * final touches, changing test name and case in expr.broadcast * revert changes to expr.broadcast --------- Co-authored-by: William Zijie Zhang <[email protected]> Co-authored-by: Steven Diamond <[email protected]> * change is_released to true --------- Co-authored-by: Marc Bataillou Almagro <[email protected]> Co-authored-by: Marc Bataillou Almagro <[email protected]> Co-authored-by: William Zijie Zhang <[email protected]> Co-authored-by: Steven Diamond <[email protected]>
Description
Please include a short summary of the change.
This PR introduces the broadcast_to atom in hopes of fixing issues with broadcasting in higher dimensions.
The broadcast_to atom is used internally inside of the expression class in its
broadcastmethod.This method is called in many places, including binary ops, basic ops and others.
The implementation of the atom follows other similar shape manipulation atoms such as vstack and concatenate. The idea is to form a set of indices which are reshaped to the expression's shape, then using numpy's API we are able to mimic the behavior of
np.broadcast_toon cvxpy's tensor views in the backend.CPP backend compatibility
In the #2728 discussion, I brought up some issues with the difference in behavior for the backends. Those issues were resolved as follows:
cp.broadcast_towhen one of the operands has dim > 2, which ensures that the SCIPY backend is used.Improved error messages
Recent changes to the codebase (notably adding the cp.concatenate atom) showed that we are able to instantiate empty numpy arrays (using
dtype=np.empty([])) and then perform analogous operations on those arrays to get the error handling from numpy for free. This technique has been reused here to improve on the existing multiply atom error handling.Issue link (if applicable): #2739
Type of change
Contribution checklist