Skip to content
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

Canonicalization of Hadamard Product #16685

Merged
merged 22 commits into from May 11, 2019

Conversation

sylee957
Copy link
Member

@sylee957 sylee957 commented Apr 19, 2019

References to other Issues or PRs

Brief description of what is fixed or changed

With matrix of ones implemented in #16676, we may use the identity to make hadamard product more canonical.

  • Associative (Default)
  • Commutative
  • Identity for Hadamard product by one matrix
  • Absorbing to zero matrix when multiplied with zero matrix
  • Rewriting to Hadamard power when repetitive matrices are multiplied.
  • (Optional) Reduce to diagonal matrix when multiplied with IdentityMatrix (Or any rectangular eye) After the decision is made for Rename DiagonalizeVector? #16682

Other comments

This is still work in progress, and I will add some tests if the design is set

I also think that HadamardProduct can automatically unpack its argument, if given a single argument, like in SymPy's Add, Mul.
As it is confusing that
HadamardProduct(A) == A is giving False because it does not unpacks single arguent
but hadamard_product(A) == A is giving True.
And the printing is not suggestive that HadamardProduct is wrapped on this.
Though changing this would make some tests fail, and there may be some discussion for design change?

Release Notes

  • matrices
    • Improved canonicalization for HadamardProduct
    • Deleted rules from matrices.expressions.hadamard

@sympy-bot
Copy link

sympy-bot commented Apr 19, 2019

Hi, I am the SymPy bot (v147). I'm here to help you write a release notes entry. Please read the guide on how to write release notes.

Your release notes are in good order.

Here is what the release notes will look like:

This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.5.

Note: This comment will be updated with the latest check if you edit the pull request. You need to reload the page to see it.

Click here to see the pull request description that was parsed.

<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->

#### References to other Issues or PRs
<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234". See
https://github.com/blog/1506-closing-issues-via-pull-requests . Please also
write a comment on that issue linking back to this pull request once it is
open. -->


#### Brief description of what is fixed or changed

With matrix of ones implemented in #16676, we may use the identity to make hadamard product more canonical.

- [X] Associative (Default)
- [X] Commutative
- [X] Identity for Hadamard product by one matrix
- [X] Absorbing to zero matrix when multiplied with zero matrix
- [x] Rewriting to Hadamard power when repetitive matrices are multiplied.
- [ ] (Optional) Reduce to diagonal matrix when multiplied with `IdentityMatrix` (Or any rectangular `eye`) After the decision is made for #16682 

#### Other comments

This is still work in progress, and I will add some tests if the design is set

I also think that `HadamardProduct` can automatically unpack its argument, if given a single argument, like in SymPy's `Add`, `Mul`.
As it is confusing that
`HadamardProduct(A) == A` is giving `False` because it does not unpacks single arguent
but `hadamard_product(A) == A` is giving `True`.
And the printing is not suggestive that `HadamardProduct` is wrapped on this.
Though changing this would make some tests fail, and there may be some discussion for design change?

#### Release Notes

<!-- Write the release notes for this release below. See
https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more information
on how to write release notes. The bot will check your release notes
automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->
- matrices
  - Improved canonicalization for `HadamardProduct`
  - Deleted `rules` from `matrices.expressions.hadamard`
<!-- END RELEASE NOTES -->

Update

The release notes on the wiki have been updated.

@sylee957 sylee957 changed the title Canonicalization of Hadamard Product [WIP] Canonicalization of Hadamard Product Apr 19, 2019
@codecov
Copy link

codecov bot commented Apr 20, 2019

Codecov Report

Merging #16685 into master will decrease coverage by 0.019%.
The diff coverage is 100%.

@@             Coverage Diff              @@
##            master    #16685      +/-   ##
============================================
- Coverage   73.847%   73.827%   -0.02%     
============================================
  Files          619       619              
  Lines       159329    159406      +77     
  Branches     37388     37414      +26     
============================================
+ Hits        117660    117685      +25     
- Misses       36241     36263      +22     
- Partials      5428      5458      +30

@Upabjojr
Copy link
Contributor

I've added some tests and made some minor fix.

It looks good, I need this PR to go on with the matrix derivatives algorithm.

…s the product order to depend on the Python hashing values.
@Upabjojr
Copy link
Contributor

I would put the examples in the HadamardProduct documentation. The function canonicalize is meant to be private.

@Upabjojr
Copy link
Contributor

For diagonal matrix checks:

from sympy.assumptions import ask, Q
ask(Q.diagonal(mat))  # <== this returns True if the matrix is diagonal

Though I would use it with care, as slowdowns might be expected.

=====

As Hadamard product is associative, all the nested products can be
flattened to the level 1.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the Hadamard product is associative nested products can be flattened.

flattened to the level 1.

As Hadamard product is commutative, all the arguments can be sorted to
the canonical form.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Hadamard product is commutative so factors can be sorted for canonical form.

the canonical form.

Matrix of only ones is an identity for Hadamard product,
so every ``OneMatrix`` can be removed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A matrix of only ones...

Matrix of only ones is an identity for Hadamard product,
so every ``OneMatrix`` can be removed.

Matrix of only zeros will make Hadamard product zero.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any zero matrix will make the whole product a zero matrix.


# Rewriting with HadamardPower
if isinstance(x, HadamardProduct):
tally = dict()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could use collections.Counter

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or multiset from iterables:

 >>> multiset('mississippi')
    {'i': 4, 'm': 1, 'p': 2, 's': 4}

so

tally = multiset(x.args)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done some experiment in cpython 3.6

from sympy.utilities.iterables import multiset
from collections import Counter

l = 'abc'+'c'*999999

%timeit Counter(l) 349 ms ± 53.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit multiset(l) 578 ms ± 36.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

I guess the one from the official library can use C function to speed up
https://github.com/python/cpython/blob/f2f55e7f03d332fd43bc665a86d585a79c3b3ed4/Modules/_collectionsmodule.c#L2237

x = HadamardProduct(*new_arg)

# Commutativity
fun = condition(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what aspect of this relates to commutativity? After using the tally, things are going to be reordered, aren't they?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the fact that things are getting reordered will make a reason to sort lastly.

@smichr
Copy link
Member

smichr commented May 10, 2019

Is there more you wanted to do with this?

@sylee957
Copy link
Member Author

Things like boilerplating can better be cleaned up later after some big progress in the module is made, regarding the comments.

I had some other things to do, but I think that there is no problem for merging this now.

@sylee957 sylee957 changed the title [WIP] Canonicalization of Hadamard Product Canonicalization of Hadamard Product May 10, 2019
@asmeurer
Copy link
Member

Should it use AssocOp? I don't know if there are issues using it in the matrix expressions.

@asmeurer
Copy link
Member

I guess MatAdd and MatMul use it via subclassing from Add and Mul. Although I added an XXX comment that that might not be desirable. So I'm really not sure if using AssocOp for this would be a good idea or not.

@smichr smichr merged commit 0b09027 into sympy:master May 11, 2019
@sylee957
Copy link
Member Author

I considered AssocOp, but I think that there is a problem for defining identity because the matrix operations can only be defined after the dimensions are known.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants