Lösen Sie ein lineares Gleichungssystem

12

Schreiben Sie ein Programm, um eine Reihe von linearen Gleichungen so kurz wie möglich zu lösen. Es muss eine beliebige Anzahl von Gleichungsproblemen lösen. Sie können eingegeben werden, wie Sie möchten. Die Koeffizienten der erweiterten Matrix sind wahrscheinlich am einfachsten. Das Programm muss keine nicht ganzzahligen Koeffizienten oder Lösungen verarbeiten. Es werden keine entarteten oder ungültigen Fälle getestet. Das Programm muss den Wert jeder Variablen oder reduzierten Zeilenebenenform ausgeben.

Es sind keine Gleichungslösungsbibliotheken, Matrixfunktionen oder Möglichkeiten zur automatischen Lösung zulässig. Sie können Matrizen mit Arrays oder Listen simulieren.

Beispieleingabe (oder gleichwertig):

m={{2,1,-1,8},{-3,-1,2,-11},{-2,1,2,-3}}

Dies stellt dar 2x+y-z=8, -3x-y+2z=-11, -2x+y+2z=-3

Beispielausgabe (oder gleichwertig):

{2,3,-1}

Dies stellt dar x=2, y=3, z=-1

qwr
quelle
2
Können die Koeffizienten der Variablen und die konstanten Terme in der Eingabe in zwei Arrays getrennt werden?
user12205
@ace ja, das ist in Ordnung
qwr
1
Was genau sagen Sie mit degenerierten Fällen? Ich vermute, dass Sie sich auf all diese Fälle beziehen: 1) Fehlgebildete Eingabe; 2) Dinge wie 0x=0oder 0x=5; 4) Fälle, in denen sich die Anzahl der Gleichungen von der Anzahl der Variablen unterscheidet; 5) Widersprüchliche Fälle wie x+5y=7, x+5y=8; 6) Fälle ohne lineare Unabhängigkeit, wie z x+3y=6, 2x+6y=12. Habe ich recht?
Victor Stafusa
@ Victor Ja, jede Eingabe, die überhaupt nicht eindeutig ist oder nicht lösbar ist.
qwr
Was ist mit Fällen, die nicht entartet, aber schlecht konditioniert sind? (Oder mit anderen Worten, welche Art von Schwenken ist erforderlich?)
Peter Taylor

Antworten:

3

Python 169 166

Implementierung

def s(a):
 if a:b=a[0];r=s([[x-1.*y*b[0]/r[0]for x,y in zip(b[1:],r[1:])]for r in a[1:]]);return[round((b[-1]-sum(x*y for x,y in zip(b[1:-1],r)))/b[0])]+r
 return[]

Demo

>>> arr=[[2, 1, -1, 8], [-3, -1, 2, -11], [-2, 1, 2, -3]]
>>> s(arr)
[2.0, 3.0, -1.0]

Hinweis

Wenn Sie mit der Float-Näherung einverstanden sind, können Sie den runden Funktionsaufruf entfernen und weiter auf 159 Zeichen spielen

Abhijit
quelle
9

APL, 1 Zeichen

Ich weiß, dass es nicht den (überarbeiteten) Anforderungen entspricht, aber es ist zu gut, um nichts zu posten:

Das Symbol "Domino" (Division ÷innerhalb eines Rechtecks) führt eine Matrixdivision durch und kann daher jedes lineare Gleichungssystem lösen. Sie müssen es nur zwischen den konstanten Termvektor und die Matrix mit den anderen Begriffen setzen:

      8 ¯11 ¯3 ⌹ ⊃(2 1 ¯1)(¯3 ¯1 2)(¯2 1 2)
2 3 ¯1

(Wenn Sie es auf TryApl ausprobieren möchten, ist )

Tobia
quelle
4

Javascript ( 284 181) - Gauß-Eliminierungsmethode

function f(A){l=A.length;d=1;for(i=0;i+1;i+=d){v=A[i][i];for(k=0;k<l+1;k++)A[i][k]/=v;for(j=i+d;A[j];j+=d)for(k=0,w=A[j][i];k<l+1;k++)A[j][k]-=w*A[i][k];if(i==l-d)d=-1,i=l}return A}

Prüfung

f([[2,1,-1,8],[-3,-1,2,-11],[-2,1,2,-3]]);

=> [[1,0,0,2],[0,1,0,3],[-0,-0,1,-1]]

Das zurückgegebene Array kombiniert die Identitätsmatrix und die Lösung.

Michael M.
quelle
Sie können einige weitere Zeichen speichern.
MarcinJuraszek
Anstelle von l=A.length;for(i=0;i<l;i++)Gebrauch for(i=0;i<l=A.length;i++).
Victor Stafusa
Anstelle von for(i=l-1;i>=0;i--)Gebrauch for(i=l;--i;).
Victor Stafusa
Sie können auch bewegen w=A[j][i]in for()und überspringen {}um.
MarcinJuraszek
Vielen Dank an alle, ich habe es geschafft, Vorwärts- und Rückwärtsschritte in einem einzigen Schritt zusammenzuführen und dabei hundert Zeichen zu sparen. Einige Ihrer Tipps sind nicht mehr gültig. (außer @MarcinJuraszek Tipp)
Michael M.
3

Diese Antwort passt nach der Regeländerung nicht mehr zur Frage, da eine Matrixfunktion verwendet wird. * *

Salbei , 32

~matrix(input())*vector(input())

Beispieleingabe:

[[2, 1, -1], [-3, -1, 2], [-2, 1, 2]]
[8, -11, -3]

Beispielausgabe:

(2, 3, -1)

* Ist wohl matrix()ein Typecast, keine Funktion (Running import types; isinstance(matrix, types.FunctionType)gibt False). Auch die ~und *sind Operatoren , keine Funktionen.

user12205
quelle
Ich habe die Regeln aktualisiert. Der Code muss eine unterschiedliche Anzahl von Gleichungen verarbeiten, und Sie können jetzt keine Matrixfunktionen verwenden.
qwr
3

Java - 522 434 228 213 Zeichen

Löst durch systematisches Überprüfen aller möglichen ganzzahligen n-Tupel durch direkte Multiplikation, bis eines gefunden wird, das funktioniert.

Die Funktion verwendet die erweiterte Matrix A, den Versuchslösungsvektor x und die Dimension n als Eingabe-Ausgabe-Lösungsvektor x. Beachten Sie, dass der Vektor x tatsächlich eins größer als die Dimension ist, um mögliche Lösungen zu durchlaufen. (Wenn ich die Variablen A, x, n, j, k, s als Instanzvariablen deklarieren würde, wäre die Funktion 31 Zeichen kürzer - für insgesamt 182, aber das fühlt sich an, als würde man die Regeln zu weit biegen.)

int[]Z(int[][]A,int[]x,int n){int j,k,s;for(;;){for(j=0;j<n;j++){for(k=s=0;k<n;s+=A[j][k]*x[k++]);if(s!=A[j][n])j+=n;}if(j==n)return x;for(j=0;j<=n;j++)if(x[j]!=x[n]||j==n){x[j]++;for(k=0;k<j;x[k++]=-x[n]);j=n;}}}

Testprogramm (etwas ungolfed):

import java.util.*;
class MatrixSolver{
    public MatrixSolver() {
        Scanner p=new Scanner(System.in); //initialize everything from stdin
        int j,k,n=p.nextInt(),A[][]=new int[n][n+1],x[]=new int[n+1];
        for(j=0;j<n;j++)for(k=0;k<=n;A[j][k++]=p.nextInt());
        x=Z(A,x,n); //call the magic function
        for(j=0;j<n;j++) System.out.print(x[j]+" "); //print the output
    }
    public static void main(String[]args){
        new MatrixSolver();
    } 

    int[]Z(int[][]A,int[]x,int n){
        int j,k,s;
        for(;;){
            for(j=0;j<n;j++){ //multiply each row of matrix by trial solution and check to see if it is correct
                for(k=s=0;k<n;s+=A[j][k]*x[k++]);
                if(s!=A[j][n])j+=n;
            }
            if(j==n)return x; //if it is correct return the trial solution
            for(j=0;j<=n;j++)if(x[j]!=x[n]||j==n){//calculate the next trial solution
                x[j]++;
                for(k=0;k<j;x[k++]=-x[n]);
                j=n;
            }
        }
    }
}

Das Programm nimmt Eingaben von stdin als durch Leerzeichen getrennte Ganzzahlen wie folgt entgegen: erstens die Dimension des Problems, zweitens die zeilenweisen Einträge der erweiterten Matrix.

Probelauf:

$java -jar MatrixSolver.jar
3 2 1 -1 8 -3 -1 2 -11 -2 1 2 -3
2 3 -1 

Ich habe mehrere Zeichen rasiert, indem ich Victors Ratschlägen zu Loops und "public" gefolgt bin, die RHS in der erweiterten Matrix anstatt separat gespeichert und meiner Testlösung einen zusätzlichen Eintrag hinzugefügt habe, um die Generierung jeder neuen Testlösung zu vereinfachen. Das OP sagte auch, dass eine Funktion ausreicht - es ist nicht erforderlich, das gesamte Programm zu zählen.

Wally
quelle
while(true){f=0;for(j=0;j<n;j++)kann ersetzt werden durch while(true){for(f=j=0;j<n;j++). Außerdem muss Ihre Klasse nicht öffentlich sein. For-Loops mit nur einer Anweisung im Körper benötigen keine geschweiften Klammern.
Victor Stafusa
Ich denke, das for(j=0;j<n;j++){for(k=0;k<n;k++){A[j][k]=p.nextInt();}b[j]=p.nextInt();}kann ersetzt werden durchfor(j=0;j<n;b[j++]=p.nextInt())for(k=0;k<n;)A[j][k++]=p.nextInt();
Victor Stafusa
@ Victor Danke, ich habe diese und andere Änderungen vorgenommen.
Wally
while(true)kann geändert werden zufor(;;)
user12205
@ace danke - habe das und ein paar andere Dinge geändert und 15 Zeichen rasiert.
Wally
1

JavaScript (ES6),  152  151 Byte

Implementierung der Cramer-Regel .

(m)(v)mv

m=>v=>m.map((_,i)=>(D=m=>m+m?m.reduce((s,[v],i)=>s+(i&1?-v:v)*D(m.map(([,...r])=>r).filter(_=>i--)),0):1)(m.map((r,y)=>r.map((k,x)=>x-i?k:v[y])))/D(m))

Probieren Sie es online aus!

Arnauld
quelle