Maple als rekeninstrument

Eenvoudige numerieke berekeningen

Eenvoudige algebraische berekeningen

Maple zou geen computer algebra pakket genoemd worden als zijn kracht niet lag in het symbolisch rekenen. Alle operatoren en functies die men kan gebruiken voor numeriek rekenen ('+',..., '/', 'sin',...) staan ook ter beschikking bij symbolische berekeningen.

> Expr1 := a*x + b;

Expr1 := a*x+b

> Expr2 := Expr1^2;

Expr2 := (a*x+b)^2

Men wil vaak waarden toekennen aan 'a', 'b' en 'c' nadat men symbolische berekeningen gedaan heeft. Dit kan met het commando 'subs' (substitute):

> Expr3 := subs(a = (alpha + beta), b = gamma^2, Expr2);

Expr3 := ((alpha+beta)*x+gamma^2)^2

Merk op dat 'a' en 'b' nog steeds geen waarde hebben, er is enkel een substitutie in 'Expr2' gebeurd, geen toekenning.

> a, b;

a, b

Een alternatief is de functie 'eval' waarbij de substituties als verzameling worden meegegeven:

> eval(Expr2, {a = (alpha + beta), b = gamma^2});

((alpha+beta)*x+gamma^2)^2

Er zijn een flink aantal commando's om de vorm van een symbolische uitdrukking te manipuleren. Enkele voorbeelden:

De 'expand' functie werkt een algebraische uitdrukking zover mogelijk uit, dwz. machten worden uitgerekend en de distributiviteit van de vermenigvuldiging tov. de optelling wordt toegepast.

> expand(Expr3);

x^2*alpha^2+2*x^2*alpha*beta+2*x*alpha*gamma^2+x^2*beta^2+2*x*beta*gamma^2+gamma^4

De functie 'factor' kan gezien worden als de inverse van 'expand', er wordt geprobeerd de uitdrukking zo compact mogelijk te schrijven door gemeenschappelijke factoren van termen te identificeren.

> factor(alpha^2*x^2 + 2*alpha*beta*x^2 + 2*alpha*gamma^2*x +
      beta^2*x^2 + 2*beta*gamma^2*x + gamma^4);

(x*alpha+x*beta+gamma^2)^2

> factor(a^3 - b^3);

(a-b)*(a^2+a*b+b^2)

Soms wil men een uitdrukking herordenen in termen die eenzelfde macht van een variabele bevatten, dit kan met behulp van de functie 'collect'.

> collect(Expr3, x);

(alpha+beta)^2*x^2+2*gamma^2*(alpha+beta)*x+gamma^4

Gemeenschappelijke factoren schrappen uit teller en noemer van een breuk kan met behulp van de functie 'normal'.

> normal((a^2-b^2)/(a^3+b^3));

(a-b)/(a^2-a*b+b^2)

Vaak wil men een uitdrukking in de meest eenvoudige vorm brengen.  Dit kan uiteraard door bovenstaande functies met de hand toe te passen, maar het kan soms ook automatisch met behulp van 'simplify'.

> simplify(sin(x)^2 + cos(x)^2 + 2*sin(x)*cos(x));

2*sin(x)*cos(x)+1

> simplify((a^2-b^2)/(a^3+b^3));

(a-b)/(a^2-a*b+b^2)

Merk echter op dat 'simplify' niet altijd datgene doet wat de gebruiker wel zou willen en dat de andere functies zeker niet overbodig zijn.

> simplify(alpha^2*x^2 + 2*alpha*beta*x^2 + 2*alpha*gamma^2*x +
        beta^2*x^2 + 2*beta*gamma^2*x + gamma^4);

x^2*alpha^2+2*x^2*alpha*beta+2*x*alpha*gamma^2+x^2*beta^2+2*x*beta*gamma^2+gamma^4

> simplify((alpha*x + beta*x + gamma^2)^2);

(x*alpha+x*beta+gamma^2)^2

> Expr1 := 'Expr1': Expr2 := 'Expr2': Expr3 := 'Expr3': Expr4 := 'Expr4':

Vectoren en matrices

Vectoren en matrices defininieren

De functie 'Matrix' wordt gebruikt om een matrix te definieren.  Hiervoor specifieert men de elementen van de matrix te als een lijst van lijsten.  Elke lijst stelt een rij van de matrix voor.

> A := Matrix([[-1, 0], [2, 3]]);

A := Matrix([[-1, 0], [2, 3]])

Men kan ook een matrix declareren zonder onmiddellijk de elementen te definieren door het aantal rijen en kolommen op te geven::

> B := Matrix(2, 2);

B := Matrix([[0, 0], [0, 0]])

Deze kunnen dan stuk per stuk toegekend of opgevraagd worden.

> B[1,1] := 3: B[1,2] := -1: B[2,1] := 2: B[2,2] := 0: B;

Matrix([[3, -1], [2, 0]])

> B[1,2];

-1

Men zou vectoren kunnen ingeven zoals matrices met het aantal rijen of kolommen gelijk aan 1, maar er is ook een functie 'Vector' voor:

> V := Vector([2, 3]);

V := Vector[column]([[2], [3]])

> A := 'A': B := 'B': V := 'V':

Speciale matrices

Met behulp van de functie 'Matrix' kan men gemakkelijk enkele speciale types matrices definieren door gebruik te maken van de 'shape' parameter.  Belangrijke voordelen zijn de identische, de diagonale en de symmetrische matrix.

> C := Matrix(3, 3, shape=identity);

C := Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])

> E := Matrix(3, 3, Vector([a, b, c]), shape=diagonal);

E := Matrix([[a, 0, 0], [0, b, 0], [0, 0, c]])

Merk op dat een vector gebruikt wordt om de diagonaalelementen te initialiseren.  Men kan dit uiteraard ook via toekenning doen zoals hieronder geillustreerd worrdt voor een symmetrische matrix.

> F := Matrix(3, 3, shape=symmetric);

F := Matrix([[0, 0, 0], [0, 0, 0], [0, 0, 0]])

> F[1,1] := a: F[1,2] := b: F[1,3] := c: F[2,2] := d: F[2,3] := e: F[3,3] := f: F;

Matrix([[a, b, c], [b, d, e], [c, e, f]])

> C := 'C': E := 'E': F := 'F':

Rekenen met matrices en vectoren

Bewerkingen met matrices zijn eenvoudig in Maple, hoewel er toch enkele punten zijn waarop gelet moet worden.

> A := Matrix([[1, 3],[-1, 2]]); B := Matrix([[2, -1],[6, -2]]);

A := Matrix([[1, 3], [-1, 2]])

B := Matrix([[2, -1], [6, -2]])

De optelling kan met de '+' uitgevoerd worden, zpals je zou verwachten:

> A + B;

Matrix([[3, 2], [5, 0]])

De vermenigvuldiging van matrices is gedefinieerd met '.', dus niet met '*' zoals voor scalaire grootheden:

> A.B;

Matrix([[20, -7], [10, -3]])

Het vermenigvuldigen van een matrix met een vector werkt analoog:

> V := Vector([1, 0]);

V := Vector[column]([[1], [0]])

> A.V;

Vector[column]([[1], [-1]])

> V.A;

Error, (in LinearAlgebra:-VectorMatrixMultiply) invalid input: `LinearAlgebra:-VectorMatrixMultiply` expects its 1st argument, v, to be of type Vector[row] but received Vector[Column]( 1..2,[ 1, 0] , datatype = anything, storage = rectangular, order = C_order )

De vector 'V' is een kolomvector zodat het bovenstaande product niet gedefinieerd is. automatisch getransponeerd heeft.  Wil men de vermenigvuldiging toch uitvoeren dan kan men de kolomvector 'V' transponeren naar een rijvector.  De functie 'Transpose' wordt gedefinieerd in het 'LinearAlgebra' package.

> LinearAlgebra[Transpose](V);

Vector[row]([1, 0])

Indien men deze (en/of andere) functie uit 'LinearAlgebra' vaak wil gebruiken kan men ze laden met behulp van 'with':

> with(LinearAlgebra):

De vermenigvuldiging wordt dan zoals verwacht:

> Transpose(V).A;

Vector[row]([1, 3])

De berekening van het scalair product van twee vectoren ligt voor de hand:

> U := Vector([2, 3]);

U := Vector[column]([[2], [3]])

> U.V;

2

In tegenstelling met wat misschien te verwachten was hoeft de vector 'U' niet eerst getransponeerd te worden.

De machtsverheffing is wel gedefinieerd als '^':

> A^2;

Matrix([[-2, 9], [-3, 1]])

Uiteraard kunnen de determinant, inverse, getransponeerde en het spoor berkend worden.

> Determinant(A);

5

> MatrixInverse(A);

Matrix([[2/5, (-3)/5], [1/5, 1/5]])

> Transpose(A);

Matrix([[1, -1], [3, 2]])

> Trace(A);

3

Ook de Euclidische norm van een vector kan eenvoudig berekend worden:

> VectorNorm(U, 2, conjugate=false);

13^(1/2)

Men kan testen of twee matrices gelijk zijn mbv. de functie 'equal'.

> Equal(A, B);

false

> Equal(A, A);

true

> A := 'A': B := 'B': U := 'U': V := 'V':

Definitie van functies

Het definieren van eigen functies in Maple is erg eenvoudig, de syntax leunt dicht aan bij de gebruikelijke wiskundige notatie.

> f := x -> x^2;

f := proc (x) options operator, arrow; x^2 end proc

In woorden: de functie f beeldt x af op x^2, de notatie is dus erg intuitief..

Functies in meerdere veranderlijken kunnen analoog geprogrammeerd worden:

> g := (x, y) -> sqrt(x^2 + y^2);

g := proc (x, y) options operator, arrow; sqrt(x^2+y^2) end proc

Het koppel (x,y) wordt afgebeeld op sqrt(x^2 + y^2).

Stel dat men berekeningen gedaan heeft met Maple en als resultaat een bepaalde uitdrukking bekomen heeft. Men wil hiermee nu een functie definieren,

> Expr := a*x^2 + b*x + c;

Expr := a*x^2+b*x+c

> f1 := x -> Expr;

f1 := proc (x) options operator, arrow; Expr end proc

> f1(2);

a*x^2+b*x+c

Dit is niet wat men op het eerste zicht zou verwachten. Indien men echter de definitie van f1 grondig bekijkt dan ziet men dat het resultaat van f1 altijd de waarde van Expr zal zijn, ongeacht de waarde van de veranderlijke x.

De meest elegante manier om dit probleem (waarmee men geregeld en meestal onverwacht mee geconfronteerd wordt) op te lossen is het gebruik van de 'unapply' functie:

> f2 := unapply(Expr, x);

f2 := proc (x) options operator, arrow; a*x^2+b*x+c end proc

> f2(2);

4*a+2*b+c

f2 gedraagt zich zoals de gebruiker wil. De 'unapply' functie komt bijvoorbeeld van pas bij het plotten van uitdrukkingen. 'unapply' kan ook gebruikt worden voor functies in meerdere veranderlijken:

> f3 := unapply(sqrt(x^2 + y^2), x, y);

f3 := proc (x, y) options operator, arrow; (x^2+y^2)^(1/2) end proc

> f := 'f': g := 'g': Expr := 'Expr': f1 := 'f1': f2 := 'f2': f3 := 'f3':

Afleiden, reeksontwikkeling en integratie

Afleiden

Er zijn twee notaties voor afgeleiden, beide worden vaak gebruikt. De eenvoudigste is via de functie 'diff' (differentiate).

> f := x -> sin(x)*exp(x);

f := proc (x) options operator, arrow; sin(x)*exp(x) end proc

> diff(f(x), x);

cos(x)*exp(x)+sin(x)*exp(x)

> diff(f(x), x, x);

2*cos(x)*exp(x)

Voor hoger orde afgeleiden wordt dit wat omslachtig, maar we kunnen de sequence operator '$' gebruiken, voor de 5'de afgeleide bijvoorbeeld:

> diff(f(x), x$5);

-4*cos(x)*exp(x)-4*sin(x)*exp(x)

Voor functies en mengafgeleiden kan men analoog te werk gaan:

> g := (x,y) -> x^2*y^7;

g := proc (x, y) options operator, arrow; x^2*y^7 end proc

> diff(g(x,y), x);

2*x*y^7

> diff(g(x,y), x, y$3);

420*x*y^4

> f := 'f': g := 'g':

Reeksontwikkeling

Het is tamelijk vervelend een Taylorreeksontwikkeling uit te voeren, Maple is hier echter goed in.

> f := x -> sinh(x);

f := proc (x) options operator, arrow; sinh(x) end proc

> Expr1 := taylor(f(x), x = 0.0, 10);

Expr1 := series(x+1/6*x^3+1/120*x^5+1/5040*x^7+1/362880*x^9+O(x^10),x,10)

Indien we de bovenstaande uitdrukking gebruikt moet worden om verdere berekeningen mee uit te voeren levert dit problemen op.

> subs(x = 0.5, Expr1);

Error, invalid substitution in series

Het resultaat van 'taylor' is 'series', geen polynoom. 'Expr1' kan omgezet worden in een polynoom met behulp van 'convert'.

> Expr2 := convert(Expr1, polynom);

Expr2 := x+1/6*x^3+1/120*x^5+1/5040*x^7+1/362880*x^9

> subs(x = 0.5, Expr2);

.5210953055

Nu werkt de substitutie uiteraard wel.  De moeilijkheid kan omzeild worden door 'eval' te gebruiken in plaats van 'subs':

> eval(Expr1, x = 0.5);

.5210953055

Merk op dat bij 'taylor(e,x,n)'  termen van ten hoogste orde n-1 voorkomen.

> Expr1 := 'Expr1': Expr2 := 'Expr2': f := 'f':

Integratie

Maple kan zowel onbepaalde als bepaalde integralen berekenen.

> int(sin(3*x) + 5*x^2, x);

-1/3*cos(3*x)+5/3*x^3

Merk op dat Maple geen integratieconstante toevoegt: dit levert problemen op bij meervoudige onbepaalde integratie, de gebruiker moet in dat geval zelf constanten toevoegen.

> int(sin(3*x) + cos(2*x), x=0..Pi/4);

1/6*2^(1/2)+5/6

'infinity' kan als integratiegrens gebruikt worden:

> int(exp(-x^2/2), x=-infinity..infinity);

2^(1/2)*Pi^(1/2)

Numerieke integratie bekomt men mbv. 'evalf':

> evalf(int(sin(x)*log(x^2)/cosh(sqrt(x)), x=1.5..3.5));

.6294996973

Sommen, producten en limieten

Sommen

Het berekenen van sommen kan via het commando 'sum':

> sum(x^'k'/'k'!, 'k'=0..5);

1+x+1/2*x^2+1/6*x^3+1/24*x^4+1/120*x^5

Merk op dat er quotes staan zowel omheen de expressie als om de sommatie-index. Dit garandeert dat de variabele 'k' lokaal is en er geen ongewenste neveneffecten optreden als 'k' globaal al een waarde heeft.

Naast numerieke grenzen voor de sommatie kan men ook met geparametriseerde grenswaarden werken om zo speciale sommen te bekomen:

> factor(sum('k', 'k'=1..'n'));

1/2*n*(n+1)

Het is ook mogelijk met reeksen te werken:

> sum(x^'k'/'k'!, 'k'=0..infinity);

exp(x)

> sum(x^'k'/'k'!, 'k');

sum(x^k/factorial(k), k)

Producten

Een product kan berekend worden mbv. de functie 'product':

> product((x + a['k']), 'k'=0..3);

(x+a[0])*(x+a[1])*(x+a[2])*(x+a[3])

> product((x + a['k']), 'k');

product(x+a[k], k)

Een numeriek voorbeeld:

> product('k', 'k'=1..10);

3628800

Dit berekent  uiteraard de faculteit van 10:

> 10!;

3628800

Limieten

Limieten kunnen berekend worden met behulp van de 'limit' functie.

> limit(sin(x)/x, x=0);

1

> limit(abs(sin(x))/x, x=0, left);

-1

> limit(abs(sin(x))/x, x = 0, right);

1

Plots

Er zijn zeer veel types plots gedefinieerd in Maple, hier zullen slechts enkele van de meest courante vermeld worden.

> plot(sin(x), x=0..6*Pi);

[Plot]

Er kunnen meerdere functies op een grafiek gezet worden.

> plot([sin(x), sin(x)*exp(-0.2*x)], x=0..6*Pi);

[Plot]

Het interval op de y-as voor de plot kan opgegeven worden.

> plot(sin(x)*exp(-0.2*x), x=0..6*Pi, `sin(x)*exp(-0.2*x)`=0..1);

[Plot]

Vaak is het nuttig de meetkundige plaats gedefinieerd door de oplossingen van een vergelijking van twee veranderlijken weer te geven met behulp van een impliciete plot.  Neem als voorbeeld de vergelijking van de cirkel:

> plots[implicitplot](x^2 + y^2 = 1, x=-2..2, y=-2..2,
                   scaling=CONSTRAINED);

[Plot]

Het is ook mogelijk data te plotten die in de vorm van een lijst gegeven is.

> Lijst := [seq([i,i^2], i=0..10)];

Lijst := [[0, 0], [1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81], [10, 100]]

> plot(Lijst, style=point, symbol=CIRCLE);

[Plot]

Typisch gebruikt men dit soort plot voor het weergeven van meetgegevens of statistisch bekomen data.

> Lijst := 'Lijst':

Vergelijkingen

Lineaire eerste graads vergelijking

Het oplossen van vergelijkingne in Maple gebeurt met behulp van de functie 'solve'. Enkele voorbeelden:

> solve(3*x - 7 = 0, x);

7/3

Merk op dat er geen waarde toegekend is aan de variabele 'x':

> x;

x

Om aan 'x' de gevonden waarde toe te kennen kan men als volgt tewerk gaan:

> assign(solve({3*x - 7 = 0}, {x}));

> x;

7/3

Let op de '{}' rond de vergelijking en de onbekende.  Het is een goede gewoonte deze steeds te gebruiken, ook als men een vergelijking in een veranderlijke oplost.

Een klassieke vergissing is nu:

> solve(2*x - 1 = 0, x);

Error, (in solve) a constant is invalid as a variable, 7/3

'x' had natuurlijk nog de waarde 7/3. Voor 'x' opnieuw gebruikt kan worden moet men eerst de waarde wissen:

> x := 'x':

Substitutie is een veiliger methode dan het 'assign' commando, zo vermijdt men ongewenste neveneffecten.

> Opl := solve({3*x - 7 = 0}, x);

Opl := {x = 7/3}

> subs(Opl, x^2 - 1);

40/9

> Opl := 'Opl':

Lineaire vergelijking van hogere graad

Voor een vergelijking met meerdere oplossingen kan men als volgt werken:

> Opl := solve(3*x^2 + 5*x - 1 = 0, x);

Opl := -5/6+1/6*37^(1/2), -5/6-1/6*37^(1/2)

Indien men de wortels in verdere berekeningen wil gebruiken kan dit met 'Opl[1]' en 'Opl[2]', bv.:

> evalf(sin(Opl[1]));

.1794825374

Voor vergelijking van hogere graad kan het resultaat soms verrassend zijn:

> Opl := solve(x^5 + 7*x^4 - 3*x = 12, x);

Opl := RootOf(_Z^5+7*_Z^4-3*_Z-12, index = 1), RootOf(_Z^5+7*_Z^4-3*_Z-12, index = 2), RootOf(_Z^5+7*_Z^4-3*_Z-12, index = 3), RootOf(_Z^5+7*_Z^4-3*_Z-12, index = 4), RootOf(_Z^5+7*_Z^4-3*_Z-12, index...Opl := RootOf(_Z^5+7*_Z^4-3*_Z-12, index = 1), RootOf(_Z^5+7*_Z^4-3*_Z-12, index = 2), RootOf(_Z^5+7*_Z^4-3*_Z-12, index = 3), RootOf(_Z^5+7*_Z^4-3*_Z-12, index = 4), RootOf(_Z^5+7*_Z^4-3*_Z-12, index...

> map(evalf@allvalues, [Opl]);

[1.173890031, -0.3413645657e-1+1.150416387*I, -1.101872021, -7.003745096, -0.3413645657e-1-1.150416387*I]

Voor lineaire vergelijkingen levert 'allvalues' het resultaat voor een 'RootOf' type uitdrukking.  De functie 'map' komt aan bod in de sectie over sequences en lijsten.

> Opl := 'Opl':

Transcendente vergelijking

De volgende transcendente vergelijking levert problemen op:

> solve(tanh(x) = 0.5*x, x);

0.

Er wordt slechts één oplossing gevonden, hoewel een plot toont dat er drie zijn:

> plot([tanh(x), 0.5*x], x=-3..3);

[Plot]

De functie 'fsolve' (float solve) laat toe een interval te specifiëren waarin een oplossing gezocht moet worden.

> fsolve(tanh(x) = 0.5*x, x, 0.5..10.0);

1.915008048

Stelsel lineaire vergelijkingen

Een stelsel vergelijkingen kan eveneens opgelost worden met 'solve'.

> Opl := solve({3*x + 2*y = 2,
             2*x - 3*y = -1},

            {x, y});

Opl := {y = 7/13, x = 4/13}

> subs(Opl,x^2 - y^2);

(-33)/169

Voor een stelsel vergelijkingen van hogere graad is de manupilatie van de wortels iets moeilijker.

> Opl := evalf(
   allvalues(solve({3*x^2 + 4*x*y - y = 3, 2*x + y^2 = 1}, {x, y}))

);

Opl := {y = 3.244307630, x = -4.762766000}, {y = -1.260027234, x = -.2938343150}, {y = .3411931351+.7857846532*I, x = .7505223829-.2681043294*I}, {y = .3411931351-.7857846532*I, x = .7505223829+.26810...Opl := {y = 3.244307630, x = -4.762766000}, {y = -1.260027234, x = -.2938343150}, {y = .3411931351+.7857846532*I, x = .7505223829-.2681043294*I}, {y = .3411931351-.7857846532*I, x = .7505223829+.26810...

> subs(Opl[3], x*y);

.4667453523+.4982736137*I

'Opl[3]' selecteert de derde oplossing van de vier.

> Opl := 'Opl':

Stelsel transcendente vergelijkingen

Voor stelsels laat 'fsolve' eveneens toe een interval te  specifiëren voor elke onbekende.

> fsolve(
   {(x + 0.3)^2 + y^2 = 2,

     tanh(x + y) = x - y},

   {x, y}, {x=0..2, y=0..2}

);

{x = 1.095712365, y = .2280065670}

> fsolve(
   {(x+0.3)^2 + y^2 = 2,

     tanh(x+y) = x - y},

   {x, y}, {x=-2..0, y=-2..0}

);

{x = -1.578793208, y = -.6038939726}

Even visueel controleren met behulp van 'implicitplot':

> p1 := plots[implicitplot]((x+0.3)^2 + y^2 = 2, x=-2..2, y=-2..2,
                         color=red, scaling=CONSTRAINED):

> p2 := plots[implicitplot](tanh(x + y) = x - y, x=-2..2, y=-2..2,
                         color=blue):

> plots[display]({p1, p2});

[Plot]

> p1 := 'p1': p2 := 'p2':