Oplossen van een lineaire vergelijking

stemmen
35

Ik moet programmatisch oplossen van een stelsel lineaire vergelijkingen in C, Objective C, of ​​(indien nodig) C ++.

Hier is een voorbeeld van de vergelijkingen:

-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

Vanuit dit, wil ik graag de beste benadering voor te krijgen a, ben tx.

De vraag is gesteld op 03/08/2008 om 19:14
bron van user
In andere talen...                            


10 antwoorden

stemmen
3

Bent u op zoek naar een softwarepakket dat het werk zal doen of eigenlijk het doen van de matrix operaties en dergelijke en doe elke stap?

De eerste, een collega van mij gewoon gebruikt Ocaml GLPK . Het is gewoon een wrapper voor de GLPK , maar het verwijdert een groot deel van de stappen van het instellen van zaken. Het lijkt erop dat je gaat aan de stok met de GLPK, in C, dat wel. Voor deze laatste, dankzij de heerlijke voor het redden van een oud artikel dat ik gebruikt om LP te leren tijdje terug, PDF . Als u specifieke hulp bij het instellen verder nodig hebt, laat het ons weten en ik weet zeker, mij of iemand weer terug in dwalen en helpen, maar ik denk dat het vrij makkelijk vanaf hier. Succes!

antwoordde op 03/08/2008 om 19:27
bron van user

stemmen
17

Regel van Cramer en Gausseliminatie zijn twee goede, general-purpose algoritmen (zie ook Gelijktijdige lineaire vergelijkingen ). Als u op zoek bent naar code, check out GiNaC , Maxima en SymbolicC ++ (afhankelijk van uw eisen voor vergunningen, natuurlijk).

EDIT: Ik weet dat je werkt in C land, maar ik heb ook een goed woordje voor te zetten SymPy (een computer algebra systeem in Python). Je kunt veel van de algoritmes te leren (als je een beetje van python kan lezen). Ook is het onder de nieuwe BSD-licentie, terwijl de meeste van de vrije wiskunde pakketten zijn GPL.

antwoordde op 03/08/2008 om 19:37
bron van user

stemmen
7

Voor een 3x3 systeem van lineaire vergelijkingen ik denk dat het goed is om de uitrol van uw eigen algoritmes zou zijn.

Echter, zou je zorgen te maken over de nauwkeurigheid, delen door nul of heel kleine aantallen en wat te doen over oneindig veel oplossingen. Mijn suggestie is om te gaan met een standaard numerieke lineaire algebra pakket zoals LAPACK .

antwoordde op 08/08/2008 om 18:59
bron van user

stemmen
1

Persoonlijk ben ik gedeeltelijk aan de algoritmes van Numerical Recipes . (Ik ben dol op de C ++ editie.)

Dit boek zal je leren waarom de algoritmen, plus je laten zien wat pretty-goed debugged implementaties van deze algoritmen.

Natuurlijk kan je gewoon blindelings gebruikt CLAPACK (ik heb het gebruikt met groot succes), maar ik zou de eerste hand-typ een Gauss Elimination algoritme om op zijn minst een vaag idee van het soort werk dat is besteed aan het maken van deze algoritmen stal.

Later, als je aan het doen bent interessanter lineaire algebra, kijken rond de broncode van Octave zal een hoop vragen te beantwoorden.

antwoordde op 25/08/2008 om 19:22
bron van user

stemmen
3

Template Numerieke Toolkit van NIST heeft hulpmiddelen om dat te doen.

Een van de meest betrouwbare manieren is het een gebruik van QR Decomposition .

Hier is een voorbeeld van een wrapper, zodat ik "GetInverse (A, Inva)" in mijn code kunt bellen en het zal de inverse in Inva zetten.

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

Array2D wordt gedefinieerd in de bibliotheek.

antwoordde op 25/08/2008 om 19:53
bron van user

stemmen
2

Uit de formulering van uw vraag, lijkt het alsof u meer vergelijkingen dan onbekenden en u wilt de inconsistenties te minimaliseren. Dit wordt typisch gedaan met lineaire regressie, waarbij de som van de kwadraten van de inconsistenties minimaliseert. Afhankelijk van de grootte van de gegevens, kunt u dit doen in een spreadsheet of in een statistisch pakket. R is een hoogwaardig, gratis pakket dat lineaire regressie doet, onder een heleboel andere dingen. Er is veel te lineaire regressie (en een heleboel weetjes), maar het is eenvoudig te doen voor eenvoudige gevallen. Hier is een R bijvoorbeeld met behulp van uw gegevens. Merk op dat de "tx" is het snijpunt aan uw model.

> 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  
antwoordde op 17/09/2008 om 15:22
bron van user

stemmen
2

In termen van run-time efficiency, hebben anderen beter dan ik beantwoord Als u altijd hetzelfde aantal vergelijkingen hebben als variabelen, ik hou van de regel van Cramer , want het is eenvoudig te implementeren. Schrijf gewoon een functie om determinant van een matrix te berekenen (of gebruik een die al is geschreven, ik weet zeker dat je die er zijn te vinden), en verdeel de determinanten van twee matrices.

antwoordde op 19/09/2008 om 04:36
bron van user

stemmen
15

Je kunt dit op te lossen met een programma precies dezelfde manier als u het op te lossen met de hand (met vermenigvuldigen en aftrekken, is voedings- resultaten terug in de vergelijkingen). Dit is vrij standaard middelbare school-niveau wiskunde.

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

Dus je eindigt met:

a =   0.0785250
b =  -0.1806125
c = -41.6375875

Als u deze waarden terug in A, B en C aansluiten, vindt u ze correct zijn.

De truc is om een ​​eenvoudige 4x3 matrix die vermindert op zijn beurt een 3x2 matrix, dan is een 2x1 die "a = n", waarbij n een werkelijke aantal gebruiken. Zodra je dat hebt, je het meegenomen in de volgende matrix tot een andere waarde te krijgen, dan zijn die twee waarden in de volgende matrix omhoog totdat je alle variabelen opgelost.

Op voorwaarde dat u N verschillende vergelijkingen, dan kunt u altijd op te lossen voor N variabelen. Ik zeg onderscheiden omdat deze twee zijn niet:

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

Zij zijn het dezelfde vergelijking vermenigvuldigd met twee dus je kunt niet een oplossing te komen van hen - het vermenigvuldigen van de eerste met twee vervolgens af te trekken laat je met de echte, maar nutteloos verklaring:

0 = 0 + 0

Bij wijze van voorbeeld, hier is een aantal C-code die werkt uit de gelijktijdige vergelijkingen die u geplaatst in uw vraag. Eerst wat nodig types, variabelen, een ondersteunende functie voor het afdrukken van een vergelijking, en de start van main:

#include <stdio.h>

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;

Vervolgens de reductie van de drie vergelijkingen met drie onbekenden twee vergelijkingen met twee onbekenden:

    // 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 ("");

Vervolgens de reductie van de twee vergelijkingen met twee onbekenden een vergelijking met één onbekende:

    // 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 ("");

Nu dat we een formule van het type number1 = unknown * number2, kunnen we gewoon werken de onbekende waarde met unknown <- number1 / number2. Dan, als je eenmaal die waarde uit heb bedacht, te vervangen door het in één van de vergelijkingen met twee onbekenden en berekent dan de tweede waarde. Vervangen dan beide (nu bekende) onbekenden in een van de oorspronkelijke vergelijkingen en u hebt nu de waarden voor alle drie onbekenden:

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

De uitvoer van die code overeenkomt met de eerdere berekeningen in dit antwoord:

         >: -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)
antwoordde op 26/02/2009 om 11:59
bron van user

stemmen
6

Neem een kijkje op de Microsoft Solver Foundation .

Hiermee kun je code als volgt te schrijven:

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

Hier is de output:
=== Solver Stichting Dienst Verslag ===
Datetime: 2009/04/20 23:29:55
Model Naam: Standaard
Capabilities aangevraagd: LP
Los Time (ms): 1027
Totale tijd (ms): 1414
oplossen Completion Status: Optimaal
Solver Geselecteerde: Microsoft.SolverFoundation.Solvers.SimplexSolver
richtlijnen:
Microsoft.SolverFoundation.Services.Directive
algoritme: Primal
Cijferen: Hybrid
Pricing (exact): Default
Pricing (dubbel): SteepestEdge
Basis: Slack
Pivot Count: 3
== = Solution Details ===
Goals:

Besluiten:
a: 0,0785250000000004
b: -,180612500000001
c: -41,6375875

antwoordde op 21/04/2009 om 04:33
bron van user

stemmen
1
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
antwoordde op 30/12/2014 om 15:24
bron van user

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more