Εισαγωγή στο αλγεβρικό πακέτο Maxima
Λεπτομέρειες μαθήματος
επεξεργασίαΠεριεχόμενα
επεξεργασία- Μία εισαγωγική προσέγγιση στο αλγεβρικό πακέτο MAXIMA και στον προγραμματισμό για φυσικούς.
Βιβλιογραφία
επεξεργασία- Επίσημος ιστοχώρος του MAXIMA[1]
Αξιολόγηση
επεξεργασία- Δύο εργαστηριακές ασκήσεις
Εισαγωγή
επεξεργασίαΤο Maxima είναι στον πυρήνα του μία γραμμή εντολών και σαν τέτοια δεν είναι ικανό να παρουσιάσει τις μαθηματικές εκφράσεις παρά μόνο σε επίπεδο χαρακτήρων ascii. Ίσως κάτι τέτοιο να ακούγεται απογοητευτικό αλλά ας ελπίζουμε να σας εκπλήξουν σε τέτοιο βαθμό οι ικανότητες που δεν θα είναι παρατηρήσιμη μία αδυναμία αισθητικής φύσης. Με την εγκατάσταση του Maxima στα Windows έχουμε στη διάθεση μας δύο γραφικά περιβάλλοντα εργασίας (GUI). Το πρώτο απο αυτά ονομάζεται XMaxima και είναι αυτό που θα χρησιμοποιήσουμε. Το δεύτερο το οποίο ονομάζεται wxMaxima είναι ένα πλήρες γραφικό περιβάλλον με έτοιμα «κουμπάκια» και «μενού» που κάνουν τη δουλειά για εμάς και μάλλον θα σας αποτρέψουν απο το να γνωρίσετε το Maxima σε βάθος. Παρά το γεγονός αυτό, το wxMaxima είναι αρκετά χρήσιμο στην περίπτωση που θέλουμε να εκτελέσουμε γρήγορα κάποια «πράξη». Το παράθυρο του XMaxima χωρίζεται σε δύο μέρη. Το πρώτο μισό αποτελεί τη γραμμή εντολών (κονσόλα) του Maxima, ενώ το δεύτερο μισό παρέχει αρχικά ένα σύντομο εγχειρίδιο. Στη γραμμή εντολών έχει εμφανιστεί, πέραν των πληροφοριών έκδοσης και άδειας, ο αριθμός εισόδου στη μορφή (%i1). Αυτός είναι ο τρόπος να μας δείχνει το Maxima ότι είναι έτοιμο να δεχτεί είσοδο. Αναλογικά η έξοδος θα παρουσιάζεται αριθμημένη στην ίδια μορφή (%o1). Όλα τα προγράμματα συμβολικής άλγεβρας έχουν κάποιους συντακτικούς κανόνες, μία δομημένη γλώσσα την οποία χρησιμοποιέι ο χρήστης για να επικοινωνίσει με το σύστημα του. Θεμελιώδους σημασίας στη γλώσσα του Maxima είναι οι τέσσερις βασικές πράξεις που τις δηλώνουμε με τα συνήθη σύμβολα «+» για την πρόσθεση, «-» για την αφαίρεση, «*» για τον πολλαπλασιαμσό και «/» για τη διαίρεση. Με μοναδική επιπλέον πληροφορία ότι κάθε στοιχείο εισόδου για να εκτελεστεί πρέπει να λήγει σε ελληνικό ερωτηματικό «;» και έπειτα να κτυπάμε το πλήκτρο enter μπορούμε να εκτελέσουμε όλες τις γνωστές πράξεις. Ας υποθέσουμε οτι θέλουμε να εκτελέσουμε τον πολλαπλασιασμό 2.279∙11.126, τότε απλά πληκτρολογούμε στη γραμμή εντολών:
(%i1) 2.279*11.126; (%o1) 25.356154 (%i2)
Υπάρχουν καταστάσεις στις οποίες θέλουμε να εκτελεστεί ή «πράξη» αλλά να μην εκτυπωθεί το αποτέλεσμα της στην οθόνη. Σε αυτές τις περιπτώσεις αντικαθιστούμε το ερωτηματικό «;» με το σύμβολο «$», όπως στο ακόλουθο παράδειγμα:
(%i2) a+a$ (%i3)
Για αυτούς που αναρωτιούνται ποιές είναι αυτές οι περιπτώσεις, ενδεικτικά αναφέρουμε το απλό παράδειγμα του ορισμού σταθερών, του οποίου σπάνια επιθυμούμε την έξοδο, έτσι χρησιμοποιούμε κατά κύριο λόγο «$».
Αρκετά όμως χρησιμοποιήσαμε το Maxima αντί για τον υπολογιστή τσέπης (είναι τουλάχιστον προσβλητικό και για τους δημιουργούς του!), ας περάσουμε στην επόμενη παράγραφο όπου θα δούμε τις βασικές συναρτήσεις/εντολες (και γράψαμε συναρτήσεις/εντολές γιατί οι εντολές του Maxima δεν είναι παρά συναρτήσεις σαν αυτές που θα μάθουμε να ορίζουμε αργότερα κι εμείς). Τέλος δηλώνουμε ότι από εδώ και στο εξής δε θα σημειώνουμε το γεγονός οτι πατάμε το πλήκτρο enter για την εκτέλεση των εντολών, καθώς επίσης όυτε και την επόμενη είσοδο, είναι σαφές ότι το Maxima με τη λήξη της εκτέλεσης μίας εντολής είναι έτοιμο να δεχτεί την επόμενη.
Απλοί αριθμητικοί υπολογισμοί
επεξεργασίαΟ συμβολισμός αρκετών συναρτήσεων, όπως για παράδειγμα των τριγωνομετρικών είναι ίδιος με αυτόν που έχουμε γνωρίσει σε μαθήματα μαθηματικών και φυσικής, έτσι έχουμε τις αντίστοιχες συναρτήσεις του Maxima sin(x), cos(x),.... Όσο για τις μαθηματικές σταθερές υπάρχει ο απλός κανόνας ότι αρχίζουν με to σύμβολο «%» και ακολουθεί η καθιερωμένη λατινική τους γραφή, παραδείγματος χάριν η μιγαδική μονάδα συμβολίζεται στο Maxima «%i», ενώ το γράφεται σαν «%pi».
(%i1) %i*%i; (%o1) -1 (%i2) %pi*%pi; (%o2) %pi^2
Παρακάτω δίνουμε τις βασικές πράξεις, σταθερές και συναρτήσεις:
- Πρόσθεση, αφαίρεση, πολλαπλασιασμός, διαίρεση, δύναμη
+, -, *, /, ^
ή**
-
%e
-
%pi
-
inf, minf
-
%i
-
%phi
- Εκθετικό, λογάριθμος
exp(...), log(...)
- Τριγωνομετρικές
sin(...), cos(...), tan(...),...
- Αντίστροφες τριγωνομετρικές
asin(...), acos(...), atan(...),...
- Υπερβολικές τριγωνομετρικές
sinh(...), cosh(...), tanh(...),...
- Αντίστροφες υπερβολικές τριγωνομετρικές
asinh(...), acosh(...), atanh(...),...
- Απόλυτη τιμή, τετραγωνική ρίζα, πρόσημο
abs(...), sqrt(...), sign(...)
Αφού τώρα πλέον γνωρίζουμε κάποιες συναρτήσεις ας επιδοθούμε στο να δοκιμάζουμε το Maxima εκτελώντας υπολογισμούς.
(%i1) sin(0.4); (%o1) 0.38941834230865 (%i2) log(1.5); (%o2) 0.40546510810816 (%i3) cos(%pi/3); (%o3) 1/2 (%i4) sin(2); (%o4) sin(2)
όπου παρατηρούμε ότι όλα πήγαιναν καλά μέχρι τον υπολογισμό του sin(2) που το Maxima μας επέστρεψε την αντίστοιχη είσοδο. Το γιατί είναι πολύ απλό. Το Maxima επιστρέφει την είσοδο όταν δεν μπορεί να δώσει απάντηση ίδιας ακρίβειας με αυτήν της μεταβλητής της εισόδου. Αν αντί sin(2) γράψουμε sin(2.0) θα έχουμε:
(%i5) sin(2.0); (%o5) 0.90929742682568
Ένας άλλος τρόπος να αναγκάσουμε το Maxima να μας δώσει την αριθμητική τιμή μίας οποιασδήποτε έκφρασης είναι οι εντολές float(x) και bfloat(x) των οποίων η χρήση γίνεται κατανοητή στα ακόλουθα παραδείγματα:
(%i6) float(sin(2)); (%o6) 0.90929742682568 (%i7) bfloat(sin(2)); (%o7) 9.092974268256817b-1
όπου η bfloat δίνει το αποτέλεσμα με την πλήρη ακρίβεια των 16 ψηφίων που χρησιμοποιεί η μηχανή. Αν ζητήσουμε την τιμή της μεταβλητής fpprec θα πάρουμε την απάντηση 16. Αυτή είναι η μεταβλητή που καθορίζει την ακρίβεια της bfloat, έτσι για παράδειγμα μπορούμε να ορίσουμε ακρίβεια 100 σημαντικών ψηφίων αλλάζοντας την τιμή της fpprec δίνοντας fpprec:100, όπου : (και οχι το ίσον =) είναι ο τελεστής ανάθεσης τιμής.
(%i8) fpprec:100$ (%i9) bfloat(%e); (%o9) 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427b0
Θα ολοκληρώσουμε αυτή την παράγραφο σημειώνοντας ότι μπορούμε να αναφερθούμε στο αποτέλεσμα οποιασδήποτε εξόδου με χρήση του αύξοντα αριθμού της ως εξής:
(%i10) sin(%o9); (%o10) 4.107812905029086954760094920183605918883069703934153453045716588061351824376549958759786190454355935b-1
Όρια, παράγωγοι και ολοκληρώματα
επεξεργασίαΟι εντολές αυτής της παραγράφου προέρχονται απο το διαφορικό και ολοκληρωτικό λογισμό και έχουν την απλή γενική σύνταξη:
εντολή(έκφραση,μεταβλητή,τιμή,επιλογές)
όπου το όρισμα της τιμής είναι μία ή δύο αριθμητικές τιμές χωρισμένες με κόμμα και σε κάποιες περιπτώσεις είναι προεραιτικό.
Όρια. Ο υπολογισμός του ορίου της συνάρτησης f(x) όταν x→a γίνεται με την εντολή limit(f(x),x,a), στην οποία μπορούμε να προσθέσουμε την επιλογή plus ή minus για τον υπολογισμό των πλευρικών ορίων.
(%i1) limit((3*x-2)/(9*x+7),x,inf); (%o1) 1/3 (%i2) limit(1/(3+2^(1/x)),x,0); (%o2) und (%i3) limit(1/(3+2^(1/x)),x,0,plus); (%o3) 0 (%i4) limit(1/(3+2^(1/x)),x,0,minus); (%o4) 1/3
Στη δεύτερη είσοδο το Maxima απαντάει ότι το όριο δεν ορίζεται, γεγονός που εύκολα μπορούμε να ελέγξουμε υπολογίζοντας τα πλευριά όρια. Ένας τέτοιος υπολογισμός μας πείθει μιας και γνωρίζουμε ότι όταν το όριο δεν ορίζεται.
Παράγωγοι. Για να παραγωγίσουμε μία συνάρτηση f(x) χρησιμοποιούμε την εντολή diff(f(x),x,k) όπου k η τάξη της παραγώγισης, ενώ όταν k=1 μπορούμε να το παραλείψουμε.
(%i5) sin(x)*cos(x); (%o5) cos(x)sin(x) (%i6) diff(%,x); (%o6) cos^2(x)-sin^2(x) (%i7) diff(%o1,x,2); (%o7) -4cos(x)sin(x)
Επίσης με την ίδια εντολή μπορούμε να υπολογίσουμε τη μικτή παράγωγο όπως στο ακόλουθο παράδειγμα:
(%i8) diff(log(x^y),x,2,y,1); (%o8) -1/x^2 (%i9) diff(diff(log(x^y),y),x,2); (%o9) -1/x^2
όπου εκτελείται η παραγώγιση .
Ολοκληρώματα. Τέλος ο υπολογισμός του αόριστου και του ορισμένου ολοκληρώματος της συνάρτησης f(x) γίνεται αντίστοιχα με τις εντολές integrate(f(x),x) και integrate(f(x),x,x0,xf) όπως δείχνει το παρακάτω παραδείγμα.
(%i10) integrate(m^2*exp(-a*m),m); (%o10) –((a^2*m^2+2*a*m+2)%e^(-a*m))/a^3
Υπάρχουν σίγουρα και ολοκληρώματα των οποίων ο υπολογισμός γίνεται πιο πολύπλοκος όπως για παράδειγμα αυτός του
(%i11) float(integrate(sin(x^2),x,0,1)); (%o11) 0.22155673136319((1.414213562373095%i+1.414213562373095)erf(0.5(1.414213562373095%i+ 1.414213562373095))+(1.414213562373095%i-1.414213562373095)erf(0.5(1.414213562373095%i- 1.414213562373095)))
που όπως βλέπουμε το αποτέλεσμα δίνεται σα συνάρτηση της συνάρτησης σφάλματος erf(...). Αυτό που είναι γνωστό για τη συνάρτηση αυτή είναι ότι η παράγωγος της είναι 2*exp(-x^2)/sqrt(%pi).
Εισαγωγή στα γραφικά
επεξεργασίαΚαι ερχόμαστε τώρα στις εντολές σχεδιασμού γραφικών παραστάσεων. Πριν όμως ας σημειώσουμε ότι το Maxima σχεδιάζει με χρήση του gnuplot ή του openmath και αυτό το κάνει να εμπεριέχει όλα τα πλεονεκτήματα και μειονεκτήματα αυτών των σχεδιαστικών πακέτων.
Η εντολή για την παραγωγή 2D γραφικών είναι η plot2d και στην πιο απλή της εκδοχή plot2d(f(x),[x,x0,xf]), η οποία δίνει τη γραφική παράσταση της συνάρτησης f(x) στο διάστημα [x0,xf].
(%i1) plot2d(x^2*cos(x),[x,0,10*%pi]);
Σχήμα 1: Η γραφική παράσταση της συνάρτησης f(x)=x^2 cos(x) όπως δίνεται σαν έξοδος της (%i1).
που όπως βλέπουμε στο σχήμα 1 οι άξονες του γραφήματος ονομάζονται αυτόματα. Όμως η εντολή plot2d όπως και πολλές άλλες εντολές επιδέχονται μία σειρά απο προσθήκες στη βασική τους σύνταξη. Έτσι για παράδειγμα μπορούμε να ορίσουμε το κατακόρυφο διάστημα που θα παραχθεί στην έξοδο και αυτό δε γίνεται παρά με το να προσθέσουμε [y,a,b] στην εντολή μας.
(%i2) plot2d(sin(x),[x,0,4*%pi],[y,-1.5,1.5]);
Σχήμα 2: Η γραφική παράσταση της συνάρτησης f(x)=sin(x) όπως δίνεται σαν έξοδος της (%i2).
Μία άλλη δυνατότητα που θα θέλαμε να έχουμε έιναι αυτή του σχεδιασμού δύο ή και παραπάνω γραφικών παραστάσεων στο ίδιο σύστημα αξόνων. Αυτό επιτυγχάνεται στο Maxima ομαδοποιώντας με αγκύλες τις συναρτήσεις που θέλουμε να σχεδιάσουμε (δημιουργώντας δηλαδή μία λίστα).
(%i3) plot2d([x^2,10*cos(x),x^2*cos(x)],[x,0,4*%pi]);
Σχήμα 3: Σχεδισμός των γραφικών παραστάσεων των συναρτήσεων f(x)=x^2, g(x)=10cos(x) και h(x)=x^2cos(x) στο ίδιο σύστημα αξόνων όπως δίνεται σαν έξοδος της (%i3).
Τέλος μπορούμε να σχεδιάσουμε καμπύλες που δίνονται σε παραμετρική μορφή x=f(t),y=g(t) με την εντολή plot2d([parametric, f(t),g(t),[t,a,b]]).
(%i4) plot2d([parametric,cos(t)*(1-cos(t)),sin(t)*(1-cos(t)^2),[t,0,2*%pi],[nticks,80]]);
Σχήμα 4: Σχεδιασμός της καμπύλης που δίνεται από τις παραμετρικές εξισώσεις f(t)=cos(t)(1-cos(t)) και g(t)=sin(t)(1-cos(t)^2) όπως δίνεται σαν έξοδος της (%i4).
όπου επιπλέον χρησιμοποιήσαμε το όρισμα [nticks,80] που καθορίζει τον αριθμό των σημείων που θα χρησιμοποιηθούν κατά το σχεδιασμό της γραφικής παράστασης.
Ορισμός συναρτήσεων
επεξεργασίαΌπως έχουμε είδη αναφέρει ο τελεστής ανάθεσης τιμών είναι «:», έτσι μπορούμε να δώσουμε ένα όνομα σε μία σταθερά ή σε ολόκληρες εκφράσεις που μπορεί να περιέχουν και μεταβλητές. Με αυτό τον τρόπο μπορούμε να καλούμε αυτές τις εκφράσεις χωρίς να είμαστε υποχρεωμένοι να τις ξαναγράφουμε. Για τον ορισμό μίας σταθεράς αρκεί αριστερά απο τον τελεστή «:» να δώσουμε το όνομα της αρεσκείας μας και δεξιά την ποσότητα που επιθυμούμε.
(%i1) x:9$ (%i2) sqrt(x); (%o2) 3
Στην περίπτωση που θέλουμε να αποδεσμεύσουμε το όνομα απο την ποσότητα που του έχουμε αναθέσει δεν έχουμε παρά να πληκτρολογήσουμε:
(%i3) remvalue(x)$ (%i4) x; (%o4) x
Επίσης μπορούμε να καλέσουμε την εντολή remvalue με όρισμα all ώστε να αποδεσμέυσουμε όλα τα ονόματα απο τις τιμές ή τις εκφράσεις που τους έχουμε αποδώσει.
(%i5) x:x+1$ (%i6) y:2$ (%i7) z:x+1$ (%i8) remvalue(all)$ (%i9) x;y;z; (%o9) x, y, z
Συναρτήσεις. Ο ορισμός συναρτήσεων γίνεται με τον τελεστή := και χρησιμοποιώντας παρενθέσεις για τις μεταβλητές:
f(x)=έκφραση→f(x):=έκφραση
Έχοντας ορίσει μία συνάρτηση μπορούμε να υπολογίσουμε την τιμή της σε οποιοδήποτε σημείο του πεδίου ορισμού της, να υπολογίσουμε τη σύνθεση με τον εαυτό της ή και με άλλες συναρτήσεις, να την παραγωγίσουμε κ.ο.κ. Θα φανεί αργότερα από το κείμενο η σημασία των συναρτήσεων, αλλά τώρα μπορούμε να αναφέρουμε τη σημαντικότητα τους στο προγραμματιστικό περιβάλλον του Maxima. Ακολουθούν μερικά απλά παραδείγματα.
(%i10) f(x):=x^2-4*x+3$ (%i11) f(5); (%o11) 8 (%i12) f(a-b); (%o12) (a-b)^2-4*(a-b)+3 (%i13) f(f(x)); (%o13) (x^2-4*x+3)^2-4*(x^2-4*x+3)+3 (%i14) diff(f(x),x); (%o14) 2*x-4
Ο καθαρισμός της μνήμης από τις συναρτήσεις γίνεται με την εντολή remfunction η οποία, όπως και η remvalue, μπορεί να καλεστεί με όρισμα την επιλογή all.
(%i15) remfunction(f)$ (%i16) remfunction(all)$
Πρέπει να είμαστε προσεκτικοί όταν ζητάμε την τιμή μίας συνάρτησης σε κάποιο x. Στο ακόλουθο παράδειγμα δείχνουμε πως μπορεί κάποιος να απορεί για το αποτέλεσμα του.
(%i17) x:3$ ⋮ (%i25) f(x):=x^2; (%o25) f(x):=x^2 (%i26) f(x); (%o26) 9
όπου παρατηρούμε ότι η συνάρτηση ορίζεται σωστά παρα το ότι έχουμε δώσει την τιμή 3 στο x, αλλά όταν ζητήσουμε την τιμή της στο x είναι σα να ζητάμε την f(3)=9.
Κλείνουμε αυτή την παράγραφο με την εντολή block της οποίας το όρισμα είναι μία σειρά από εντολές χωρισμένες με κόμμα. Η block επιστρέφει την τιμή της τελευταίας έκφρασης αν δεν ζητηθεί κάτι άλλο ενώ αργότερα θα δούμε ότι συναρτήσεις της μορφής f(x,y,z,…):=block([a,b,…],…,…,…) όπου το πρώτο όρισμα της block είναι μία λίστα των τοπικών μεταβλητών, αποτελούν τον πυρήνα των προγραμμάτων που θα κατασκευάσουμε.
Αλγεβρικές εξισώσεις
επεξεργασίαΣε αυτή την παράγραφο θα ασχοληθούμε με την αναλυτική και αριθμητική λύση αλγεβρικών εξισώσεων, πριν από αυτό όμως είναι απαραίτητο να αναφερθούμε σε μερικές βασικές εντολές για την παραγοντοποίηση ή ανάπτυξη αλγεβρικών και τριγωνομετρικών εκφράσεων.
- factor(f(x)): Παραγοντοποίηση πολυωνύμων
(%i1) f(x):=x^2+x-6$ (%i2) factor(f(x)); (%o2) (x-2)(x+3)
- expand(f(x)): Ανάπτυξη πολυωνύμων
(%i3) f(x):=(x+3)^3$ (%i4) expand(f(x)); (%o4) x^3+9*x^2+27*x+27
- ratsimp(f(x)): Απλοποίηση ρητών εκφράσεων
(%i5) f(x):=(x^2-1)/(x+1)$ (%i6) ratsimp(f(x)); (%o6) x-1
- trigepand(f(x)): Ανάπτυξη τριγωνομετρικών εκφράσεων
(%i7) f(x):=sin(2*x)+cos(2*x)$ (%i8) trigexpand(f(x)); (%o8) –sin(x)^2+2*cos(x)sin(x)+cos(x)^2
- trigsimp(f(x)): Απλοποίηση τριγωνομετρικών εκφράσεων
(%i9) f(x):=2*cos(x)^2+sin(x)^2$ (%i10) trigsimp(f(x)); (%o10) cos(x)^2+1
Η λύση αλγεβρικών εξισώσεων επιτυγχάνεται με τις εντολές
solve(f(x)), allroots(f(x)), find_root(f(x)).
Η πρώτη απο αυτές αναζητά ακριβείς λύσεις, η δεύτερη υπολογίζει αριθμητικά τις ρίζες πολυωνυμικών εξισώσεων και η τελευταία υπολογίζει επίσης αριθμητικά μία ρίζα οποιασδήποτε εξίσωσης. Οι εξισώσεις μπορούν να γραφούν είτε σαν f(x)=g(x) είτε απλά σαν f(x)-g(x) όπου το Maxima θα υποθέσει ότι η ζητούμενη εξίσωση είναι η f(x)-g(x)=0.
(%i11) solve(x^3-3*x^2-x+3,x); (%o11) [x=1,x=-1,x=3] (%i12) allroots(x^3+3*x+1); (%o12) [x=-0.32218535462609, x=1.754380959783722%i+0.16109267731304, x=0.16109267731304-1.754380959783722%i] (%i13) find_root(cos(x)=x,x,0,1); (%o13) 0.73908513321516
Αν μία μη πολυωνυμική εξίσωση f(x)=0 έχει περισσότερες της μία ρίζες, αυτές πρέπει να αναζητηθούν μία προς μία με την find_root επιλέγοντας κατάλληλο διάστημα αναζήτησης. Μπορούμε να σχεδιάσουμε την f(x) ώστε να προσδιορίσουμε γραφικά αυτά τα διαστήματα. Τέλος μπορούμε να χρησιμοποιήσουμε την find_root για την εύρεση των ακρότατων μίας συνάρτησης f(x) ως ακολούθως find_root(diff(f(x),x),x,a,b).
Λίστες
επεξεργασίαΣε αυτή την παράγραφο θα ασχοληθούμε με την παραγωγή στοιχείων που ονομάζονται λίστες. Κάθε λίστα αποτελείται από έναν αριθμό στοιχείων εγκλεισμένα σε αγκύλες που αριθμούνται με δείκτη
[s_1,s_2,…,s_n]→[s[1],s[2],…,s[3]]
Αν γυρίσετε πίσω στο κείμενο θα διαπυστώσετε ότι υπάρχουν περιπτώσεις στις οποίες οι έξοδοι δόθηκαν από το Maxima σαν λίστες στοιχείων. Μπορούμε να ορίσουμε λίστες ως εξής:
(%i1) s:[a,b,c,d]; (%o1) [a,b,c,d]
καθώς και να καλέσουμε οποιοδήποτε στοιχείο της λίστας γράφοντας τον αύξοντα αριθμό του μέσα σε αγκύλες όπως παρακάτω:
(%i2) s[3]; (%o2) c
Πέρα όμως απο αυτές τις λίστες, των οποίων τα στοιχεία έχουν οριστεί ένα προς ένα απο το χρήστη μπορούμε να παράγουμε λίστες των οποίων τα στοιχεία υπακούουν σε κάποιον κανόνα με την εντολή
makelist(f(n),n,n0,nf)
Ο κανόνας ορίζεται απο τη συνάρτηση f(n) και το αποτέλεσμα της εντολής είναι η λίστα [f(n0),f(n0+1),…,f(nf)].
(%i3) s:makelist(n!,n,1,10); (%o3) [1,2,6,24,120,720,5040,40320,362880,3628800]
όπου το n πηγαίνει από το ένα μέχρι το δέκα με βήμα ένα. Φυσικά μπορούμε να σχεδιάσουμε τα στοιχεία μίας λίστας σαν συνάρτηση του αύξοντα αριθμού των στοιχείων της.
(%i4) x:makelist(n,n,0,20)$ (%i5) y:makelist(n^3,n,0,20)$ (%i6) plot2d([discrete,x,y],[style,points]);
Σχήμα 5: Σχεδισμός των διακριτών στοιχείων της λίστας που ορίζεται στην είσοδο (%i5) σαν συνάρτηση του δείκτη των στοιχείων της όπως δίνεται σαν έξοδος της (%i6).
Είναι σχεδόν αυτονόητο ότι μπορούμε να παράγουμε λίστες με στοιχεία άλλες λίστες, παραδείγματος χάριν με την εντολή s:makelist([f(n),g(n)],n,n0,nf). Σε αυτή την περίπτωση η s[i][j] επιστρέφει το j στοιχείο του i στοιχείου λίστας. Επίσης η length(λίστα) επιστρέφει τον αριθμό των στοιχείων μιας λίστας, ενώ η append(s1,s2,…,sn) επιστρέφει μία λίστα με τα στοιχεία της λίστας s1 ακολουθούμενα απο τα στοιχεία της s2 κ.ο.κ. Προσέξτε ότι για την προσθήκη ενός μόνο στοιχείου q σε μία λίστα s πρέπει να γράψουμε append(s,[q]).
Στοιχειώδης προγραμματισμός
επεξεργασίαΣε αυτή την παράγραφο θα εισαχθούμε στο προγραμματιστικό περιβάλλον του Maxima. Για να επιτύχουμε αυτό το άλμα θα πρέπει να αναφέρουμε τα προγραμματιστικά στοιχεία του Maxima, ενώ φυσικά οι έτοιμες συναρτήσεις που είδη γνωρίζουμε θα φανούν πολύ χρήσιμες. Να τονίσουμε ότι δε θα χρησιμοποιούμε αριθμούς εισόδου – εξόδου όπως κάναμε μέχρι τώρα. Ας αρχίσουμε με τη δήλωση λογικής συνθήκης if με το παρακάτω παράδειγμα
f1(x):=if x<1 then 1 else x*f1(x-1)$ f1(5); 120
όπου εκτελέστηκε ο υπολογισμός f(5)=5f(4)=5(4f(3))=20(3f(2))= 60(2f(1))=120. Το ίδιο παράδειγμα μπορεί να γραφτεί με χρήση της εντολής while ως εξής
f2(x):=block([t],t:1,while x>1 do (t:x*t,x:x-1),t)$ f2(5); 120
όπου το πρώτο μέρος της block περιέχει μία λίστα με τις τοπικές μεταβλητές. Αν μας ρωτούσαν «είναι το Α μεγαλύτερο απο το Β;» θα μπορούσαμε να απαντήσουμε με «ναι» ή «όχι». Βέβαια στην περίπτωση που τα δεδομένα που μας δίνουν για τα Α και Β δεν είναι αρκετά για να πάρουμε μία απόφαση θα μπορούσαμε να απαντήσουμε «δεν είμαι σε θέση να γνωρίζω». Ας δούμε ένα παράδειγμα που θα κάνει αυτόν τον έλεγχο
test(x,y):=block([], if x>y then print(x,”is greater than”,y) elseif x<y then print(x,”is smaller than”,y) elseif x=y then print(x,”is equal to”,y) else print(”who knows!”), return(alldone))$
η εκτέλεση του οποίου δίνει τα εξής
test(1,2); 1 is smaller than 2 alldone test(3,2); 3 is greater than 2 alldone test(%i,2); who knows! alldone test(x**2+3,2); x**2+3 is greater than 2 alldone test(x**2+2,2); alldone
όπου στο τελευταίο παράδειγμα το Maxima δεν ειναι σε θέση να γνωρίζει την απάντηση. Γιατί όμως δε δίνει στην έξοδο who knows!; Αυτό συμβαίνει γιατί το Maxima δε γνωρίζει ποιά σχέση υπάρχει μεταξύ των στοιχείων που δώσαμε και απο τη στιγμή που η μεταβλητή prederror; επιστρέφει false η εκτέλεση συνεχίζει στην επόμενη δήλωση. Για να λύσουμε το πρόβλημα μας θα μπορούσαμε να θεωρήσουμε ότι το x>0 με την παρακάτω εντολή
assume(x>0)$ test(x**2+2,2); x**2+2 is greater than 2 alldone
ενώ αν θέλουμε να ξεχαστεί η υπόθεση μας πληκτρολογούμε forget(x>0). Ένα άλλο σημαντικό στοιχείο είναι η κατασκευή συναρτήσεων με τυχαίο αριθμό μεταβλητών εισόδου. Η επίτευξη είναι σχετικά απλή αν σκεφτούμε ότι το όρισμα μπορεί να είναι μία λίστα στοιχείων
prog([list]):=block([], print(”your list is”,list,”and its length is”), return(length(list)))$ prog(1,2,3,4,5,6,a); your list is [1,2,3,4,5,6,a] and its length is 7
Στοιχείο κάθε σύγχρονης γλώσσας προγραμματισμού είναι οι πίνακες (της προγραμματιστικής ορολογίας, σαν απόδοση δηλαδή του όρου array). Ο ορισμός ενός τέτοιου πίνακα στο Maxima είναι απλός και μπορεί να έχει μία από τις παρακάτω μορφές
a[3]:2*x$ a[x]:mystery$ a[x]:=cos(x)$ a[x+1]; cos(x+1)
ενώ μετά από όλα αυτά
a; a
Μπορούμε να πάρουμε πληροφορίες για τον πίνακα με χρήση της εντολής arrayinfo(a); [hashed,1,[3],[x],[x+1]]. Ένα άλλο σημαντικό στοιχείο στη δομή των γλωσσών προγραμματισμού είναι οι επαναληπτικοί βρόγχοι.
f(n):=block([temp],temp:1 for i:1 step 1 thru n do(temp:temp*i,print(temp)) return(temp))$ f(4); 1 2 6 24 24
Όπου παρατηρούμε ότι μπορούμε να ομαδοποιούμε μία σειρά από εντολές με τη χρήση παρενθέσεων. Πριν δώσουμε ένα πιο χρήσιμο και πιο πολύπλοκο παράδειγμα θα σημειώσουμε τις εντολές αποθήκευσης και κλήσης αρχείων και συναρτήσεων.
save(filename,all): αποθήκευση ολόκληρου του χώρου εργασίας.
save(filename,funcs): αποθήκευση συναρτήσεων.
load(filename): κλήση αποθηκευμένου αρχείου.
Πίνακες
επεξεργασίαΟρισμός πινάκων και βασικές πράξεις
επεξεργασίαΗ άλγεβρα πινάκων είναι από τα πιο σημαντικά μέρη στην εκπαίδευση ενός εφαρμοσμένου επιστήμονα (φυσικού,μηχανικού κ.ο.κ.) και σαν τέτοια δε θα μπορούσε να λείπει απο ένα πακέτο συμβολικών μαθηματικών.
Το Maxima παρέχει την εντολή matrix για τον ορισμό πινάκων, της οποίας η σύνταξη είναι
matrix([γραμμή1],[γραμμή2],…,[γραμμήn])
όπου όπως παρατηρούμε κάθε γραμμή είναι μία λίστα στοιχείων.
(%i1) A:matrix([1,2],[4,9]); (%o1) [1 2] [ ] [4 9]
Οι πράξεις «+», «-», «*», «/» και «^» εκτελούνται στοιχείο προς στοιχείο, ο συνήθης μη μεταθετικός πολλαπλασιασμός πινάκων συμβολίζεται με μία τελεία «.» μεταξύ των πινάκων, ενώ τέλος η μη μεταθετική δύναμη συμβολίζεται με «^^».
(%i2) B:matrix([1,3],[2,2])$ (%i3) A+B; (%o3) [2 5] [ ] [6 11] (%i4) A-B; (%o4) [0 -1] [ ] [2 7] (%i5) A*B; (%o5) [1 6] [ ] [8 18] (%i6) A.B; (%o6) [5 7] [ ] [22 30] (%i7) A/B; (%o7) [1 2/3] [ ] [2 9/2] (%i8) A^B; (%o8) [1 3] [ ] [2 2] [1 2] [ ] [4 9] (%i9) B^2; (%o9) [1 9] [ ] [4 4] (%i10) A^^-1; (%o10) [9 -2] [ ] [-4 1]
όπου στην (%o10) έχουμε τον αντίστροφο του πίνακα Α. Τέλος να σημειώσουμε ότι όταν έχουμε βαθμωτή βάση υψωμένη σε δύναμη πίνακα οι τελεστές «^» και «^^» δίνουν το ίδιο αποτέλεσμα δράσης στοιχείο προς στοιχείο.
Συναρτήσεις χειρισμού πινάκων
επεξεργασίαΟι εντολές που θα δούμε σε αυτή την παράγραφο είναι οι:
entermatrix, zeromatrix, ident, diagmatrix, row, col, addrow, addcol, invert, transpose, determinant, charpoly, eigenvalues και eigenvectors
Η «πράξη» που εκτελεί η κάθε εντολή είναι σχεδόν προφανής, αυτό που θα δούμε με χρήση παραδειγμάτων είναι η σύνταξη τους.
Η entermatrix είναι η διαδραστική ισοδύναμη της matrix, συνεπώς σκοπό έχει τη δημιουργία πινάκων. Δέχεται σαν όρισμα τη διάσταση του πίνακα που θέλουμε να δημιουργίσουμε και έπειτα αλληλεπιδρά με το χρήστη ώστε να του επιστρέψει τον πίνακα αυτόν.
(%i1) A:entermatrix(3,3); Is the matrix 1.Diagonal 2.Symmetric 3.Antisymmetric 4.General Answer 1, 2, 3 or 4 : 1; Row 1 Column 1: 2; Row 2 Column 2: 2; Row 3 Column 3: 2; Matrix entered. (%o1) [2 0 0] [ ] [0 2 0] [ ] [0 0 2]
Η εντολή zeromatrix δέχεται σαν όρισμα τον αριθμό γραμμών και στηλών ώστε να επιστρέψει έναν πίνακα αυτών των διαστάσεων με όλα τα στοιχεία του μηδενικά.
(%i2) zeromatrix(2,4); (%o2) [0 0 0 0] [ ] [0 0 0 0]
Η ident επιστρέφει το μοναδιαίο n×n πίνακα, συνεπώς:
(%i3) ident(2); (%o3) [1 0] [ ] [0 1]
Κλείνουμε τις εντολές κατασκευής πινάκων με την diagmatrix(n,x), η οποία επιστρέφει τον n×n διαγώνιο πίνακα του οποίου τα στοιχεία είναι όλα x. Έχουμε δηλαδή ότι ident(n)=diagmatrix(n,1).
(%i4) diagmatrix(2,x^3); (%o4) [x^3 0] [ ] [0 x^3]
Η εξαγωγή γραμμών ή στηλών ενός πίνακα Μ γίνεται με τις εντολές row(M,n) και col(M,n) των οποίων τα στοιχεία επιστροφής είναι πίνακες.
(%i5) M:matrix([a,b],[c,d])$ (%i6) row(M,2); (%o6) [c d] (%i7) col(M,1); (%o7) [ a ] [ ] [ c ]
Η προσθήκη γραμμών ή στηλών γίνεται με τις εντολές addrow(M,λίστα1,λίστα2,...) και addcol(M,λίστα1,λίστα2,...) αντίστοιχα.
(%i8) addrow(M,[e,f]); (%o8) [ a b ] [ ] [ c d ] [ ] [ e f ] (%i9) addcol(M,[e,f]); (%o9) [ a b e ] [ ] [ c d f ]
Οι εντολές invert, transpose και determinant δέχονται σαν όρισμα έναν πίνακα M και επιστρέφουν τον αντίστροφο, τον πίνακα που προκύπτει αν κάνουμε τις γραμμές στήλες και την ορίζουσα του πίνακα M αντίστοιχα.
(%i10) invert(M); (%o10) [ d b ] [ --------- - ---------] [ a d – b c a d - b c] [ ] [ c a ] [ - --------- --------- ] [ a d - b c a d - b c ] (%i11) transpose(M); (%o11) [a c] [ ] [b d] (%i12) determinant(M); (%o12) ad-bc
Η εντολή charpoly επιστρέφει άλυτο το χαρακτηριστικό πολυώνυμο ενός πίνακα A. Φυσικά το χαρακτηριστικό πολυώνυμο μπορεί έπειτα να λυθεί με μία απο τις εντολές επίλυσης αλγεβρικών εξισώσεων.
(%i13) A:matrix([3,1],[2,4])$ (%i14) expand(charpoly(A,lambda)); (%o14) lambda^2-7lambda + 10 (%i15) sol:solve(%); (%o15) [lambda=5,lambda=2] (%i16) sol[1];sol[2]; (%o16) lambda=5 (%o17) lambda=2
Οι εντολές eigenvalues και eigenvectors δέχονται σαν όρισμα έναν πίνακα του οποίου επιστρέφουν τις ιδιοτιμές και τα ιδιοδιανύσματα όπως στο ακόλουθο παράδειγμα:
(%i18) eigenvalues(A); (%o18) [[5,2],[1,1]] (%i19) eigenvectors(A); (%o19) [[[5,2],[1, 1]],[1, 2],[1,-1]]
Όπως βλέπουμε και οι δύο εντολές επιστρέφουν λίστες με στοιχεία λίστες. Στην έξοδο (%o18) το πρώτο στοιχείο λίστα περιέχει τις ιδιοτιμές ενώ το δεύτερο τις πολλαπλότητες αυτών αντίστοιχα.