Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
212 views
in Technique[技术] by (71.8m points)

How to solve a Linear System of Equations in Python When the Coefficients are Unknown (but still real numbers)

Im not a programer so go easy on me please ! I have a system of 4 linear equations and 4 unknowns, which I think I could use python to solve relatively easily. However my equations not of the form " 5x+2y+z-w=0 " instead I have algebraic constants c_i which I dont know the explicit numerical value of, for example " c_1 x + c_2 y + c_3 z+ c_4w=c_5 " would be one my four equations. So does a solver exist which gives answers for x,y,z,w in terms of the c_i ?

question from:https://stackoverflow.com/questions/66050505/how-to-solve-a-linear-system-of-equations-in-python-when-the-coefficients-are-un

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Numpy has a function for this exact problem: numpy.linalg.solve

To construct the matrix we first need to digest the string turning it into an array of coefficients and solutions.

Finding Numbers

First we need to write a function that takes a string like "c_1 3" and returns the number 3.0. Depending on the format you want in your input string you can either iterate over all chars in this array and stop when you find a non-digit character, or you can simply split on the space and parse the second string. Here are both solutions:

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)

or the simpler solution

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

Note: See edits

Get matrices

Now we can use that to split each expression into two parts: The solution and the equation by the "=". The equation is then split into sub_expressions by the "+" This way we would end turn the string "3x+4y = 3" into

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

Each sub expression then needs to be fed into our find_numbers function. The End result can be appended to the coefficient and solution matrices:

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

Now let's write a simple main function to test this code:

# 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()

Let's run the program in the console!

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

[4.0, 2.0]

You can see that the program identified all our numbers correctly

AGAIN: use the find_number function appropriate for your format

Put The Pieces Together

These Matrices now just need to be pumped directly into the numpy function:

# 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()

Now let's test that:

$ 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.]

As you can see the program now solves the functions for us.

Out of curiosity: Math homework? This feels like math homework.

Edit: Had a typo "c_string" instead of "c_strings" worked out in all tests out of pure and utter luck.

Edit 2: Upon further inspection I would reccomend to split the sub-expressions by a "*":

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

This results in fairly readable input strings


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...