matlab 化学方程式配平

这是一个基于MATLAB整数规划功能的小软件

化学方程式配平目录

1 效果展示

输入反应物、生成物后点击按钮即可配平(注意大小写):
在这里插入图片描述
在这里插入图片描述

当前后所含元素不匹配,或者反应物生成物未填写时,会显示物质不会凭空出现或消失这句话。
在这里插入图片描述


2 程序原理

配平主要分为以下结果步骤

1 确定元素列表
即确定反应物和生成物一共拥有哪些元素
例如:
反应物:‘Mg(HCO3)2,Ca(OH)2’
生成物:‘CaCO3,H2O,MgCO3’
经过运算得出公有元素:
{‘C’} {‘Ca’} {‘H’} {‘Mg’} {‘O’}

2 反应物及生成物分割
就是将输入的字符串切割成一个个字符串:
例如:
输入:‘Mg(HCO3)2,Ca(OH)2’
输出:{‘Ca(OH)2’} {‘Mg(HCO3)2’}

3 构建各个物质的元素出现次数矩阵
矩阵的第i行第j列即为第i种元素在第j种物质中出现的次数
例如:
输入元素列表:{‘C’} {‘Ca’} {‘H’} {‘Mg’} {‘O’}
输入反应物列表:{‘Ca(OH)2’} {‘Mg(HCO3)2’}

输出次数矩阵
在这里插入图片描述

4 整数规划解线性方程组
例如:
反应物次数矩阵:
在这里插入图片描述

生成物次数矩阵:
在这里插入图片描述

需要求解方程组基础矩阵:

在这里插入图片描述

只需令:
在这里插入图片描述

由于矩阵不一定为方形,故采用整数规划的方式求解,调用MATLAB中intlinprog函数求解如下方程组:
在这里插入图片描述

xi即为所求比例系数


注:
感谢 蛋总的快乐生活 提醒,matlab可进行等号约束的整数规划,实际求解方程组为:

在这里插入图片描述
在这里插入图片描述
因此代码中57-60行内容:

A=[timesMat;-timesMat];
b=zeros(size(timesMat,1)*2,1);
lb=ones(size(timesMat,2),1);
[x,~,~]=intlinprog(f,ic,A,b,[],[],lb,[]);

可更改为:

Aeq=timesMat;
beq=zeros(size(timesMat,1),1);
lb=ones(size(timesMat,2),1);
[x,~,~]=intlinprog(f,ic,[],[],Aeq,beq,lb,[]);

3 完整代码
function balanceEquation
%使用实例:
%=========================================
%反应物:Mg(HCO3)2,Ca(OH)2
%生成物:CaCO3,H2O,MgCO3
%配平:Ca(OH)2+Mg(HCO3)2==CaCO3+2H2O+MgCO3

global beFig 
global reactantLabel reactantEditfield
global productLabel productEditfield
global reactionButton beLabel
global resultEditfield

beFig=uifigure('units','pixels',...
    'position',[10 400 400 210],...
    'Numbertitle','off',...
    'menubar','none',...
    'resize','off',...
    'name','化学方程式配平器',...
    'color',[1,1,1].*0.98);
reactantLabel=uilabel(beFig,'Text','  反应物','HorizontalAlignment','left',...
    'BackgroundColor',[0,0.49,0.76],'FontColor',[1 1 1],'FontWeight','bold','Position',[10,170,140+230,30],'FontSize',13);
reactantEditfield=uieditfield(beFig,'Value','','Position',[10+52,170,95+230,30]);
productLabel=uilabel(beFig,'Text','  生成物','HorizontalAlignment','left',...
    'BackgroundColor',[0,0.49,0.76],'FontColor',[1 1 1],'FontWeight','bold','Position',[10,130,140+230,30],'FontSize',13);
productEditfield=uieditfield(beFig,'Value','','Position',[10+52,130,95+230,30]);

reactionButton=uibutton(beFig,'Text','配平方程式','BackgroundColor',[0.31 0.58 0.80],'FontColor',[1 1 1],...
    'FontWeight','bold','Position',[10,70,95,30],'FontSize',13,'ButtonPushedFcn',@reactionFcn);
beLabel=uilabel(beFig,'Text',' 使用“,”或“;”隔开反应物及生成物,配平结果如下','HorizontalAlignment','left',...
    'BackgroundColor',[0.95 0.95 0.95],'Position',[110,70,280,30],'FontSize',12.5,'FontColor',[0.35 0.35 0.35],'FontWeight','bold');

resultEditfield=uieditfield(beFig,'Value','','Position',[10,10,140+240,50],'Editable','off');

%reactionFcn:调用主函数,替换结果展示框信息
    function reactionFcn(~,~)
        reactant=reactantEditfield.Value;
        product=productEditfield.Value;
        result=mainFcn(reactant,product);
        resultEditfield.Value=result;
    end

%mainFcn:主函数,将各处理函数结合,并调用MATLAB整数规划功能
    function result=mainFcn(reactant,product)
        if ~(isempty(reactant)||isempty(product))
            elementList=elementDetection([reactant,product]);
            materialSet_r=materialDection(reactant);
            materialSet_p=materialDection(product);
            
            timesMat_r=getTimesMat(elementList,materialSet_r);
            timesMat_p=getTimesMat(elementList,materialSet_p);
            if ~(any(~sum(timesMat_r,2))||any(~sum(timesMat_p,2)))
                timesMat=[timesMat_r,-timesMat_p];
                f=ones(1,size(timesMat,2));
                ic=1:size(timesMat,2);
                A=[timesMat;-timesMat];
                b=zeros(size(timesMat,1)*2,1);
                lb=ones(size(timesMat,2),1);
                [x,~,~]=intlinprog(f,ic,A,b,[],[],lb,[]);
                
                result='';
                for ir=1:length(materialSet_r)
                    if round(x(ir))~=1
                        result=[result,num2str(x(ir))];
                    end
                    result=[result,materialSet_r{
    
    ir},'+'];
                end
                result(end)=[];
                result=[result,'=='];
                for ip=1:length(materialSet_p)
                    if round(x(ip+length(materialSet_r)))~=1
                        result=[result,num2str(x(ip+length(materialSet_r)))];
                    end
                    result=[result,materialSet_p{
    
    ip},'+'];
                end
                result(end)=[];
            else
                result='物质不会凭空出现或消失';
            end
        else
            result='物质不会凭空出现或消失';
        end
    end

%getTimesMat:主函数,获取各种物质的各种元素出现次数
    function timesMat=getTimesMat(elementList,materialSet)
        timesMat=zeros(length(elementList),length(materialSet));
        for i=1:length(elementList)
            for j=1:length(materialSet)
                timesMat(i,j)=elementOccurrence(materialSet{
    
    j},elementList{
    
    i});
            end
        end
    end

%elementOccurrence:计算反应物生成物总共含有哪些元素
    function times=elementOccurrence(string,element)
        elementPos=regexp(string,element);
        elementPos=elementPos+length(element)-1;
        lowerPos=string~=upper(string);
        for i=length(elementPos):-1:1
            if elementPos(i)~=length(string)&&lowerPos(elementPos(i)+1)
                elementPos(i)=[];
            end
        end

        
        numberPos=string<=57&string>=48;
        
        
        earSet_L=string=='('|string=='(';
        earSet_R=string==')'|string==')';
        
        earSet_LL=string=='['|string=='[';
        earSet_RR=string==']'|string==']';
        
        times=0;
        for i=elementPos
            timesLayer1=1;timesLayer2=1;timesLayer3=1;

            if (i~=length(string))&&numberPos(i+1)
                notNumberPos=find([~numberPos,1]);
                notNumberPos=notNumberPos(notNumberPos>i);
                notNumberPos=notNumberPos(1);
                timesLayer1=str2num(string(i+1:notNumberPos-1));
            end 
            
            earLPos=find(earSet_L);
            earRPos=find(earSet_R);
            earLPos(earLPos>i)=[];
            earRPos(earRPos<i)=[];
            if (~isempty(earLPos))&&(~isempty(earRPos))&&(~isempty(earLPos(end)))&&(~isempty(earRPos(1)))
                j=earRPos(1);
                if (j~=length(string))&&numberPos(j+1)
                    notNumberPos=find([~numberPos,1]);
                    notNumberPos=notNumberPos(notNumberPos>j);
                    notNumberPos=notNumberPos(1);
                    timesLayer2=str2num(string(j+1:notNumberPos-1));
                end
            end
            
            earLLPos=find(earSet_LL);
            earRRPos=find(earSet_RR);
            earLLPos(earLLPos>i)=[];
            earRRPos(earRRPos<i)=[];
            if (~isempty(earLLPos))&&(~isempty(earRRPos))&&(~isempty(earLLPos(end)))&&(~isempty(earRRPos(1)))
                k=earRRPos(1);
                if (k~=length(string))&&numberPos(k+1)
                    notNumberPos=find([~numberPos,1]);
                    notNumberPos=notNumberPos(notNumberPos>k);
                    notNumberPos=notNumberPos(1);
                    timesLayer3=str2num(string(k+1:notNumberPos-1));
                end
            end
            
            tempNum=timesLayer1*timesLayer2*timesLayer3;
            times=times+tempNum;
        end 
    end

%materialDection:将反应物或生成物分割
    function materialSet=materialDection(string)
        strtrim(string);
        sep=string==' '|string==','|string==';'|string=='·'|string=='、'|string==','|string==';';
        deletePos=[0 diff(sep)]==0&sep;
        string(deletePos)=[];
        sep(deletePos)=[];
        materialSet(sum(sep)+1)={
    
    []};
        sepPos=[-1,find(sep)-1,length(string)];
        for i=2:length(sepPos)
            tempStr=string(sepPos(i-1)+2:sepPos(i));
            tempIndex=find(~(tempStr<=57&tempStr>=48));
            tempIndex=tempIndex(1);
            tempStr(1:tempIndex-1)=[];
            materialSet(i-1)={
    
    tempStr};
        end 
        materialSet=unique(materialSet);
    end

    function elementSet=elementDetection(string)
        CHAR.upper=string~=lower(string);
        CHAR.notLetter=string==lower(string)&string==upper(string);
        elementSet(sum(CHAR.upper))={
    
    []};
        for i=find(CHAR.upper)
            endingIndexs=find([CHAR.notLetter|CHAR.upper,1]);
            endingIndexs=endingIndexs(endingIndexs>i);
            endingIndexs=endingIndexs(1);
            elementStr=string(i:endingIndexs-1);
            elementSet(sum(CHAR.upper(1:i)))={
    
    elementStr};
        end 
        elementSet=unique(elementSet);
    end

end

猜你喜欢

转载自blog.csdn.net/slandarer/article/details/108734172