如何平衡 Python 中的化学方程式 2.7 使用矩阵
How to balance a chemical equation in Python 2.7 Using matrices
我有一项大学作业,我必须平衡以下等式:
NaOH + H2S04 --> Na2S04 + H2O
目前我对 python 和一般编码的了解极为有限。
到目前为止,我已经尝试使用矩阵来求解方程。
看起来我得到了解决方案 a=b=x=y=0
我想我需要将其中一个变量设置为 1 并求解其他三个变量。
我不知道该怎么做,
我搜索了一下,好像
其他人使用了更复杂的代码,但我真的无法理解!
这是我目前所拥有的
#aNaOH + bH2S04 --> xNa2SO4 +y H20
#Na: a=2x
#O: a+4b=4x+y
#H: a+2h = 2y
#S: b = x
#a+0b -2x+0y = 0
#a+4b-4x-y=0
#a+2b+0x-2y=0
#0a +b-x+0y=0
A=array([[1,0,-2,0],
[1,4,-4,-1],
[1,2,0,-2],
[0,1,-1,0]])
b=array([0,0,0,0])
c =linalg.solve(A,b)
print c
0.0.0.0
问题是您构建了一个线性系统,b 是零向量。现在对于这样的系统,总是有一个直接的答案,即所有变量也都是零。因为将数字与零相乘并添加零,结果始终为零。
一个解决方案可能是将 1 赋给一个变量。以 a
为例。如果我们分配 a = 1
,那么我们将在 a
为 1 的函数中得到 b
、x
和 y
。
所以现在或线性系统是:
B X Y | #
2 |1 # A = 2X
-4 4 1 |1 # A+4B = 4X+4Y
-2 2 |1 # A+2B = 2Y
-1 1 0 |0 # B = X
或者写成代码:
>>> A = array([[0,2,0],[-4,4,1],[-2,0,2],[-1,1,0]])
>>> B = array([1,1,1,0])
>>> linalg.lstsq(A,B)
(array([ 0.5, 0.5, 1. ]), 6.9333477997940491e-33, 3, array([ 6.32979642, 2.5028631 , 0.81814033]))
所以这意味着:
A = 1, B = 0.5, X = 0.5, Y = 1.
如果我们将其乘以 2,我们得到:
2 NaOH + H2S04 -> Na2S04 + 2 H20
哪个是正确的。
我参考了 翻译成
# 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()
运行起来像
Please enter left-hand list of compounds, separated by spaces:
NaOH H2SO4
Please enter right-hand list of compounds, separated by spaces:
Na2SO4 H2O
Balanced solution:
2 NaOH + 1 H2SO4 -> 1 Na2SO4 + 2 H2O
做得很好。但是,当我根据第 5 版 David Lay 的线性代数教科书上的以下方程测试此片段时,我收到了一个可以进一步简化的次优解。
第55、1.6 练习检查 ex 7.:
NaHCO_3 + H_3C_6H_5O_7 --> Na_3C_6H_5O_7 + H_2O + CO_2
您的代码段 returns:
平衡解决方案:
15NaHCO3 + 6H3C6H5O7 -> 5Na3C6H5O7 + 10H2O + 21CO2
正确答案是:
3NaHCO_3 + H_3C_6H_5O_7 -> Na_3C_6H_5O_7 + 3H_2O + 3CO_2
您可以使用此解决方案。它适用于任何化学方程式。最后一个系数可以用一行计算,其中 b[i]!=0
H2SO4+NaOH-->Na2SO4+H2OH2SO4+NaOH-->Na2SO4+H2O
a=np.array([[2,1,0],[1,0,-1],[4,1,-4],[0,1,-2]])
b=np.array([2,0,1,0])
x=np.linalg.lstsq(a,b,rcond=None)[0]
print(x)
y=sum(x*a[0])/b[0]
print("y=%f"%y)
输出:
[0.5 1. 0.5]
y=1.000000
我有一项大学作业,我必须平衡以下等式:
NaOH + H2S04 --> Na2S04 + H2O
目前我对 python 和一般编码的了解极为有限。 到目前为止,我已经尝试使用矩阵来求解方程。 看起来我得到了解决方案 a=b=x=y=0 我想我需要将其中一个变量设置为 1 并求解其他三个变量。 我不知道该怎么做, 我搜索了一下,好像 其他人使用了更复杂的代码,但我真的无法理解!
这是我目前所拥有的
#aNaOH + bH2S04 --> xNa2SO4 +y H20
#Na: a=2x
#O: a+4b=4x+y
#H: a+2h = 2y
#S: b = x
#a+0b -2x+0y = 0
#a+4b-4x-y=0
#a+2b+0x-2y=0
#0a +b-x+0y=0
A=array([[1,0,-2,0],
[1,4,-4,-1],
[1,2,0,-2],
[0,1,-1,0]])
b=array([0,0,0,0])
c =linalg.solve(A,b)
print c
0.0.0.0
问题是您构建了一个线性系统,b 是零向量。现在对于这样的系统,总是有一个直接的答案,即所有变量也都是零。因为将数字与零相乘并添加零,结果始终为零。
一个解决方案可能是将 1 赋给一个变量。以 a
为例。如果我们分配 a = 1
,那么我们将在 a
为 1 的函数中得到 b
、x
和 y
。
所以现在或线性系统是:
B X Y | #
2 |1 # A = 2X
-4 4 1 |1 # A+4B = 4X+4Y
-2 2 |1 # A+2B = 2Y
-1 1 0 |0 # B = X
或者写成代码:
>>> A = array([[0,2,0],[-4,4,1],[-2,0,2],[-1,1,0]])
>>> B = array([1,1,1,0])
>>> linalg.lstsq(A,B)
(array([ 0.5, 0.5, 1. ]), 6.9333477997940491e-33, 3, array([ 6.32979642, 2.5028631 , 0.81814033]))
所以这意味着:
A = 1, B = 0.5, X = 0.5, Y = 1.
如果我们将其乘以 2,我们得到:
2 NaOH + H2S04 -> Na2S04 + 2 H20
哪个是正确的。
我参考了
# 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()
运行起来像
Please enter left-hand list of compounds, separated by spaces:
NaOH H2SO4
Please enter right-hand list of compounds, separated by spaces:
Na2SO4 H2O
Balanced solution:
2 NaOH + 1 H2SO4 -> 1 Na2SO4 + 2 H2O
做得很好。但是,当我根据第 5 版 David Lay 的线性代数教科书上的以下方程测试此片段时,我收到了一个可以进一步简化的次优解。
第55、1.6 练习检查 ex 7.:
NaHCO_3 + H_3C_6H_5O_7 --> Na_3C_6H_5O_7 + H_2O + CO_2
您的代码段 returns:
平衡解决方案:
15NaHCO3 + 6H3C6H5O7 -> 5Na3C6H5O7 + 10H2O + 21CO2
正确答案是:
3NaHCO_3 + H_3C_6H_5O_7 -> Na_3C_6H_5O_7 + 3H_2O + 3CO_2
您可以使用此解决方案。它适用于任何化学方程式。最后一个系数可以用一行计算,其中 b[i]!=0
H2SO4+NaOH-->Na2SO4+H2OH2SO4+NaOH-->Na2SO4+H2O
a=np.array([[2,1,0],[1,0,-1],[4,1,-4],[0,1,-2]])
b=np.array([2,0,1,0])
x=np.linalg.lstsq(a,b,rcond=None)[0]
print(x)
y=sum(x*a[0])/b[0]
print("y=%f"%y)
输出:
[0.5 1. 0.5] y=1.000000