# Find minimum integer coefficients for a chemical reaction like
#   A * NaOH + B * H2SO4 -> C * Na2SO4 + D * H20
import sympy
import re

   # match a single element and optional count, like Na2
ELEMENT_CLAUSE = re.compile("([A-Z][a-z]?)([0-9]*)")

def parse_compound(compound):
"""
Given a chemical compound like Na2SO4,
return a dict of element counts like {"Na":2, "S":1, "O":4}
"""
assert "(" not in compound, "This parser doesn't grok subclauses"
return {el: (int(num) if num else 1) for el, num in ELEMENT_CLAUSE.findall(compound)}

def main():
print("\nPlease enter left-hand list of compounds, separated by spaces:")
lhs_strings = input().split()
lhs_compounds = [parse_compound(compound) for compound in lhs_strings]

print("\nPlease enter right-hand list of compounds, separated by spaces:")
rhs_strings = input().split()
rhs_compounds = [parse_compound(compound) for compound in rhs_strings]

# Get canonical list of elements
els = sorted(set().union(*lhs_compounds, *rhs_compounds))
els_index = dict(zip(els, range(len(els))))

# Build matrix to solve
w = len(lhs_compounds) + len(rhs_compounds)
h = len(els)
A = [[0] * w for _ in range(h)]
# load with element coefficients
for col, compound in enumerate(lhs_compounds):
    for el, num in compound.items():
        row = els_index[el]
        A[row][col] = num
for col, compound in enumerate(rhs_compounds, len(lhs_compounds)):
    for el, num in compound.items():
        row = els_index[el]
        A[row][col] = -num   # invert coefficients for RHS

# Solve using Sympy for absolute-precision math
A = sympy.Matrix(A)    
# find first basis vector == primary solution
coeffs = A.nullspace()[0]    
# find least common denominator, multiply through to convert to integer solution
coeffs *= sympy.lcm([term.q for term in coeffs])

# Display result
lhs = " + ".join(["{} {}".format(coeffs[i], s) for i, s in enumerate(lhs_strings)])
rhs = " + ".join(["{} {}".format(coeffs[i], s) for i, s in enumerate(rhs_strings, len(lhs_strings))])
print("\nBalanced solution:")
print("{} -> {}".format(lhs, rhs))

if __name__ == "__main__":
main()

Recommended Answers

All 2 Replies

That's a tall order since:

SymPy is a Python library for symbolic mathematics.

Your first order of business would be to convert SymPy or find something that can stand as it's replacement but for your language of choice.

Frankly if I were asked to do this I would call the .py file from Java and leave this in Python. Or accept that this must stay in Python unlesd one has enough time (months or more?) to do such a conversion.

It looks ike there's only a couple of SymPy calls that do anything, so the challenge is simply to replace those two methods.
There are a ton of Java libraries for handling matrix arithmetic etc - it shouldn't be to hard to find the required functionality.
The rest of the code looks easy enough to convert.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.