生肉-待完善
This commit is contained in:
parent
12df1e8d57
commit
9eee646100
|
@ -10,5 +10,6 @@
|
|||
<component name="PyDocumentationSettings">
|
||||
<option name="format" value="PLAIN" />
|
||||
<option name="myDocStringFormat" value="Plain" />
|
||||
<option name="renderExternalDocumentation" value="true" />
|
||||
</component>
|
||||
</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):
|
||||
"""
|
||||
配平化学方程式,返回配平后的化学方程式
|
||||
|
@ -15,12 +21,94 @@ def solve_equation(eq):
|
|||
:return: 配平后的化学方程式,与输入格式相同
|
||||
若无法配平,则返回 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
|
||||
from validity_check import IllegalAtomException
|
||||
import equation_solver
|
||||
|
||||
# 按间距中的绿色按钮以运行脚本。
|
||||
if __name__ == '__main__':
|
||||
eq = input('请输入化学方程式:')
|
||||
try:
|
||||
print(parser.parse_equation(eq))
|
||||
except IllegalAtomException as e:
|
||||
print(e.args[0])
|
||||
while True:
|
||||
eq = input('请输入化学方程式:')
|
||||
try:
|
||||
eq = parser.parse_equation(eq)
|
||||
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 帮助
|
||||
|
|
24
parser.py
24
parser.py
|
@ -156,3 +156,27 @@ def parse_equation(eq):
|
|||
'left': left,
|
||||
'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