当系数未知但仍然是实数时,如何在 Python 中求解线性方程组

问题描述

我不是程序员,所以请放轻松!我有一个由 4 个线性方程和 4 个未知数组成的系统,我认为我可以使用 python 相对轻松地解决这些问题。然而,我的方程不是“5x+2y+zw=0”形式的,而是我有代数常数 c_i,我不知道它的显式数值,例如“c_1 x + c_2 y + c_3 z+ c_4w=c_5”将是一个我的四个方程。那么是否存在根据 c_i 给出 x,y,z,w 答案的求解器?

解决方法

Numpy 有一个函数可以解决这个问题:numpy.linalg.solve

要构建矩阵,我们首先需要消化字符串,将其转换为系数和解的数组。

找数字

首先我们需要编写一个函数,它接受一个像 "c_1 3" 这样的字符串并返回数字 3.0。根据您在输入字符串中所需的格式,您可以遍历此数组中的所有字符并在找到非数字字符时停止,或者您可以简单地拆分空格并解析第二个字符串。以下是两种解决方案:

def find_number(sub_expr):

    """
    Finds the number from the format
    number*string or numberstring.

    Example:
    3x -> 3
    4*x -> 4
    """

    num_str = str()

    for char in sub_expr:
        if char.isdigit():
            num_str += char
        else:
            break

    return float(num_str)

或更简单的解决方案

def find_number(sub_expr):
    """
    Returns the number from the format "string number"
    """
    return float(sub_expr.split()[1])

注意:查看编辑

获取矩阵

现在我们可以使用它来将每个表达式分成两部分:解和由“=”组成的方程。然后方程被“+”分割成子表达式这样我们就可以把字符串“3x+4y = 3”变成

sub_expressions = ["3x","4y"]
solution_string = "3"

然后需要将每个子表达式输入到我们的 find_numbers 函数中。最终结果可以附加到系数和解矩阵:

def get_matrices(expressions):

    """
    Returns coefficient_matrix and solutions from array of string-expressions.
    """

    coefficient_matrix = list()
    solutions = list()

    last_len = -1

    for expression in expressions:

        # Note: In this solution all coefficients must be explicitely noted and must always be in the same order.
        # Could be solved with dicts but is probably overengineered.

        if not "=" in expression:
            print(f"Invalid expression {expression}. Missing \"=\"")
            return False

        try:
            c_string,s_string = expression.split("=")

            c_strings = c_string.split("+")
            solutions.append(float(s_string))

            current_len = len(c_strings)

            if last_len != -1 and current_len != last_len:
                print(f"The expression {expression} has a mismatching number of coefficients")
                return False

            last_len = current_len

            coefficients = list()

            for c_string in c_strings:
                coefficients.append(find_number(c_string))

            coefficient_matrix.append(coefficients)


        except Exception as e:
            print(f"An unexpected Runtime Error occured at {coefficient}")
            print(e)
            exit()

    return coefficient_matrix,solutions

现在让我们编写一个简单的 main 函数来测试这段代码:

# This is not the code you want to copy-paste
# Look further down.
from sys import argv as args

def main():
    expressions = args[1:]

    matrix,solutions = get_matrices(expressions)

    for row in matrix:
        print(row)

    print("")
    print(solutions)

if __name__ == "__main__":
    main()

让我们在控制台中运行程序!

user:$ python3 solve.py 2x+3y=4 3x+3y=2
[2.0,3.0]
[3.0,3.0]

[4.0,2.0]

您可以看到程序正确识别了我们所有的号码

再次:使用适合您的格式的 find_number 函数

拼凑起来

这些矩阵现在只需要直接注入 numpy 函数即可:

# This is the main you want
from sys import argv as args
from numpy.linalg import solve as solve_linalg

def main():
    expressions = args[1:]

    matrix,solutions = get_matrices(expressions)

    coefficients = solve_linalg(matrix,solutions)

    print(coefficients)

# This bit needs to be at the very bottom of your code to load all functions first.
# You could just paste the main-code here,but this is considered best-practice
if __name__ == '__main__':
    main()

现在让我们测试一下:

$ python3 solve.py x*2+y*4+z*0=20 x*1+y*1+z*-1=3 x*2+y*2+z*-3=3
[2. 4. 3.]

如您所见,该程序现在为我们解决了这些功能。

出于好奇:数学作业?这感觉就像数学作业。

编辑:出于纯粹的运气,在所有测试中都解决了拼写错误“c_string”而不是“c_strings”。

编辑 2:经过进一步检查,我建议用“*”分割子表达式:

def find_number(sub_expr):
    """
    Returns the number from the format "string number"
    """
    return float(sub_expr.split("*")[1])

这导致相当可读的输入字符串