生肉-待完善
This commit is contained in:
parent
12df1e8d57
commit
9eee646100
|
@ -10,5 +10,6 @@
|
||||||
<component name="PyDocumentationSettings">
|
<component name="PyDocumentationSettings">
|
||||||
<option name="format" value="PLAIN" />
|
<option name="format" value="PLAIN" />
|
||||||
<option name="myDocStringFormat" value="Plain" />
|
<option name="myDocStringFormat" value="Plain" />
|
||||||
|
<option name="renderExternalDocumentation" value="true" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PySciProjectComponent">
|
||||||
|
<option name="PY_SCI_VIEW" value="true" />
|
||||||
|
<option name="PY_SCI_VIEW_SUGGESTED" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -1,3 +1,9 @@
|
||||||
|
from fractions import Fraction
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import scipy as sp
|
||||||
|
|
||||||
|
|
||||||
def solve_equation(eq):
|
def solve_equation(eq):
|
||||||
"""
|
"""
|
||||||
配平化学方程式,返回配平后的化学方程式
|
配平化学方程式,返回配平后的化学方程式
|
||||||
|
@ -15,12 +21,94 @@ def solve_equation(eq):
|
||||||
:return: 配平后的化学方程式,与输入格式相同
|
:return: 配平后的化学方程式,与输入格式相同
|
||||||
若无法配平,则返回 None
|
若无法配平,则返回 None
|
||||||
"""
|
"""
|
||||||
# 使用加减消元法解方程组
|
# 统计所有元素的种类
|
||||||
# 依据:反应前后,每个元素的个数相等
|
elements = set()
|
||||||
|
for each in eq['left']:
|
||||||
# 用二维数组表示方程组的系数,用一维数组表示方程组的常数项
|
for atom in each['atoms']:
|
||||||
|
elements.add(list(atom.keys())[0])
|
||||||
|
for each in eq['right']:
|
||||||
|
for atom in each['atoms']:
|
||||||
|
elements.add(list(atom.keys())[0])
|
||||||
|
elements = list(elements)
|
||||||
|
# 构造系数矩阵
|
||||||
|
matrix = []
|
||||||
|
constant = []
|
||||||
|
for atom in elements:
|
||||||
|
# 遍历左边,左侧系数为正
|
||||||
|
row = []
|
||||||
|
for each in eq['left']:
|
||||||
|
for atom_ in each['atoms']:
|
||||||
|
if atom in atom_:
|
||||||
|
row.append(atom_[atom])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
row.append(0)
|
||||||
|
# 遍历右边,右侧系数为负
|
||||||
|
for each in eq['right']:
|
||||||
|
for atom_ in each['atoms']:
|
||||||
|
if atom in atom_:
|
||||||
|
row.append(-atom_[atom])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
row.append(0)
|
||||||
|
# 取出row中的最后一个元素,反转后加入常数项
|
||||||
|
constant.append(-row.pop())
|
||||||
|
matrix = np.mat(matrix, int)
|
||||||
|
print(matrix)
|
||||||
|
print(constant)
|
||||||
|
# 求解线性方程组
|
||||||
|
try:
|
||||||
|
result = sp.linalg.solve(matrix, constant).tolist()
|
||||||
|
except Exception as e:
|
||||||
|
print(e.args[0])
|
||||||
|
print('无解')
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 将结果写入化学方程式,最后一个生成物的系数需要计算得到
|
||||||
|
last_substance = eq['right'][-1]
|
||||||
|
last_atom = list(last_substance['atoms'][0].keys())[0]
|
||||||
|
# 计算除最后一种生成物外的所有生成物包含last_atom的系数之和
|
||||||
|
sum_ = 0
|
||||||
|
index = 0
|
||||||
|
for each in eq['left']:
|
||||||
|
for atom in each['atoms']:
|
||||||
|
if last_atom in atom:
|
||||||
|
# 该生成物包含last_atom,则获得last_atom的总个数,等于系数*原子个数
|
||||||
|
sum_ += result[index] * atom[last_atom]
|
||||||
|
break
|
||||||
|
index += 1
|
||||||
|
for each in eq['right'][:-1]:
|
||||||
|
for atom in each['atoms']:
|
||||||
|
if last_atom in atom:
|
||||||
|
sum_ -= result[index] * atom[last_atom]
|
||||||
|
break
|
||||||
|
index += 1
|
||||||
|
result.append(sum_ / last_substance['atoms'][0][last_atom])
|
||||||
|
result = expand_to_int(*result)
|
||||||
|
for i, each in enumerate(eq['left']):
|
||||||
|
each['coefficient'] = result[i]
|
||||||
|
for i, each in enumerate(eq['right']):
|
||||||
|
each['coefficient'] = result[i + len(eq['left'])]
|
||||||
|
return eq
|
||||||
|
|
||||||
|
|
||||||
|
def expand_to_int(*args):
|
||||||
|
"""
|
||||||
|
将一系列小数同时扩大,全部转换为最接近的整数
|
||||||
|
|
||||||
|
:param args: 一系列小数
|
||||||
|
:return: 一系列整数
|
||||||
|
"""
|
||||||
|
# 将所有小数转换为分数
|
||||||
|
fractions = []
|
||||||
|
for each in args:
|
||||||
|
fractions.append(Fraction(each).limit_denominator())
|
||||||
|
# 计算所有分数的最小公倍数
|
||||||
|
lcm = 1
|
||||||
|
for each in fractions:
|
||||||
|
lcm = lcm * each.denominator // np.gcd(lcm, each.denominator)
|
||||||
|
# 将所有分数扩大为最小公倍数
|
||||||
|
result = []
|
||||||
|
for each in fractions:
|
||||||
|
result.append(each.numerator * lcm // each.denominator)
|
||||||
|
return result
|
117
fraction.py
117
fraction.py
|
@ -1,117 +0,0 @@
|
||||||
class Fraction:
|
|
||||||
"""
|
|
||||||
代表分数的类,包含分子和分母
|
|
||||||
提供加减乘除运算
|
|
||||||
"""
|
|
||||||
def __init__(self, top, bottom):
|
|
||||||
self.num = top
|
|
||||||
self.den = bottom
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.num) + "/" + str(self.den)
|
|
||||||
|
|
||||||
def __add__(self, otherfraction):
|
|
||||||
newnum = self.num * otherfraction.den + self.den * otherfraction.num
|
|
||||||
newden = self.den * otherfraction.den
|
|
||||||
return Fraction(newnum, newden)
|
|
||||||
|
|
||||||
def __sub__(self, otherfraction):
|
|
||||||
newnum = self.num * otherfraction.den - self.den * otherfraction.num
|
|
||||||
newden = self.den * otherfraction.den
|
|
||||||
return Fraction(newnum, newden)
|
|
||||||
|
|
||||||
def __mul__(self, otherfraction):
|
|
||||||
newnum = self.num * otherfraction.num
|
|
||||||
newden = self.den * otherfraction.den
|
|
||||||
return Fraction(newnum, newden)
|
|
||||||
|
|
||||||
def __truediv__(self, otherfraction):
|
|
||||||
newnum = self.num * otherfraction.den
|
|
||||||
newden = self.den * otherfraction.num
|
|
||||||
return Fraction(newnum, newden)
|
|
||||||
|
|
||||||
def __eq__(self, otherfraction):
|
|
||||||
firstnum = self.num * otherfraction.den
|
|
||||||
secondnum = otherfraction.num * self.den
|
|
||||||
return firstnum == secondnum
|
|
||||||
|
|
||||||
def __gt__(self, otherfraction):
|
|
||||||
firstnum = self.num * otherfraction.den
|
|
||||||
secondnum = otherfraction.num * self.den
|
|
||||||
return firstnum > secondnum
|
|
||||||
|
|
||||||
def __lt__(self, otherfraction):
|
|
||||||
firstnum = self.num * otherfraction.den
|
|
||||||
secondnum = otherfraction.num * self.den
|
|
||||||
return firstnum < secondnum
|
|
||||||
|
|
||||||
def __ge__(self, otherfraction):
|
|
||||||
firstnum = self.num * otherfraction.den
|
|
||||||
secondnum = otherfraction.num * self.den
|
|
||||||
return firstnum >= secondnum
|
|
||||||
|
|
||||||
def __le__(self, otherfraction):
|
|
||||||
firstnum = self.num * otherfraction.den
|
|
||||||
secondnum = otherfraction.num * self.den
|
|
||||||
return firstnum <= secondnum
|
|
||||||
|
|
||||||
def __ne__(self, otherfraction):
|
|
||||||
firstnum = self.num * otherfraction.den
|
|
||||||
secondnum = otherfraction.num * self.den
|
|
||||||
return firstnum != secondnum
|
|
||||||
|
|
||||||
def get_num(self):
|
|
||||||
return self.num
|
|
||||||
|
|
||||||
def get_den(self):
|
|
||||||
return self.den
|
|
||||||
|
|
||||||
def __radd__(self, otherfraction):
|
|
||||||
return self
|
|
||||||
|
|
||||||
|
|
||||||
# 约分函数:将分数约分为最简分数
|
|
||||||
def reduce_fraction(fraction):
|
|
||||||
"""
|
|
||||||
将分数约分为最简分数
|
|
||||||
|
|
||||||
:param fraction: 分数,Fraction 类型
|
|
||||||
:return: 约分后的分数,Fraction 类型
|
|
||||||
"""
|
|
||||||
# 求最大公约数
|
|
||||||
def gcd(a, b):
|
|
||||||
if b == 0:
|
|
||||||
return a
|
|
||||||
else:
|
|
||||||
return gcd(b, a % b)
|
|
||||||
|
|
||||||
g = gcd(fraction.get_num(), fraction.get_den())
|
|
||||||
return Fraction(fraction.get_num() // g, fraction.get_den() // g)
|
|
||||||
|
|
||||||
|
|
||||||
# 通分函数:将多个分数通分
|
|
||||||
def common_denominator(fractions):
|
|
||||||
"""
|
|
||||||
将多个分数通分
|
|
||||||
|
|
||||||
:param fractions: 分数列表,Fraction 类型
|
|
||||||
:return: 通分后的分数列表,Fraction 类型
|
|
||||||
"""
|
|
||||||
# 求最大公约数
|
|
||||||
def gcd(a, b):
|
|
||||||
if b == 0:
|
|
||||||
return a
|
|
||||||
else:
|
|
||||||
return gcd(b, a % b)
|
|
||||||
|
|
||||||
# 求最小公倍数
|
|
||||||
def lcm(a, b):
|
|
||||||
return a * b // gcd(a, b)
|
|
||||||
|
|
||||||
# 通分
|
|
||||||
denominator = 1
|
|
||||||
for fraction in fractions:
|
|
||||||
denominator = lcm(denominator, fraction.get_den())
|
|
||||||
for i in range(len(fractions)):
|
|
||||||
fractions[i] = Fraction(fractions[i].get_num() * denominator // fractions[i].get_den(), denominator)
|
|
||||||
return fractions
|
|
15
main.py
15
main.py
|
@ -4,14 +4,17 @@
|
||||||
# 按 双击 ⇧ 在所有地方搜索类、文件、工具窗口、操作和设置。
|
# 按 双击 ⇧ 在所有地方搜索类、文件、工具窗口、操作和设置。
|
||||||
|
|
||||||
import parser
|
import parser
|
||||||
from validity_check import IllegalAtomException
|
import equation_solver
|
||||||
|
|
||||||
# 按间距中的绿色按钮以运行脚本。
|
# 按间距中的绿色按钮以运行脚本。
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
eq = input('请输入化学方程式:')
|
while True:
|
||||||
try:
|
eq = input('请输入化学方程式:')
|
||||||
print(parser.parse_equation(eq))
|
try:
|
||||||
except IllegalAtomException as e:
|
eq = parser.parse_equation(eq)
|
||||||
print(e.args[0])
|
equation_solver.solve_equation(eq)
|
||||||
|
print('化学方程式:', parser.format_equation(eq))
|
||||||
|
except Exception as e:
|
||||||
|
print(e.args[0])
|
||||||
|
|
||||||
# 访问 https://www.jetbrains.com/help/pycharm/ 获取 PyCharm 帮助
|
# 访问 https://www.jetbrains.com/help/pycharm/ 获取 PyCharm 帮助
|
||||||
|
|
24
parser.py
24
parser.py
|
@ -156,3 +156,27 @@ def parse_equation(eq):
|
||||||
'left': left,
|
'left': left,
|
||||||
'right': right
|
'right': right
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def format_molecule(molecule):
|
||||||
|
"""
|
||||||
|
化学式的字典表示转化为字符串
|
||||||
|
:param molecule: 化学式的字典表示
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
if molecule['coefficient'] != 1:
|
||||||
|
return str(molecule['coefficient']) + molecule['pretty_name']
|
||||||
|
else:
|
||||||
|
return molecule['pretty_name']
|
||||||
|
|
||||||
|
def format_equation(eq):
|
||||||
|
"""
|
||||||
|
将化学方程式的字典表示转化为字符串,需要包含系数
|
||||||
|
:param eq: 化学方程式的字典表示
|
||||||
|
:return: 化学方程式的字符串表示
|
||||||
|
"""
|
||||||
|
left = eq['left']
|
||||||
|
right = eq['right']
|
||||||
|
left = [format_molecule(molecule) for molecule in left]
|
||||||
|
right = [format_molecule(molecule) for molecule in right]
|
||||||
|
return ' + '.join(left) + ' => ' + ' + '.join(right)
|
|
@ -0,0 +1,2 @@
|
||||||
|
numpy~=1.23.5
|
||||||
|
scipy~=1.9.3
|
Loading…
Reference in New Issue