Reputation: 652
I have some Counter objects like below representing the left hand side and right hand side of an equation:
Left Hand Side: (Counter({22.99: 1}), Counter({12.011: 2, 15.999: 2}), Counter({12.011: 7}))
Right Hand Side: Counter({12.011: 15, 15.999: 1})
My objective is to find the common elements between both sides of the equation and then determine a linear combination of the left that can give me the right side.
In the example above, the equation to solve would be:
2A*12.011 + 7B*12.011 = 15W*12.011
2A*15.999 = W*15.999
I anticipate this operation would involve converting the Counter dictionary to a matrix to solve a system of linear equations but am stuck on how to do this.
Upvotes: 0
Views: 351
Reputation: 11612
Here is a solution very much along the lines of your approach.
from collections import Counter
import numpy as np
from scipy import linalg
lhs = (Counter({22.99: 1}), Counter({12.011: 2, 15.999: 2}), Counter({12.011: 7}))
rhs = Counter({12.011: 15, 15.999: 1})
# get unique keys that occur in any Counter in 2D
# each unique key represents a separate dimension
ks = np.array([*set().union(rhs, *lhs)])[:, None]
# get a helper function to convert Counters to vectors
ctr_to_vec = np.vectorize(Counter.__getitem__)
lhs_mat = ctr_to_vec(lhs, ks)
rhs_vec = ctr_to_vec(rhs, ks)
# compute coefficients solving the least-squares problem
coefs = linalg.lstsq(lhs_mat, rhs_vec)[0]
is_linear_comb = np.allclose(lhs_mat @ coefs, rhs_vec)
Upvotes: 1