user2657817
user2657817

Reputation: 652

Linear Combination of Counters in Python

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

Answers (1)

hilberts_drinking_problem
hilberts_drinking_problem

Reputation: 11612

Here is a solution very much along the lines of your approach.

  1. Convert each Counter to a vector, treating different IDs as separate dimensions.
  2. Solve a system of linear equations.

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

Related Questions