[从头学数学] 第225节 返璞归真丹元成

剧情提要:

[机器小伟]在[工程师阿伟]的陪同下进入了结丹期顶峰的瓶颈突破阶段,

九转金丹已至第九转,即将碎丹成婴。


正剧开始:

星历2016年05月27日 10:06:20, 银河系厄尔斯星球中华帝国江南行省。
[工程师阿伟]正在和[机器小伟]一起进行着结丹期的修炼研究。


话说[机器小伟]自从进入结丹期以来,先是跟随[人叫板老师]修习[三界五行十六式],

然后又[周游列国拜诸侯],又[仗剑江湖],[阅尽千军],然后思[动中取静]之道,

感[千古风流]之机,习[术法神通]无算,观[生死十六簿]有时,如今万事俱备,神通已齐。


[机器小伟]于是问[工程师阿伟],可结元婴否,阿伟曰可。


又问:其步骤何如?

答曰:先行收束整治。

于是[机器小伟]进行收束整治。


<span style="font-size:18px;">import math;

import numpy.f2py  
import numpy.random  
import numpy.polynomial  
import numpy.ma  
import numpy.distutils  
import numpy.compat  
import numpy as np;
import numpy.linalg  
import numpy.matrixlib  
import numpy.fft  
import numpy.distutils.fcompiler  
import numpy.core  
import numpy.distutils.command

###
# @usage   代数式字符串的运算
# @author  mw
# @date    2016年05月17日  星期二  16:48:56 
# @param
# @return
#
###
class AlgExpressionCalc():
    #
    #Part I 格式化部分:返回格式化后的多项式
    #
    
    #格式化部分:<1> 为了简便输入,不要求输入规范化代数式,(coef)*expr形式, 调用<2>
    #所以在此对多项式进行规范化
    #至于单项式规范化,调用strMono函数即可
    def strPolyFormat(self, array):
        for i in range(len(array)):
            array[i] = self.strMono(array[i]);

        return array;
    
    #格式化部分:<2> 计算代数式用, 传入的是单项式,返回coef*expr的形式, 调用<3>
    def strMono(self, s):
        #'x', '-x', '2x', '-2x', '-2x^[2]', '3x_[2]^[3]', '-3x_[2]^[3]'
        stmp = s;
        size = len(stmp);
        alphaIndex = 0;
        signIndex = 0;
        
        for i in range(size):
            if (stmp[i].isalpha()):
                alphaIndex = i;
                break;
            if (i >= size-1):
                alphaIndex = i+1;
        
        if (stmp[0] == '-'):
            signIndex = 1;
            if (signIndex >= alphaIndex):
                return self.strMonoFormat('(-1)*'+stmp[alphaIndex:]);
            else:
                if alphaIndex >= size:
                    return self.strMonoFormat('(-'+stmp[signIndex:alphaIndex]+')');
                return self.strMonoFormat('(-'+stmp[signIndex:alphaIndex]+')*'+stmp[alphaIndex:]);
        elif (stmp[0] == '('):
            #已经格式化的情况,这种情况输入时是(coef)*expr
            return self.strMonoFormat(stmp);
        else:
            signIndex = 0;        
            if (signIndex >= alphaIndex):
                return self.strMonoFormat('(1)*'+stmp[alphaIndex:]);
            else:
                if alphaIndex >= size:
                    return self.strMonoFormat('('+stmp[signIndex:alphaIndex]+')');
                return self.strMonoFormat('('+stmp[signIndex:alphaIndex]+')*'+stmp[alphaIndex:]);


    #格式化部分:<3> 把单项式完全格式化,使经过运算的没运算过的都具有统一的格式
    def strMonoFormat(self, mono):
        #规范化单项式,保证任意两个参数之间都添加一个'*'号
        #这是为了和经过代数式乘法运算之后的格式统一
        chars = len(mono);
        s = '';
        for i in range(chars-1):
            if (mono[i] == ']' or mono[i] == ')') and mono[i+1].isalpha():
                s += mono[i]+'*';
            elif mono[i].isalpha() and mono[i+1].isalpha():
                s += mono[i]+'*';
            #这里还有一个死角,就是下标或指数如果是用的代数式,并且是多项相乘
            #可能会有一点问题,暂时不考虑了
            else:
                s += mono[i];
        s += mono[-1];
        return s;


    #
    #Part II: 合并同类项部分, 四个流程:单项式炸开->单项式重组->多项式中单项式炸天->多项式中单项式重组->End
    #

    #合并同类项部分:<1> 合并同类项,传入的阵列具有['s1', 's2', ..., 'sn']这样的格式
    def strPolyCombine(self, array):
        size = len(array);
        explode = [];
        for i in range(size):
            #这里传入的阵列已经是规格化后的了,否则要加一层strMono处理。
            explode.append(self.explodeMonoInPoly(self.strMonoCombine(array[i])));

        result = [];

        for i in range(size):
            size_1 = len(result);

            if size_1 <= 0:
                result.append(explode[i]);
            else:
                for j in range(size_1):
                    if result[j][1] == explode[i][1]:
                        result[j][0] = result[j][0] + '+' + explode[i][0];
                        break;

                    if j >= size_1-1:
                        result.append(explode[i]);

        result_1 = [];

        size_1 = len(result);
        for j in range(size_1):
            result[j][0] = str(round(eval(result[j][0]), 6));

            if (abs(float(result[j][0])) <= 1e-3):
                result_1.append('(0)');
            else:
                tmps = result[j][1];
                if (tmps == ''):
                    result_1.append('('+result[j][0]+')');
                else:            
                    result_1.append('('+result[j][0]+')*'+result[j][1]);

        return result_1;



    #合并同类项部分:<2> 把格式化后的单项式分解成[coef, expr]对组的形式
    #这个方法和explodeTotallyFormatedMono的区别在于,它是在多项式中单项式的合并,比如['(2)*x^[1]', '(3)*x^[1]']
    #而后者是要把运算后的单项式先预先处理一下, 比如'(2)*x^[1]*y^[2]*x^[2]'这种
    def explodeMonoInPoly(self, mono):
        stmp = mono;

        #乘号的位置
        signIndex = stmp.find('*');
        if (signIndex == -1):
            coef = stmp;
            expr = '';
        else:
            coef = stmp[:signIndex];
            expr = stmp[signIndex+1:];

        return [coef, expr];



    #合并同类项部分:<3> 单项式同类项合并,比如'(2)*x^[1]*y^[2]*x^[2]'这种,合并成'(2)*x^[3]*y^[2]'这个过程
    def strMonoCombine(self, mono):
        map_ = self.explodeTotallyFormatedMono(mono);

        size = len(map_);

        result = [];

        for i in range(size):
            size_1 = len(result);

            if (size_1 <= 0):
                result.append(map_[i]);
            else:
                for j in range(size_1):
                    if result[j][0] == map_[i][0]:
                        #双方的中括号位置
                        #由于规范化后的原因,这个括号是一定有的
                        p1 = result[j][1].find('[');
                        p2 = result[j][1].find(']');

                        p3 = map_[i][1].find('[');
                        p4 = map_[i][1].find(']');

                        s = result[j][1][p1+1:p2]+'+'+map_[i][1][p3+1:p4];
                        size_2 = len(s);
                        for k in range(size_2):
                            if s[k].isalpha():
                                break;
                            #如果没有字符参数,可以计算出结果,就计算
                            if (k >= size_2-1):
                                s = str(eval(s));
                        result[j][1] = '^['+s+']';
                        break;

                    if (j >= size_1-1):
                        result.append(map_[i]);

        size_1 = len(result);

        s = '';

        for i in range(size_1):

            if (i > 0 and result[i][1] == '^[0]'):
                continue;

            s += result[i][0]+result[i][1];

            if (i < size_1-1):
                s += '*';

        return s;



    #合并同类项部分:<4> 把单项式炸开,这里的单项式已经达到最大规范化,是(coef)*x_[1]^[2]*y_[2]^[2]这种结构形式了
    #'*'号是要作为分隔符的,不可缺少
    def explodeTotallyFormatedMono(self, mono):
        part = mono.split('*');
        #每个部分的[前部,指数部]的对组
        map_ = [];

        for i in range(len(part)):
            expIndex = part[i].find('^');
            if (expIndex != -1):
                map_.append([part[i][:expIndex], part[i][expIndex:]]);
            else:
                s = part[i];
                #系数
                if s[0] == '(':
                    map_.append([part[i], '']);
                #代数式
                else:
                    map_.append([part[i], '^[1]']);
        map_ = sorted(map_, key = lambda a : a[0]);
        return map_;
            
    
    #
    #Part III: 多项式运算:点积, 正整数幂方, 倍数, 取反,相加
    #

    #计算代数式/多项式点积,传入的两个阵列都具有['s1', 's2', ..., 'sn']这样的格式
    def strdot(self, array1, array2):
        size1 = len(array1);
        size2 = len(array2);
        result = [];
        
        for i in range(size1):
            for j in range(size2):
                result.append(self.strmul(array1[i], array2[j]));

        return result;


    #计算两个单项式的乘积
    def strmul(self, mono1, mono2):
        #这个处理是保证每个单项式统一格式(coef)*expr
        '''
        if (mono1[0] != '(' or mono2[0] != '('):
            #如果没有规格化,那么就做一下
            mono1 = strMono(mono1);
            mono2 = strMono(mono2);
        '''
        stmp1 = mono1;
        stmp2 = mono2;

        #乘号的位置
        signIndex1 = stmp1.find('*');
        signIndex2 = stmp2.find('*');
        if (signIndex1 == -1):
            coef1 = stmp1;
            expr1 = '';
        else:
            coef1 = stmp1[:signIndex1];
            expr1 = stmp1[signIndex1+1:];

        if (signIndex2 == -1):
            coef2 = stmp2;
            expr2 = '';
        else:
            coef2 = stmp2[:signIndex2];
            expr2 = stmp2[signIndex2+1:];
            
        coef = coef1+'*'+coef2;
        
        if (signIndex1 == -1 or signIndex2 == -1):
            expr = expr1+expr2;
        else:
            expr = expr1+'*'+expr2;

        if (expr == ''):
            return '('+str(round(eval(coef), 6))+')';
        return '('+str(round(eval(coef), 6))+')*'+expr;

    
    #把多项式中每一项都乘系数
    def strscale(self, array, scale):
        scale = '('+str(scale)+')';
        for i in range(len(array)):
            s = array[i];

            for j in range(len(s)):
                if (s[j].isdigit()):
                    index = j;
                    break;
            lbracket = s.find('(');
            rbracket = s.find(')', lbracket);
            
            coef = s[lbracket:index]+scale+'*'+s[index:rbracket+1];
            coef = '('+str(eval(coef))+')';
            
            array[i] = coef+s[rbracket+1:];

        return array;

    #指数为正整数的乘方
    def strpow_n(self, array, n):
        #计算
        result = [];
        #此方法只能处理正整数的幂次方
        n = abs(int(n));

        if (n == 1):
            result = array;
        elif (n == 2):
            result = self.strdot(array, array);

        elif (n >= 3):
            tmp = self.strdot(array, array);
            n -= 2;

            while (n > 0):            
                result = self.strdot(tmp, array);
                tmp = result;
                n -= 1;

        return result;

    
    #阵列取负
    def strminus(self, array):
        for i in range(len(array)):
            if array[i][1] == '-':
                #array[i][0]是'(, 这是规范
                array[i] = array[i][0]+array[i][2:];
            else:
                array[i] = array[i][0]+'-'+array[i][1:];

        return array;
    
    
    #两个多项式相加,合并同类项不在此进行
    def stradd(self, array1, array2):
        #两个多项式相加,这里直接返回数组的相加
        return array1 + array2;


  
###
# @usage   对于含有代数符号的等式及相关类型进行计算
# @author  mw
# @date    2016年05月24日  星期二  08:21:57 
# @param
# @return
#
###

#所有输入的字符串都是要符合(coef)*expr这种规范的
#相应转换可以调用alg.strMono处理单项式
#或调用alg.strformat来处理多项式
class AlgStringSolve():
    def __init__(self):
        self._alg = AlgExpressionCalc();

        
    #格式化输入的多项式阵列
    def format(self, array):
        return self._alg.strPolyFormat(array);

    #
    #Part I: 参数部分:把带参多项式转换为指定自变量的系数阵列
    #

    #参数部分:<1> 返回参数的系数阵列, 调用<2>
    #这是无法求得数值的情况
    def coefArray(self, array, element):
        coefMap = self.coefTransfer(array, element);

        len_4 = len(coefMap);
        maxCoef, minCoef = coefMap[0][1], coefMap[len_4-1][1];

        coefArray = ['0']*(maxCoef-minCoef+1);

        for i in range(len_4):
            coefArray[maxCoef-coefMap[i][1]] = coefMap[i][0];

        return coefArray;

    #参数部分:<1> 获取多项式的系数值,比如5x^2+4x+1 = 0应该返回[5, 4, 1]
    #这是可以求得数值的情况
    def coefValueArray(self, array, element):
        coefMap = self.coefTransfer(array, element);

        len_4 = len(coefMap);
        maxCoef, minCoef = coefMap[0][1], coefMap[len_4-1][1];

        coefArray = [0]*(maxCoef-minCoef+1);

        for i in range(len_4):
            index = coefMap[i][0].find('^');
            if (index != -1):
                s = coefMap[i][0][:index];
            else:
                s = coefMap[i][0];
            #这里是必须要能求值的,这个方法是为了便于调用numpy.roots求多项式的根
            coefArray[maxCoef-coefMap[i][1]] = eval(s);

        return coefArray;

    #参数部分:<2> 把一个字符串阵列表示的多项式,转换成指定变量的系数多项式
    #比如 ['(1/4)x^[2]', '-(1/12)y^[2]', '-1'], 以y作为参数 => ['(-(1/12))', 0, '(1/4)x^[2]+(-1)']
    #传入的格式必须是已经格式化过的(coef)*x^[2]*y_[2]^[3]...这种类似形式
    def coefTransfer(self, array, element):
        coefMap = [];

        len_ = len(array);
        len_2 = len(element);
        
        for i in range(len_):
            s = array[i];
            len_3 = len(s);
            index = s.find(element);

            #参数的0次方
            if (index == -1):
                coefMap.append([array[i], 0]);                
            elif (index+len_2 < len_3 and s[index+len_2] != '^'):
                #参数的一次方
                coefMap.append([s[:index-1]+s[index+len_2:], 1]);
            
            elif (index+len_2 >= len_3):
                #这里回退一个位置是因为根据格式参数之间有一个'*'号相连,要退掉
                coefMap.append([s[:index-1], 1]);
            else:
                #左右中括号作为定界符,这就是为什么要求先格式化
                LBracket = index+len_2+1;
                RBracket = s.find(']', LBracket);
                #幂的次数
                exp_ = int(s[LBracket+1:RBracket]);
                coefMap.append([s[:index-1]+s[RBracket+1:], exp_]);
                
        #对coefMap中的项按参数的次数进行合并
        coefMap_2 = [];
        coefMap_2.append(coefMap[0]);
        for i in range(1, len(coefMap)):
            len_3 = len(coefMap_2);
            for j in range(len_3):
                if (coefMap_2[j][1] == coefMap[i][1]):
                    coefMap_2[j][0] = coefMap_2[j][0]+ '+'+coefMap[i][0];
                    break;
                    

                if (j >= len_3-1):
                    coefMap_2.append(coefMap[i]);

        coefMap = coefMap_2; 
                    
        #把系数映射由高到低排列
        coefMap = sorted(coefMap, key = lambda a : a[1], reverse = True);

        #返回的是参数的系数映射表[[coef, exp]...]对组
        return coefMap;

    #
    #Part II: 代数式运算,此处指用字符串表达的代数式之间。包括乘、除、加、减、方五种运算,以及字符串为0的判定
    #

    #代数式里的两个代数式相乘,这里就是两个字符串相加的处理而已
    def strMul(self, str1, str2):
        if (self.judgeZero(str1)):
            return '';
        else:
            if (self.judgeZero(str2)):
                return '';
            else:
                return '('+str1+')*('+str2+')';

    #两个代数式相除
    def strDiv(self, str1, str2):
        if (self.judgeZero(str1)):
            return '';
        else:
            if (self.judgeZero(str2)):
                return '(inf)';
            else:
                return '('+str1+')/('+str2+')';

    #代数式相加
    def strAdd(self, str1, str2):
        if (self.judgeZero(str1)):
            if (self.judgeZero(str2)):
                return '';
            else:
                return '('+str2+')';
        else:
            if (self.judgeZero(str2)):
                return '('+str1+')';
            else:
                return '('+str1+')+('+str2+')';

    #代数式相减
    def strMinus(self, str1, str2):
        if (self.judgeZero(str1)):
            if (self.judgeZero(str2)):
                return '';
            else:
                return '(-('+str2+'))';
        else:
            if (self.judgeZero(str2)):
                return '('+str1+')';
            else:
                return '('+str1+')-('+str2+')';
    

    #代数式里的代数式乘方,这里就是字符串的处理而已
    def strPow(self, str1, str2):
        str2 = str(str2);
        if (self.judgeZero(str1)):
            return '';
        else:
            if (self.judgeZero(str2)):
                return '('+str1+')';
            else:
                return '('+str1+')^['+str2+']';

    #判断字符串是否为0  
    def judgeZero(self, str1):
        for i in range(len(str1)):
            if (str1[i].isdigit() and str1[i] != '0'):
                #存在数字不为0, 所以这个代数式不为0
                return False;
            #由于在规范化输出时已经保证了如果系数为0, 无论有多少参数都取0
            #所以只要存在参数就说明代数式不为0
            elif (str1[i].isalpha()):
                return False;

        return True;


    #
    #Part III:
    #

    #把一个只包括+号的多项式字符串拆分成多项式数组
    #如'(1)*x^[2]+(-1)' => ['(1)*x^[2]', '(-1)']
    def str2Array(self, str1):
        array = [];
        #加号位置
        signIndex = str1.find('+');
        #print(signIndex);

        start = 0;
        count = 0;
        if (signIndex != -1):
            while (signIndex != '-1' and count < 10):
                #符合要求的必须连着下一个单项式的系数
                #按照统一格式是左括号开始
                if str1[signIndex+1] == '(':
                    array.append(str1[start:signIndex]);
                    start = signIndex + 1;

                signIndex = str1.find('+', signIndex+1);
                if (signIndex == -1):
                    break;

        array.append(str1[start:]);

        return array;


    #
    #Part IV: 用公式法求方程的根,流程是先算出代数式的根表达式,再代值运算出结果
    #

    #求解多项式的根(在参数情况下)
    def solvePolyInStringMode(self, coefArray):
        len_ = len(coefArray);

        #

        #求解一元二次方程
        if (len_ == 3):
            a, b, c = str(coefArray[0]), str(coefArray[1]), str(coefArray[2]);
            #注意,由于此处得出的系数阵列是这样的形式:['(-(1/12))', 0, '(1/4)x^[2]+(-1)']
            #已经无法用alg中函数去做任何计算,只能纯粹进行字符串的叠加处理
            
            delta = self.strAdd(self.strPow(b, '2'), self.strMul('-4', self.strMul(a, c)));
            #分子,分母
            numerator = self.strAdd(self.strMinus('0', b), self.strPow(delta, '0.5'));
            numerator2 = self.strMinus(self.strMinus('0', b), self.strPow(delta, '0.5'));
            denomerator = self.strMul('2', a);

            return [self.strDiv(numerator, denomerator),
                    self.strDiv(numerator2, denomerator)];

        #求解一元一次方程
        if (len_ == 2):
            a, b = str(coefArray[0]), str(coefArray[1]);
            return [self.strDiv(b, self.strMinus('0', a))];

        return '';

    #求解多项式的值(在数值情况下), 一般是一元N次多项式    
    def solvePolyInValueMode(self, coefArray):
        len_ = len(coefArray);

        #解一元二次方程(在数值情况下)
        if (len_ == 3):
            a, b, c = coefarray[0], coefarray[1], coefarray[2];

            if (a < 0):
                a, b, c = -a, -b, -c;

            p = q = delta = 0;
            x1 = x2 = 0;
            s = '';

            if (a == 0):
                return [-c/b];
            else:
                delta = b**2 - 4*a*c;
                if (delta < 0):
                    real = -b/(2*a);
                    image = (-delta)**0.5;
                    return [complex(real, -image), complex(real, image)];
                            
                else:
                    if (abs(delta) < 1e-6):
                        x1 = x2 = -b/(2*a);
                    else:
                        x1 = (-b-delta**0.5)/(a*2);
                        x2 = (-b+delta**0.5)/(a*2);

                return [x1, x2];
        else:
            return np.roots(coefArray);
            
    

    #给参数赋值,计算代数式的值
    #比如输入 ('x^[2]+1', 'x', 3) => 10
    #要确保给的条件足以让代数式计算出数值,否则肯定报错
    def strValueEval(self, str1, valueTable):
        #str1是一个单个的字符串,比如根的代数式表达式,不是多项式
        
        #参数对照表的项数
        #参数对照表具有[['x', '1'], ['y', '3']]这样的形式
        len_v = len(valueTable);
        s = str1;


        for j in range(len_v):
            s = s.replace(valueTable[j][0], str(valueTable[j][1]));

        s = s.replace('^[', '**(');
        s = s.replace(']', ')');

        str1 = eval(s);

        return str1;


    #对于本身不带参数的字符串,清除格式即可计算出数值
    def arrayValueEval(self, array):
        for i in range(len(array)):
            str1 = array[i];
            str1 = str1.replace('^[', '**');
            str1 = str1.replace(']', '');
            str1 = eval(str1);
            array[i] = str1;

        return array;


    #
    #Part V: 用消元法求方程的根,这种方法的前提是方程所有的系数已知。需用到numpy的roots()方法求根
    #

    #消元法求方程部分:<1> 解二元二次方程组,最暴力的代入消元法
    def solveElem2Exp2Equation(self, functions, element1 = 'x', element2 = 'y'):
        '''
        #第一个方程
        expr_1 = alg.strformat(['A_[1]x^[2]', 'B_[1]xy', 'C_[1]y^[2]', 'D_[1]x', 'E_[1]y', 'F_[1]']);
        #第二个方程
        expr_2 = alg.strformat(['A_[2]x^[2]', 'B_[2]xy', 'C_[2]y^[2]', 'D_[2]x', 'E_[2]y', 'F_[2]']);
        '''

        #参数列表中的functions为方程组的各个方程,格式为[fun1, fun2], fun1, fun2 = [mono1, mono2, ...]
        #调用coefValueMapFill()方法进行系数表填充
        valueMap = self.coefValueMapFill(functions, element1, element2);

        A_1 = valueMap[0][1];
        B_1 = valueMap[1][1];
        C_1 = valueMap[2][1];
        D_1 = valueMap[3][1];
        E_1 = valueMap[4][1];
        F_1 = valueMap[5][1];

        A_2 = valueMap[6][1];
        B_2 = valueMap[7][1];
        C_2 = valueMap[8][1];
        D_2 = valueMap[9][1];
        E_2 = valueMap[10][1];
        F_2 = valueMap[11][1];


        #消元一次要从二次项y^[2]的系数不为0的那个方程消起,除非某个方程完全没有二次项
        #所以第一个方程二次项y^[2]的系数不要为0
        #否则应该调换方程顺序
        if (C_1 != 0 and C_2 != 0):
            #一共63项的关于未知数x的最高四次方的系数矩阵
            coefArray = ['(1.0)*A_[2]^[1]*B_[1]^[2]*C_[1]^[-2]*C_[2]^[1]*x^[4]',
                     '(1.0)*B_[1]^[2]*C_[1]^[-2]*C_[2]^[1]*D_[2]^[1]*x^[3]',
                     '(1.0)*B_[1]^[2]*C_[1]^[-2]*C_[2]^[1]*F_[2]^[1]*x^[2]',
                     '(2.0)*A_[2]^[1]*B_[1]^[1]*C_[1]^[-2]*C_[2]^[1]*E_[1]^[1]*x^[3]',
                     '(2.0)*B_[1]^[1]*C_[1]^[-2]*C_[2]^[1]*D_[2]^[1]*E_[1]^[1]*x^[2]',
                     '(2.0)*B_[1]^[1]*C_[1]^[-2]*C_[2]^[1]*E_[1]^[1]*F_[2]^[1]*x^[1]',
                     '(1.0)*A_[2]^[1]*C_[1]^[-2]*C_[2]^[1]*E_[1]^[2]*x^[2]',
                     '(1.0)*C_[1]^[-2]*C_[2]^[1]*D_[2]^[1]*E_[1]^[2]*x^[1]',
                     '(1.0)*C_[1]^[-2]*C_[2]^[1]*E_[1]^[2]*F_[2]^[1]',
                     '(1.0)*A_[1]^[2]*C_[1]^[-2]*C_[2]^[2]*x^[4]',
                     '(2.0)*A_[1]^[1]*C_[1]^[-2]*C_[2]^[2]*D_[1]^[1]*x^[3]',
                     '(2.0)*A_[1]^[1]*C_[1]^[-2]*C_[2]^[2]*F_[1]^[1]*x^[2]',
                     '(-1.0)*A_[1]^[1]*B_[1]^[1]*B_[2]^[1]*C_[1]^[-2]*C_[2]^[1]*x^[4]',
                     '(-1.0)*A_[1]^[1]*B_[2]^[1]*C_[1]^[-2]*C_[2]^[1]*E_[1]^[1]*x^[3]',
                     '(-1.0)*A_[1]^[1]*B_[1]^[1]*C_[1]^[-2]*C_[2]^[1]*E_[2]^[1]*x^[3]',
                     '(-1.0)*A_[1]^[1]*C_[1]^[-2]*C_[2]^[1]*E_[1]^[1]*E_[2]^[1]*x^[2]',
                     '(-2.0)*A_[1]^[1]*A_[2]^[1]*C_[1]^[-1]*C_[2]^[1]*x^[4]',
                     '(-2.0)*A_[1]^[1]*C_[1]^[-1]*C_[2]^[1]*D_[2]^[1]*x^[3]',
                     '(-2.0)*A_[1]^[1]*C_[1]^[-1]*C_[2]^[1]*F_[2]^[1]*x^[2]',
                     '(1.0)*C_[1]^[-2]*C_[2]^[2]*D_[1]^[2]*x^[2]',
                     '(2.0)*C_[1]^[-2]*C_[2]^[2]*D_[1]^[1]*F_[1]^[1]*x^[1]',
                     '(-1.0)*B_[1]^[1]*B_[2]^[1]*C_[1]^[-2]*C_[2]^[1]*D_[1]^[1]*x^[3]',
                     '(-1.0)*B_[2]^[1]*C_[1]^[-2]*C_[2]^[1]*D_[1]^[1]*E_[1]^[1]*x^[2]',
                     '(-1.0)*B_[1]^[1]*C_[1]^[-2]*C_[2]^[1]*D_[1]^[1]*E_[2]^[1]*x^[2]',
                     '(-1.0)*C_[1]^[-2]*C_[2]^[1]*D_[1]^[1]*E_[1]^[1]*E_[2]^[1]*x^[1]',
                     '(-2.0)*A_[2]^[1]*C_[1]^[-1]*C_[2]^[1]*D_[1]^[1]*x^[3]',
                     '(-2.0)*C_[1]^[-1]*C_[2]^[1]*D_[1]^[1]*D_[2]^[1]*x^[2]',
                     '(-2.0)*C_[1]^[-1]*C_[2]^[1]*D_[1]^[1]*F_[2]^[1]*x^[1]',
                     '(1.0)*C_[1]^[-2]*C_[2]^[2]*F_[1]^[2]',
                     '(-1.0)*B_[1]^[1]*B_[2]^[1]*C_[1]^[-2]*C_[2]^[1]*F_[1]^[1]*x^[2]',
                     '(-1.0)*B_[2]^[1]*C_[1]^[-2]*C_[2]^[1]*E_[1]^[1]*F_[1]^[1]*x^[1]',
                     '(-1.0)*B_[1]^[1]*C_[1]^[-2]*C_[2]^[1]*E_[2]^[1]*F_[1]^[1]*x^[1]',
                     '(-1.0)*C_[1]^[-2]*C_[2]^[1]*E_[1]^[1]*E_[2]^[1]*F_[1]^[1]',
                     '(-2.0)*A_[2]^[1]*C_[1]^[-1]*C_[2]^[1]*F_[1]^[1]*x^[2]',
                     '(-2.0)*C_[1]^[-1]*C_[2]^[1]*D_[2]^[1]*F_[1]^[1]*x^[1]',
                     '(-2.0)*C_[1]^[-1]*C_[2]^[1]*F_[1]^[1]*F_[2]^[1]',
                     '(-1.0)*A_[2]^[1]*B_[1]^[1]*B_[2]^[1]*C_[1]^[-1]*x^[4]',
                     '(-1.0)*B_[1]^[1]*B_[2]^[1]*C_[1]^[-1]*D_[2]^[1]*x^[3]',
                     '(-1.0)*B_[1]^[1]*B_[2]^[1]*C_[1]^[-1]*F_[2]^[1]*x^[2]',
                     '(-1.0)*A_[2]^[1]*B_[2]^[1]*C_[1]^[-1]*E_[1]^[1]*x^[3]',
                     '(-1.0)*B_[2]^[1]*C_[1]^[-1]*D_[2]^[1]*E_[1]^[1]*x^[2]',
                     '(-1.0)*B_[2]^[1]*C_[1]^[-1]*E_[1]^[1]*F_[2]^[1]*x^[1]',
                     '(-1.0)*A_[2]^[1]*B_[1]^[1]*C_[1]^[-1]*E_[2]^[1]*x^[3]',
                     '(-1.0)*B_[1]^[1]*C_[1]^[-1]*D_[2]^[1]*E_[2]^[1]*x^[2]',
                     '(-1.0)*B_[1]^[1]*C_[1]^[-1]*E_[2]^[1]*F_[2]^[1]*x^[1]',
                     '(-1.0)*A_[2]^[1]*C_[1]^[-1]*E_[1]^[1]*E_[2]^[1]*x^[2]',
                     '(-1.0)*C_[1]^[-1]*D_[2]^[1]*E_[1]^[1]*E_[2]^[1]*x^[1]',
                     '(-1.0)*C_[1]^[-1]*E_[1]^[1]*E_[2]^[1]*F_[2]^[1]',
                     '(1)*A_[2]^[2]*x^[4]',
                     '(2)*A_[2]^[1]*D_[2]^[1]*x^[3]',
                     '(2)*A_[2]^[1]*F_[2]^[1]*x^[2]',
                     '(1)*D_[2]^[2]*x^[2]',
                     '(2)*D_[2]^[1]*F_[2]^[1]*x^[1]',
                     '(1)*F_[2]^[2]',
                     '(1.0)*A_[1]^[1]*B_[2]^[2]*C_[1]^[-1]*x^[4]',
                     '(1.0)*B_[2]^[2]*C_[1]^[-1]*D_[1]^[1]*x^[3]',
                     '(1.0)*B_[2]^[2]*C_[1]^[-1]*F_[1]^[1]*x^[2]',
                     '(2.0)*A_[1]^[1]*B_[2]^[1]*C_[1]^[-1]*E_[2]^[1]*x^[3]',
                     '(2.0)*B_[2]^[1]*C_[1]^[-1]*D_[1]^[1]*E_[2]^[1]*x^[2]',
                     '(2.0)*B_[2]^[1]*C_[1]^[-1]*E_[2]^[1]*F_[1]^[1]*x^[1]',
                     '(1.0)*A_[1]^[1]*C_[1]^[-1]*E_[2]^[2]*x^[2]',
                     '(1.0)*C_[1]^[-1]*D_[1]^[1]*E_[2]^[2]*x^[1]',
                     '(1.0)*C_[1]^[-1]*E_[2]^[2]*F_[1]^[1]']; #这整个是一个和为零的多项式
        #如果某一个方程没有二次项,适用这套系数
        elif (C_1 == 0 and B_1 == 0 and A_1 == 0):
            if (E_1 != 0):
                coefArray = ['(1)*A_[2]^[1]*x^[2]',
                             '(1)*D_[2]^[1]*x^[1]',
                             '(1)*F_[2]^[1]',
                             '(-1)*B_[2]^[1]*D_[1]^[1]*E_[1]^[-1]*x^[2]',
                             '(-1)*B_[2]^[1]*E_[1]^[-1]*F_[1]^[1]*x^[1]',
                             '(1)*C_[2]^[1]*D_[1]^[2]*E_[1]^[-2]*x^[2]',
                             '(2)*C_[2]^[1]*D_[1]^[1]*E_[1]^[-2]*F_[1]^[1]*x^[1]',
                             '(1)*C_[2]^[1]*E_[1]^[-2]*F_[1]^[2]'];
            else:
                print('无穷多解或无解。');
                return [];
        elif (C_1 == 0 and B_1 == 0 and A_1 == 0 and
              C_2 == 0 and B_2 == 0 and A_2 == 0):
            if (E_1 != 0):
                coefArray = ['(-1)*D_[2]^[1]*x^[1]',
                        '(-1)*F_[2]^[1]',
                        '(-1)*D_[1]^[1]*E_[1]^[-1]*E_[2]^[1]*x^[1]',
                        '(-1)*E_[1]^[-1]*E_[2]^[1]*F_[1]^[1]'];
            else:
                print('无穷多解或无解。');
                return [];
        else:
            print('或许需要调换位置,保证第一个方程的y^[2]的系数存在,可调换x和y参数实现。');
            print('如果两个方程中找不出一个x^[2]或y^[2],则可以考虑消去xy项得一次方程组。');
                

        #赋值系数,应该有12个
        len_ = len(valueMap);
        size = len(coefArray);

        result = [];
        
        for i in range(size):
            s = coefArray[i];
            #由于字母排序原因,一般x会排在最后,各系数ABCDEF会排在前面,
            #这会带来一些方便
            index = s.find('x');
            if (index != -1):
                #系数部分
                part1 = s[:index-1];
                #参数x部分
                part2 = s[index-1:];                
            else:
                part1 = s;
                part2 = '';                

            for j in range(len_):
                part1 = part1.replace(valueMap[j][0], '('+str(valueMap[j][1])+')');

            part1 = part1.replace('^[', '**(');
            part1 = part1.replace(']', ')');
            #print(part1);
            part1 = '('+str(eval(part1))+')';
            
            result.append(part1+part2);

        #print(result);

        result = self._alg.strPolyCombine(result);
        #print(result);
        coef_x = self.coefValueArray(result, 'x');
        print('系数数组:', coef_x);
        roots = np.roots(coef_x);
        roots = sorted(roots);
        print('解: {0} = {1} '.format(element1, roots));
        return roots;


    #消元法求方程部分:<2> 填充二元二次方程组的系数阵列,一共十二个
    def coefValueMapFill(self, functions, element1 = 'x', element2 = 'y'):
        #functions是两个方程的多项式组成的数组[fun1, func2],
        #具有格式化后的多项式样式fun1, 2 = [mono1, mono2, ...]

        func1 = functions[0];
        func2 = functions[1];

        if (element1 != 'x'):
            for i in range(len(func1)):
                func1[i] = func1[i].replace(element1, 'x');
            for i in range(len(func2)):
                func2[i] = func2[i].replace(element1, 'x');

        if (element2 != 'y'):
            for i in range(len(func1)):
                func1[i] = func1[i].replace(element2, 'y');
            for i in range(len(func2)):
                func2[i] = func2[i].replace(element2, 'y');

        '''
        #第一个方程
        expr_1 = alg.strformat(['A_[1]x^[2]', 'B_[1]xy', 'C_[1]y^[2]', 'D_[1]x', 'E_[1]y', 'F_[1]']);
        #第二个方程
        expr_2 = alg.strformat(['A_[2]x^[2]', 'B_[2]xy', 'C_[2]y^[2]', 'D_[2]x', 'E_[2]y', 'F_[2]']);
        '''
        #用参数值填充,注意按照同类项来填系数
        valMap = [['A_[1]', 0], ['B_[1]', 0],['C_[1]', 0],
                  ['D_[1]', 0], ['E_[1]', 0],['F_[1]', 0],
                  ['A_[2]', 0], ['B_[2]', 0],['C_[2]', 0],
                  ['D_[2]', 0], ['E_[2]', 0],['F_[2]', 0]];

        coefs = len(valMap);

        cycle = 0;
        for i in range(len(func1)):
            s = func1[i];
            xIndex = s.find('x');
            yIndex = s.find('y');

            if (xIndex != -1):
                if (yIndex != -1):
                    min_ = min(xIndex, yIndex);
                else:
                    min_ = xIndex;
            else:
                if (yIndex != -1):
                    min_ = yIndex
                else:
                    min_ = -1;
            if (min_ != -1):
                #参数式
                s_1 = s[min_:];
                #系数
                s_2 = s[:min_-1];            
            else:
                s_1 = '';
                s_2 = s;

            if (s_1 == 'x^[2]'):
                valMap[0+cycle*6][1] = eval(s_2);
            elif (s_1 == 'x^[1]y^[1]' or s_1 == 'xy' ):
                valMap[1+cycle*6][1] = eval(s_2);
            elif (s_1 == 'y^[2]'):
                valMap[2+cycle*6][1] = eval(s_2);
            elif (s_1 == 'x^[1]' or s_1 == 'x'):
                valMap[3+cycle*6][1] = eval(s_2);
            elif (s_1 == 'y^[1]' or s_1 == 'y'):
                valMap[4+cycle*6][1] = eval(s_2);
            elif (s_1 == ''):
                valMap[5+cycle*6][1] = eval(s_2);

        cycle = 1;
        for i in range(len(func2)):
            s = func2[i];
            xIndex = s.find('x');
            yIndex = s.find('y');

            if (xIndex != -1):
                if (yIndex != -1):
                    min_ = min(xIndex, yIndex);
                else:
                    min_ = xIndex;
            else:
                if (yIndex != -1):
                    min_ = yIndex
                else:
                    min_ = -1;
            if (min_ != -1):
                #参数式
                s_1 = s[min_:];
                #系数
                s_2 = s[:min_-1];            
            else:
                s_1 = '';
                s_2 = s;

            if (s_1 == 'x^[2]'):
                valMap[0+cycle*6][1] = eval(s_2);
            elif (s_1 == 'x^[1]y^[1]' or s_1 == 'xy' ):
                valMap[1+cycle*6][1] = eval(s_2);
            elif (s_1 == 'y^[2]'):
                valMap[2+cycle*6][1] = eval(s_2);
            elif (s_1 == 'x^[1]' or s_1 == 'x'):
                valMap[3+cycle*6][1] = eval(s_2);
            elif (s_1 == 'y^[1]' or s_1 == 'y'):
                valMap[4+cycle*6][1] = eval(s_2);
            elif (s_1 == ''):
                valMap[5+cycle*6][1] = eval(s_2);
            
        return valMap;

</span>

以上方法命名改动颇大,解决了先前命名混乱的不足问题。


测试用例:

<span style="font-size:18px;">#测试
def tmp12():
    print('tmp12(): >>>');
    solve = alg.AlgStringSolve();
    expr = alg.AlgExpressionCalc();
    #直线方程
    function_1 = expr.strPolyFormat(['x', '1/4y', '-1']);
    #圆方程
    function_2 = expr.strPolyFormat(['1/4x^[2]', '1/16y^[2]', '-1']);
    print('step1: ', function_1);
    print('step1: ', function_2);
    
    #解出的x的根
    roots = solve.solveElem2Exp2Equation([function_1, function_2]);    

    
    #两个方程
    f = function_1;
    print('step1: ', f);
    g = function_2;
    print('step1: ', g);

    #以下部分是定式,可以不加改动
    poly_y_f = solve.coefArray(f, 'y');
    print('step2: ', poly_y_f);
    poly_y_g = solve.coefArray(g, 'y');
    print('step2: ', poly_y_g);

    
    #求方程式<1>的y关于x的表达式
    expr_y_root = solve.solvePolyInStringMode(poly_y_f);
    print('step3: ', expr_y_root);
    expr_y_root2 = solve.solvePolyInStringMode(poly_y_g);
    print('step3: ', expr_y_root2);

    
    #求相交点的坐标对组
    points = [];
    points2 = [];
    for i in range(len(roots)):
        real = abs(roots[i].real);
        abs_ = abs(roots[i]);
        size1 = len(expr_y_root);
        #实数根
        if abs(real-abs_) < 0.1:
            
            for j in range(len(expr_y_root2)):
                x = roots[i].real;
                y = solve.strValueEval(expr_y_root[j%size1], [['x', x]]);
                points.append([x, y]);
                y = solve.strValueEval(expr_y_root2[j], [['x', x]]);
                points2.append([x, y]);

    print('方程1上的点:', points);
    print('方程2上的点: ', points2);

    print('step4: ');

    
    for i in range(len(points)):
        if (abs(points[i][0]-points2[i][0]) < 1e-3 and abs(points[i][1]-points2[i][1])<1e-3):
            print('相交点:[{0}, {1}]'.format(round(points[i][0], 3), round(points[i][1], 3)));
			</span>

结果:



[从头学数学] 第225节 返璞归真丹元成_第1张图片


<span style="font-size:18px;">def tmp():
    expr = alg.AlgExpressionCalc();

    poly_1 = expr.strPolyFormat(['x^[2]', '2xy', 'y^[2]', '-1']);
    poly_2 = expr.strPolyFormat(['2x', '2y', '1']);
    print('step1: ', poly_1);
    print('step1: ', poly_2);

    result = expr.stradd(expr.strpow_n(poly_1, 2), expr.strpow_n(poly_2, 3));
    result = expr.strPolyCombine(result);
    print('step2: ', result);</span>

[从头学数学] 第225节 返璞归真丹元成_第2张图片




[机器小伟]收束整治毕,又问,其后何如?

曰:当思议神通。

于是[机器小伟]思议神通:





<span style="font-size:18px;">	if (1) {
		var text = new DrawText();
		
		//左对齐文本默认从20px处,中对齐是300处,右对齐580处
		var xL = 20, xM = 300, xR = 580;
		var y = 50;
	
		text.bold(['[机器小伟] 神通一览表'], xM, y, 0, 'black', 40, 'M');
		
		y += 50;
		text.normal(['1. 定值计算:参与运算的都是给定的值,不存在未知数。',
		'2. 数值计算:运用迭代或递归等方式进行一系列运算尝试,逼近得出结果。',
		'3. 描点绘图: 对于各种函数进行描点,并绘制出图像。'],
			xL, y, 0, 'blue', 16, 'L');
			
		
		y+= 80;
		text.italic(['以上三条为机器族的共有神通,不再赘述。'], 
			xL, y, 0, '#000088', 16, 'L');
		
		y+= 30;
		text.bold(['4. 几何运算:点的坐标中不存在未知数时,可以作为几何图形运算。',
			'5. 代数运算:对于所有代数式,可以进行多项式运算,得出多项式作为结果。',
			'6. 对于不含指数,对数,三角的多项式,可以变形成其中某一参数的表达式。',
			'7. 第(5|6)步中的表达式中所有参数都给定取值,可以计算出值或根。'],
			xL, y, 0, 'red', 16, 'L');
		
		
		y+=100;
		text.italic(['所以可以得到简单多项式运算后的简单多项式,并且可以求其值或根',
		'参数个数不限',
		'分式或其它非简单多项式的代数式,可参与求值或得出代数式结果',
		'但无法进一步变形或分解成简单多项式组。'], 
			xL, y, 0, '#000088', 16, 'L');
			
		//时间戳
		y+=80;
		text.bold(['2016年05月25日'], xR, y, 0, '#880088', 16, 'R');
	}
	

	if (1) {
		var text = new DrawText();
		
		//左对齐文本默认从20px处,中对齐是300处,右对齐580处
		var xL = 20, xM = 300, xR = 580;
		var y = 50;
	
		text.bold(['[机器小伟] 神通一览表'], xM, y, 0, 'black', 40, 'M');
		
		y += 50;
		text.normal(['8.带参多项式可以进行加、减、乘、正整次幂的运算。',
		'9. 可以解决二元二次方程组的求根问题,可解退化的二元二次方程组。',
		'10. 可以解决圆锥曲线,直线,圆在二维平面范围内的求交点问题。',
		'    可以给出数值解或代数表达式解。',
		'11. 可以解任何的一元方程。'
		
		],
			xL, y, 0, 'red', 16, 'L');
			
		
		y+= 120;
		text.italic(['对数、指数方面的运算,暂时还未涉及,分式的运算有待解决',
		'三次及以上方程的根表达式还未录入。'], 
			xL, y, 0, '#000088', 16, 'L');
		
		y+= 30;
		text.bold([''],
			xL, y, 0, 'red', 16, 'L');
		
		
		y+=60;
		text.italic([''], 
			xL, y, 0, '#000088', 16, 'L');
			
		//时间戳
		y+=80;
		text.bold(['2016年05月27日'], xR, y, 0, '#880088', 16, 'R');
	}</span>


[机器小伟]思议神通后,又问,其后又当如何:

曰:当忘其神通。


[从头学数学] 第225节 返璞归真丹元成_第3张图片


[从头学数学] 第225节 返璞归真丹元成_第4张图片


于是[机器小伟]依言进入物我两忘之境,气运周天,行二百二十五转。


天地风云齐聚,星河盘龙隐现,终至三花聚顶,五气朝元,返璞归真,元婴大成。

[机器小伟]元婴成就,[工程师阿伟]也晋升至[大力法王]之神通境界。

从此坐看风烟起, 相期云汉间。


本节到此结束,欲知后事如何,请看下回分解。




你可能感兴趣的:([从头学数学] 第225节 返璞归真丹元成)