Résoudre une équation linéaire

J'ai besoin de résoudre par programme un système d'équations linéaires en C, en Objective C ou (si nécessaire) en C ++.

Voici un exemple des équations:

-44.3940 = a * 50.0 + b * 37.0 + tx
-45.3049 = a * 43.0 + b * 39.0 + tx
-44.9594 = a * 52.0 + b * 41.0 + tx

À partir de là, j'aimerais obtenir la meilleure approximation pour a , b et tx .

0
D'autres personnes ont répondu à cette question, mais consultez le livre Analyse numérique: Mathématiques de l'informatique scientifique de Kincaid et Cheney. Le livre est en grande partie sur la résolution de différents systèmes d'équations.
ajouté l'auteur Matthew, source

13 Réponses

Dans "Free Lie Algebras" de Reutenauer, section 7.6.2:

A direct bijection between primitive necklaces of length n over F and the set of irreducible polynomials of degree n in F[x] may be described as follows: let K be the field with qn elements; it is a vector space of dimension n over F, so there exists in K an element θ such that the set {θ, θq, ..., θqn-1} is a linear basis of K over F.

With each word w = a0...an-1 of length n on the alphabet F, associate the element β of K given by β = a0θ + a1θq + ... + an-1 θqn-1. It is easily shown that to conjugate words w, w' correspond conjugate elements β, β' in the field extension K/F, and that w \mapsto β is a bijection. Hence, to a primitive conjugation class corresponds a conjugation class of cardinality n in K; to the latter corresponds a unique irreducible polynomial of degree n in F[x]. This gives the desired bijection.

25
ajouté

See section 38.10 "Generating irreducible polynomials from Lyndon words" of http://www.jjj.de/fxt/#fxtbook

4
ajouté

Je crois qu'une telle bijection est présentée dans

S. Golomb. Polynômes irréductibles, codes de synchronisation, colliers primitifs et algèbre cyclotomique. Dans Proc. Con Combinatoire Math. et son Appl., pages 358- 370, Chapel Hill, 1969. Univ. de North Carolina Press.

mais je n'ai pas un accès immédiat à ce document - je suis assez sûr qu'il est là cependant.

3
ajouté
Un petit peu de preuve supplémentaire (toujours pas concluante): springerlink.com/index/P6X9P2BV73L2X2GG.pdf "Comme il existe une bijection entre les mots de Lyndon sur un alphabet de cardinalité k et des polynômes irréductibles sur Fk [10] ..." où la référence [10] est à l'article de Golomb.
ajouté l'auteur CodingWithoutComments, source
Je ne semble pas y avoir accès non plus, mais au moins un autre article ( Berstel "rel =" nofollow noreferrer "> jstor.org/stable/2001573"> Berstel et Reutenauer ) suggère que c'est un problème ouvert.En effet, j'ai essentiellement la même motivation qu'eux pour poser cette question, donc je suppose que je aurait dû lire ce document plus attentivement.
ajouté l'auteur Qiaochu Yuan, source

La correspondance inventée par Golomb repose sur le choix d'un élément primitif a dans le domaine de l'ordre q ^ n. Ensuite, à chaque mot de Lyndon L = (l_0, l_1, ..., l_ {n-1}) on affecte le polynôme primitif ayant comme racine l'élément a ^ {m (L)} où m (L) est le somme entière de l_i * q ^ i sur i = 0,1, ..., n-1.

3
ajouté

Êtes-vous à la recherche d'un progiciel qui fera le travail ou effectuera réellement les opérations matricielles et tel et faire chaque étape?

Le premier, un de mes collègues vient d'utiliser Ocaml GLPK . C'est juste un emballage pour le GLPK , mais il supprime un grand nombre des étapes de mise en place des choses. On dirait que vous allez devoir vous contenter du GLPK, en C, cependant. Pour ce dernier, grâce à délicieux pour avoir sauvegardé un vieil article, j'avais l'habitude d'apprendre LP en arrière, PDF . Si vous avez besoin d'une aide spécifique, informez-nous et je suis sûr que moi ou quelqu'un va revenir et aider, mais je pense que c'est assez simple d'ici. Bonne chance!

0
ajouté

Personnellement, je suis partial face aux algorithmes de Recettes numériques . (J'aime l'édition C ++.)

Ce livre vous apprendra pourquoi les algorithmes fonctionnent, et vous montrera quelques implémentations assez bien débuguées de ces algorithmes.

Bien sûr, vous pouvez utiliser aveuglément CLAPACK (je l'ai utilisé avec beaucoup de succès), mais Je voudrais d'abord taper un algorithme d'élimination gaussienne pour au moins avoir une faible idée du genre de travail qui a été fait pour rendre ces algorithmes stables.

Plus tard, si vous faites une algèbre linéaire plus intéressante, regardez autour du code source de Octave répondra à beaucoup de questions.

0
ajouté

Vous pouvez résoudre ceci avec un programme exactement de la même façon que vous le résolvez manuellement (avec multiplication et soustraction, puis réintroduire les résultats dans les équations). C'est assez mathématique de niveau secondaire.

-44.3940 = 50a + 37b + c (A)
-45.3049 = 43a + 39b + c (B)
-44.9594 = 52a + 41b + c (C)

(A-B): 0.9109 =  7a -  2b (D)
(B-C): 0.3455 = -9a -  2b (E)

(D-E): 1.2564 = 16a (F)

(F/16):  a = 0.078525 (G)

Feed G into D:
       0.9109 = 7a - 2b
    => 0.9109 = 0.549675 - 2b (substitute a)
    => 0.361225 = -2b (subtract 0.549675 from both sides)
    => -0.1806125 = b (divide both sides by -2) (H)

Feed H/G into A:
       -44.3940 = 50a + 37b + c
    => -44.3940 = 3.92625 - 6.6826625 + c (substitute a/b)
    => -41.6375875 = c (subtract 3.92625 - 6.6826625 from both sides)

Donc vous finissez avec:

a =   0.0785250
b =  -0.1806125
c = -41.6375875

Si vous replacez ces valeurs dans A, B et C, vous constaterez qu'elles sont correctes.

L'astuce consiste à utiliser une simple matrice 4x3 qui réduit à son tour une matrice 3x2, puis une 2x1 qui est "a = n", n étant un nombre réel. Une fois que vous avez cela, vous le placez dans la matrice suivante pour obtenir une autre valeur, puis ces deux valeurs dans la matrice suivante jusqu'à ce que vous ayez résolu toutes les variables.

À condition que vous ayez N équations distinctes, vous pouvez toujours résoudre pour N variables. Je dis distinct parce que ces deux ne sont pas:

 7a + 2b =  50
14a + 4b = 100

Ils sont la même équation multipliée par deux donc vous ne pouvez pas obtenir une solution de leur part - en multipliant le premier par deux puis en soustrayant vous laisse avec la déclaration vrai mais inutile:

0 = 0 + 0

À titre d'exemple, voici un code C qui calcule les équations simultanées que vous avez placées dans votre question. D'abord quelques types nécessaires, variables, une fonction de support pour imprimer une équation, et le début de main :

#include 

typedef struct { double r, a, b, c; } tEquation;
tEquation equ1[] = {
    { -44.3940,  50, 37, 1 },      // -44.3940 = 50a + 37b + c (A)
    { -45.3049,  43, 39, 1 },      // -45.3049 = 43a + 39b + c (B)
    { -44.9594,  52, 41, 1 },      // -44.9594 = 52a + 41b + c (C)
};
tEquation equ2[2], equ3[1];

static void dumpEqu (char *desc, tEquation *e, char *post) {
    printf ("%10s: %12.8lf = %12.8lfa + %12.8lfb + %12.8lfc (%s)\n",
        desc, e->r, e->a, e->b, e->c, post);
}

int main (void) {
    double a, b, c;

Ensuite, la réduction des trois équations avec trois inconnues à deux équations à deux inconnues:

    // First step, populate equ2 based on removing c from equ.

    dumpEqu (">", &(equ1[0]), "A");
    dumpEqu (">", &(equ1[1]), "B");
    dumpEqu (">", &(equ1[2]), "C");
    puts ("");

    // A - B
    equ2[0].r = equ1[0].r * equ1[1].c - equ1[1].r * equ1[0].c;
    equ2[0].a = equ1[0].a * equ1[1].c - equ1[1].a * equ1[0].c;
    equ2[0].b = equ1[0].b * equ1[1].c - equ1[1].b * equ1[0].c;
    equ2[0].c = 0;

    // B - C
    equ2[1].r = equ1[1].r * equ1[2].c - equ1[2].r * equ1[1].c;
    equ2[1].a = equ1[1].a * equ1[2].c - equ1[2].a * equ1[1].c;
    equ2[1].b = equ1[1].b * equ1[2].c - equ1[2].b * equ1[1].c;
    equ2[1].c = 0;

    dumpEqu ("A-B", &(equ2[0]), "D");
    dumpEqu ("B-C", &(equ2[1]), "E");
    puts ("");

Ensuite, la réduction des deux équations avec deux inconnues à une équation avec une inconnue:

    // Next step, populate equ3 based on removing b from equ2.

    // D - E
    equ3[0].r = equ2[0].r * equ2[1].b - equ2[1].r * equ2[0].b;
    equ3[0].a = equ2[0].a * equ2[1].b - equ2[1].a * equ2[0].b;
    equ3[0].b = 0;
    equ3[0].c = 0;

    dumpEqu ("D-E", &(equ3[0]), "F");
    puts ("");

Now that we have a formula of the type number1 = unknown * number2, we can simply work out the unknown value with unknown <- number1 / number2. Then, once you've figured that value out, substitute it into one of the equations with two unknowns and work out the second value. Then substitute both those (now-known) unknowns into one of the original equations and you now have the values for all three unknowns:

    // Finally, substitute values back into equations.

    a = equ3[0].r / equ3[0].a;
    printf ("From (F    ), a = %12.8lf (G)\n", a);

    b = (equ2[0].r - equ2[0].a * a) / equ2[0].b;
    printf ("From (D,G  ), b = %12.8lf (H)\n", b);

    c = (equ1[0].r - equ1[0].a * a - equ1[0].b * b) / equ1[0].c;
    printf ("From (A,G,H), c = %12.8lf (I)\n", c);

    return 0;
}

La sortie de ce code correspond aux calculs précédents de cette réponse:

         >: -44.39400000 =  50.00000000a +  37.00000000b +   1.00000000c (A)
         >: -45.30490000 =  43.00000000a +  39.00000000b +   1.00000000c (B)
         >: -44.95940000 =  52.00000000a +  41.00000000b +   1.00000000c (C)

       A-B:   0.91090000 =   7.00000000a +  -2.00000000b +   0.00000000c (D)
       B-C:  -0.34550000 =  -9.00000000a +  -2.00000000b +   0.00000000c (E)

       D-E:  -2.51280000 = -32.00000000a +   0.00000000b +   0.00000000c (F)

From (F    ), a =   0.07852500 (G)
From (D,G  ), b =  -0.18061250 (H)
From (A,G,H), c = -41.63758750 (I)
0
ajouté

D'après le libellé de votre question, il semble que vous ayez plus d'équations que d'inconnues et que vous voulez minimiser les incohérences. Ceci est typiquement fait avec la régression linéaire, qui minimise la somme des carrés des incohérences. Selon la taille des données, vous pouvez le faire dans une feuille de calcul ou dans un package statistique. R est un paquet gratuit de haute qualité qui effectue une régression linéaire, entre autres choses. Il y a beaucoup de régression linéaire (et beaucoup de gotcha), mais comme c'est simple à faire pour les cas simples. Voici un exemple de R utilisant vos données. Notez que le "tx" est l'interception de votre modèle.

> y <- c(-44.394, -45.3049, -44.9594)
> a <- c(50.0, 43.0, 52.0)
> b <- c(37.0, 39.0, 41.0)
> regression = lm(y ~ a + b)
> regression

Call:
lm(formula = y ~ a + b)

Coefficients:
(Intercept)            a            b  
  -41.63759      0.07852     -0.18061  
0
ajouté

In terms of run-time efficiency, others have answered better than I. If you always will have the same number of equations as variables, I like Cramer's rule as it's easy to implement. Just write a function to calculate determinant of a matrix (or use one that's already written, I'm sure you can find one out there), and divide the determinants of two matrices.

0
ajouté

Cramer's Rule and Gaussian Elimination are two good, general-purpose algorithms (also see Simultaneous Linear Equations). If you're looking for code, check out GiNaC, Maxima, and SymbolicC++ (depending on your licensing requirements, of course).

EDIT: Je sais que vous travaillez en terre C, mais je dois aussi mettre un mot pour SymPy (un système d'algèbre informatique en Python). Vous pouvez apprendre beaucoup de ses algorithmes (si vous pouvez lire un peu de python). En outre, il est sous la nouvelle licence BSD, tandis que la plupart des paquets mathématiques gratuits sont GPL.

0
ajouté
En réalité, ni la règle de Cramer ni l'élimination gaussienne ne sont très bonnes dans le monde réel. ils n'ont pas non plus de bonnes propriétés numériques, et ils ne sont pas beaucoup utilisés pour des applications sérieuses. essayez la factorisation LDU. ou mieux, ne vous inquiétez pas de l'algorithme, et utilisez plutôt LAPACK.
ajouté l'auteur Peter, source
pour les variables nombre inférieur à 4, la règle de Cramer est la meilleure pour écrire le code de résolution
ajouté l'auteur Ge Rong, source

Template Numerical Toolkit from NIST has tools for doing that.

L'un des moyens les plus fiables consiste à utiliser un Décomposition QR .

Voici un exemple de wrapper pour que je puisse appeler "GetInverse (A, InvA)" dans mon code et il mettra l'inverse dans InvA.

void GetInverse(const Array2D& A, Array2D& invA)
   {
   QR qr(A);  
   invA = qr.solve(I); 
   }

Array2D est défini dans la bibliothèque.

0
ajouté
Qu'est-ce que I dans qr.solve (I) ?
ajouté l'auteur Ponkadoodle, source

Jetez un coup d'œil à la Fondation Microsoft Solver .

Avec cela, vous pouvez écrire du code comme ceci:

  SolverContext context = SolverContext.GetContext();
  Model model = context.CreateModel();

  Decision a = new Decision(Domain.Real, "a");
  Decision b = new Decision(Domain.Real, "b");
  Decision c = new Decision(Domain.Real, "c");
  model.AddDecisions(a,b,c);
  model.AddConstraint("eqA", -44.3940 == 50*a + 37*b + c);
  model.AddConstraint("eqB", -45.3049 == 43*a + 39*b + c);
  model.AddConstraint("eqC", -44.9594 == 52*a + 41*b + c);
  Solution solution = context.Solve();
  string results = solution.GetReport().ToString();
  Console.WriteLine(results); 

Here is the output:
===Solver Foundation Service Report===
Datetime: 04/20/2009 23:29:55
Model Name: Default
Capabilities requested: LP
Solve Time (ms): 1027
Total Time (ms): 1414
Solve Completion Status: Optimal
Solver Selected: Microsoft.SolverFoundation.Solvers.SimplexSolver
Directives:
Microsoft.SolverFoundation.Services.Directive
Algorithm: Primal
Arithmetic: Hybrid
Pricing (exact): Default
Pricing (double): SteepestEdge
Basis: Slack
Pivot Count: 3
===Solution Details===
Goals:

Decisions:
a: 0.0785250000000004
b: -0.180612500000001
c: -41.6375875

0
ajouté
Alors, quelles propriétés de stabilité numérique pouvons-nous attendre de cela? Comme ce n'est pas un logiciel libre, il est censé être assorti d'une diligence raisonnable, de tests comparatifs avec des librairies grand public comme LAPACK, etc. Il doit y avoir un avantage substantiel pour l'emporter sur une solution propriétaire.
ajouté l'auteur Evgeni Sergeev, source
function x = LinSolve(A,y)
%
% Recursive Solution of Linear System Ax=y
% matlab equivalent: x = A\y 
% x = n x 1
% A = n x n
% y = n x 1
% Uses stack space extensively. Not efficient.
% C allows recursion, so convert it into C. 
% ----------------------------------------------
n=length(y);
x=zeros(n,1);
if(n>1)
    x(1:n-1,1) = LinSolve( A(1:n-1,1:n-1) - (A(1:n-1,n)*A(n,1:n-1))./A(n,n) , ...
                           y(1:n-1,1) - A(1:n-1,n).*(y(n,1)/A(n,n))); 
    x(n,1) = (y(n,1) - A(n,1:n-1)*x(1:n-1,1))./A(n,n); 
else
    x = y(1,1) / A(1,1);
end
0
ajouté
Alors que faire si A (n, n) est zéro?
ajouté l'auteur Evgeni Sergeev, source