Résoudre un système d'équations linéaires

12

Écrivez un programme pour résoudre une série d'équations linéaires aussi courte que possible. Il doit résoudre un nombre arbitraire de problèmes d'équations. Ils peuvent être saisis comme vous le souhaitez, les coefficients de matrice augmentée sont probablement les plus faciles. Le programme n'a pas à gérer les coefficients ou les solutions non entiers. Aucun cas dégénéré ou invalide ne sera testé. Le programme doit afficher la valeur de chaque forme d'échelon de ligne variable ou réduite.

Aucune bibliothèque de résolution d'équations, fonctions matricielles ou aucun moyen de résolution automatique n'est autorisé. Vous pouvez simuler des matrices avec des tableaux ou des listes.

Exemple d'entrée (ou équivalent):

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

Cela représente 2x+y-z=8, -3x-y+2z=-11, -2x+y+2z=-3

Exemple de sortie (ou équivalent):

{2,3,-1}

Cela représente x=2, y=3, z=-1

qwr
la source
2
Les coefficients des variables et les termes constants peuvent-ils être séparés en deux tableaux en entrée?
user12205
@ace oui, ça va
qwr
1
Que dites-vous exactement par cas dégénérés? Je suppose que vous vous référez à tous ces cas: 1) entrée mal formée; 2) Des choses comme 0x=0ou 0x=5; 4) Cas où le nombre d'équations est différent du nombre de variables; 5) Des cas contradictoires comme x+5y=7, x+5y=8; 6) Cas sans indépendance linéaire, comme x+3y=6, 2x+6y=12. Ai-je raison?
Victor Stafusa
@Victor Oui, toute entrée présentant une quelconque ambiguïté ou non résoluble.
qwr
Qu'en est-il des cas qui ne sont pas dégénérés mais qui sont mal conditionnés? (Ou, en d'autres termes, quel type de pivotement est nécessaire?)
Peter Taylor

Réponses:

3

Python 169 166

la mise en oeuvre

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[]

Démo

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

Remarque

Si vous êtes d'accord avec l'approximation du flotteur, vous pouvez supprimer l'appel de la fonction ronde et continuer le golf à 159 caractères

Abhijit
la source
9

APL, 1 caractère

Je sais que cela ne correspond pas aux exigences (révisées), mais il est trop bon de ne pas publier:

Le symbole "domino" (division à l' ÷intérieur d'un rectangle) effectue une division matricielle, il peut donc résoudre tout système d'équations linéaires. Il suffit de le mettre entre le vecteur à terme constant et la matrice avec les autres termes:

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

(si vous voulez l'essayer sur TryApl, c'est )

Tobia
la source
4

Javascript ( 284 181) - Méthode d'élimination de Gauss

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}

Tester

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

Le tableau renvoyé combine la matrice d'identité et la solution.

Michael M.
la source
Vous pouvez enregistrer quelques caractères supplémentaires.
MarcinJuraszek
Au lieu d' l=A.length;for(i=0;i<l;i++)utilisation for(i=0;i<l=A.length;i++).
Victor Stafusa
Au lieu d' for(i=l-1;i>=0;i--)utilisation for(i=l;--i;).
Victor Stafusa
Vous pouvez également déplacer w=A[j][i]dans for()et sauter {}autour.
MarcinJuraszek
Merci à tous, j'ai réussi à fusionner les étapes avant et arrière en une seule étape, économisant une centaine de caractères et certains de vos conseils ne sont plus valides. (sauf @MarcinJuraszek tip)
Michael M.
3

Cette réponse ne correspond plus à la question après le changement de règle car elle utilise une fonction matricielle. *

Sauge , 32

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

Exemple d'entrée:

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

Exemple de sortie:

(2, 3, -1)

* Sans doute, matrix()est un transtypage, pas une fonction (l'exécution import types; isinstance(matrix, types.FunctionType)donne False). En outre, la ~et *sont les opérateurs , pas de fonctions.

user12205
la source
J'ai mis à jour les règles. Le code doit gérer un nombre différent d'équations et vous ne pouvez plus utiliser de fonctions matricielles.
qwr
3

Java - 522 434 228 213 caractères

Résout en vérifiant systématiquement tous les n-tuples entiers possibles par multiplication directe jusqu'à ce que l'on trouve un qui fonctionne.

La fonction prend la matrice augmentée, A, le vecteur de solution d'essai, x, et la dimension, n, comme vecteur de solution d'entrées-sorties, x. Notez que le vecteur x est en fait un plus grand que la dimension pour vous aider à parcourir les solutions possibles. (Si je déclarais les variables A, x, n, j, k, s comme variables d'instance, la fonction serait de 31 caractères plus courte - pour un total de 182, mais cela donne l'impression de trop plier les règles.)

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;}}}

Programme de test (quelque peu non golfé):

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;
            }
        }
    }
}

Le programme prend les entrées de stdin sous forme d'entiers séparés par des espaces comme suit: premièrement, la dimension du problème, deuxièmement, les entrées de la matrice augmentée par ligne.

Exemple d'exécution:

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

J'ai rasé plusieurs caractères en suivant les conseils de Victor sur les boucles et le "public", en stockant le RHS dans la matrice augmentée au lieu de séparément, et en ajoutant une entrée supplémentaire à ma solution d'essai pour simplifier la génération de chaque nouvelle solution d'essai. L'OP a également déclaré qu'une fonction est suffisante - pas besoin de compter l'ensemble du programme.

Wally
la source
while(true){f=0;for(j=0;j<n;j++)peut être remplacé par while(true){for(f=j=0;j<n;j++). De plus, votre classe n'a pas besoin d'être publique. Les boucles pour avec une seule instruction dans le corps n'ont pas besoin des accolades.
Victor Stafusa
Je pense que cela for(j=0;j<n;j++){for(k=0;k<n;k++){A[j][k]=p.nextInt();}b[j]=p.nextInt();}peut être remplacé parfor(j=0;j<n;b[j++]=p.nextInt())for(k=0;k<n;)A[j][k++]=p.nextInt();
Victor Stafusa
@Victor Merci, j'ai apporté ces modifications et d'autres.
Wally
while(true)peut être changé enfor(;;)
user12205
@ace merci - a changé cela et quelques autres choses et a rasé 15 caractères.
Wally
1

JavaScript (ES6),  152  151 octets

Mise en œuvre de la règle de Cramer .

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

Essayez-le en ligne!

Arnauld
la source