1 / 26

Στατική Συμβολική Παραγώγιση Λάμδα Εκφράσεων στην C++

Στατική Συμβολική Παραγώγιση Λάμδα Εκφράσεων στην C++. Η βιβλιοθήκη λ& d++. λάμδα εκφράσεις>τί είναι;>στον λ-λογισμό. Τί είναι λοιπόν οι λάμδα εκφράσεις;

baby
Download Presentation

Στατική Συμβολική Παραγώγιση Λάμδα Εκφράσεων στην C++

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Στατική Συμβολική ΠαραγώγισηΛάμδα Εκφράσεων στην C++ Η βιβλιοθήκη λ&d++.

  2. λάμδα εκφράσεις>τί είναι;>στον λ-λογισμό • Τί είναι λοιπόν οι λάμδα εκφράσεις; • Ο όρος λάμδα έκφραση προέρχεται από τον λάμδα λογισμό του Alonzo Church ο οποίος είναι ένα υπολογιστικό μοντέλο αντίστοιχο των μηχανών Turing, δηλαδή μια μαθηματική θεωρεία που σκοπό έχει να ορίσει τί είναι υπολογισμός και να ερευνήσει το τί είναι υπολογίσιμο και τί όχι. • Ο λ-λογισμός ορίζει την γλώσσα των λ-όρων σαν την γλώσσα που παράγεται από τον κανόνα: • <λ-όρος>::=<μεταβλητή>|(λ<μεταβλητή>.<λ-όρος>)|(<λ-όρος><λ-όρος>) • Ή αλλιώς: • Μια μεταβλητή είναι λ-όρος. • Αν x μεταβλητή και t λ-όρος τότε το (λx.t) είναι λ-όρος. • Αν t και u είναι λ-όροι τότε (t u) είναι λ-όρος. • Οπότε το (λx.x)το ((λx.(yx))(λx.x))και το • (λf.(λx.(f(λy.((xx)y)))))(λx.(f((λy.((xx)y))))) • είναι όλα λ-όροι.

  3. λάμδα εκφράσεις>τί είναι;>στον λ-λογισμό Οι λ-όροι της 2ης μορφής ονομάζονται λάμδα συναρτήσεις, ή λάμδα εκφράσεις, ή συναρτησιακές αφαιρέσεις, ή ανώνυμες συναρτήσεις. Αλλά αυτή είναι η μορφή των λάμδα εκφράσεων στον λ-λογισμό.

  4. λάμδα εκφράσεις>τί είναι;>στις γλώσσες προγραμματισμού Στις γλώσσες προγραμματισμού οι λ-εκφράσεις είναι απλές συναρτήσεις με 2 κυρίως διαφορές: Δεν έχουν όνομα! Ο ορισμός τους μπορεί να εμφανίζεται μέσα σε μια έκφραση.

  5. βιβλιοθήκη>χρήση>includes & δηλώσεις Για να χρησιμοποιήσουμε την βιβλιοθήκη: Συμπεριλαμβάνουμε το κατάλληλο αρχείο επικεφαλίδας: #include"λnd++.h" Δηλώνουμε μια μεταβλητή τύπου “Arg”: Argx; (ο τύπος Argείναι ένας τύπος πολυμορφικής ταυτοτικής συνάρτησης Τ->Τ) Γράφουμε την λάμδα συνάρτηση που θέλουμε. π.χ.: x+1 ή κάτι πιο περίπλοκο όπως: 4*x*x+3*x+2.5 ή (2*x+2.2)*(cos(-x)+x*x*sin((-x)/(x)+5))/(3*cos(3.2*x+1)-1e-10)

  6. βιβλιοθήκη>χρήση>βασική χρήση Βεβαίως το να δηλώσουμε μια λάμδα συνάρτηση δεν είναι από μόνο του πολύ χρήσιμο. Πιθανότατα θέλουμε... να την εφαρμόσουμε κάπου, Να κάνουμε κάτι με την τιμή που θα επιστρέψει, Και όλα αυτά μέσα σε ένα πρόγραμμα. #include<iostream> usingstd::wcout; usingstd::endl; #include"λnd++.h" intmain() { Argx; wcout<<(4*x*x+3*x+2.5)(-2.5)<<endl; return0; }// end function main wcout<<(4*x*x+3*x+2.5)(-2.5)<<endl; 4*x*x+3*x+2.5 (4*x*x+3*x+2.5)(-2.5)

  7. βιβλιοθήκη>χρήση>απόδωση ονόματος Επίσης μπορεί να θέλουμε να της δώσουμε ένα όνομα ώστε να την χρησιμοποιήσουμε πολλές φορές: #include<iostream> usingstd::wcout; usingstd::endl; #include"λnd++.h" intmain() { Argx; autof=4*x*x+3*x+2.5; wcout<<f(-2.5)<<endl; wcout<<f(1)<<endl; return0; }// end function main

  8. βιβλιοθήκη>χρήση>απόδωση ονόματος>ο καθοριστής τύπου auto autoi=1;  inti=1; autox=2.2;  doublex=2.2; autoy=2.2f; floaty=2.2f; Αναγκαίο καθώς κάθε λάμδα έκφραση έχει έναν μοναδικό τύπο που κωδικοποιεί την εσωτερική δομή της έκφρασης

  9. βιβλιοθήκη>χρήση>αιχμαλωσία #include<iostream> usingstd::wcout; usingstd::wcin; usingstd::endl; #include"λnd++.h" constinta=4; constintb=3; intmain() { Argx; floatc; wcout<<"Type a number: "; wcin>>c; autof=a*x*x+b*x+c; wcout<<f(-2.5)<<endl; wcout<<f(1)<<endl; return0; }// end function main Και αν θέλουμε να χρησιμοποιήσουμε στο σώμα της λάμδα συνάρτησης κάποια μεταβλητή από μια περιβάλουσα εμβέλεια; Απλά την χρησιμοποιούμε! Οι τιμές των ‘αιχμαλοτισμένων’ μεταβλητών αντιγράφονται στο αντικείμενο που αναπαρτιστά την λ-έκφραση και μπορούν να χρησιμοποιηθούν από αυτό. Προς το παρόν δεν υποστιρίζεται ‘αιχμαλότιση’ κατ’ αναφορά.

  10. βιβλιοθήκη>χρήση>επιστροφή από συνάρτηση #include<iostream> usingstd::wcout; usingstd::endl; #include"λnd++.h" template<typenameT> autosub(Tx)->decltype(x-Arg()) { Argy; returnx-y; }// end function sub intmain() { wcout<<sub(2)(5)<<endl; wcout<<sub(2.2)(1)<<endl; wcout<<sub(2)(0.5)<<endl; return0; }// end function main Έτσι όμως μπορείς να επιστρέψεις με ασφάλεια μια λ-έκφραση από μια άλλη συνάρτηση. π.χ.:

  11. βιβλιοθήκη>χρήση>πολυμορφισμός Μέχρι τώρα έχουμε δεί ότι μπορούμε να εφαρμόσουμε μια λ-έκφραση σε αντικείμενα τύπου intκαι double. Οι λ-συναρτήσεις μας όμως χρησιμοποιούν παραμετρικό πολυμορφισμό και μπορούμε να τις εφαρμόσουμε σε οποιοδήποτε αντικείμενο έχει νόημα για το εκάστοτε σώμα τους. Τα λάθη ασφαλώς εντοπίζονται στον χρόνο μεταγλώττισης! π.χ.: complex<int>i(0,1); autof=3*x; unsignedlonglongull=f(2ull); floatfl=f(2.5f); complex<int>ic=f(2+3*i); Vector2D<>dv=f(Vector2D<>(-2.0,5)); αλλά: complex<float>fc=f(2+3*i);// illegal! διότι κάποιος αποφάσισε ότι το παρακάτω είναι illegal! complex<float>fc2=3*(2+3*i);// illegal!

  12. βιβλιοθήκη>χρήση>παραγώγιση Για να παραγωγίσουμε μια λ-έκφραση απλώς την δίνουμε σαν όρισμα στην συνάρτηση Differentiate. μπορεί να είναι ανώνυμη: Differentiate(cos(3*x+2)) ή να της έχουμε δώσει ένα όνομα: autof=cos(3*x+2); // .. Differentiate(f) Το αποτέλεσμα είναι μια λ-έκφραση της παραγώγου. την οποία μπορούμε να εφαρμόσουμε κάπου: Differentiate(cos(3*x+2))(0.01); Differentiate(f)(0.01); ή της δώσουμε ένα όνομα: autog=Differentiate(cos(3*x+2)); autoh=Differentiate(f);

  13. βιβλιοθήκη>χρήση>παραγώγιση>ονοκληρωμένο πρόγραμμα #include<iostream> usingstd::wcout; usingstd::endl; #include"λnd++.h" intmain() { Argx; autof=cos(3*x+2); wcout<<Differentiate(cos(3*x+2))(0.01)<<endl; wcout<<Differentiate(f)(0.01)<<endl; autog=Differentiate(cos(3*x+2)); autoh=Differentiate(f); wcout<<g(0.01)<<endl; wcout<<h(0.01)<<endl; return0; }// end function main

  14. βιβλιοθήκη>γιατί στατικά; Τί κερδίζουμε κάνοντας την παραγώγιση στατικά; Ταχύτατη εκτέλεση! Όχι μόνο το πρόγραμμα δεν επιβαρύνεται με την ανάγκη να εκτελέσει τους μετασχηματισμούς του δένρου έκφρασης στον χρόνο εκτέλεσης αλλά ο κώδικας της παραγώγου περνάει από τους εξαιρετικά ικανούς και επιθετικούς βελτιστοποιητές των σύγχρονων μεταγλωττιστών! Παραδείγματαπαραγόμενου κώδικα (g++ με βελτιστοποιήσεις ενεργές):

  15. βιβλιοθήκη>γιατί στατικά;>σταθερές εκφράσεις Σταθερές εκφράσεις: το wcout<<(cos(2*x+3))(3)<<endl; παράγει movsdxmm1, QWORDPTR .LC0[rip] #, learcx, _ZSt5wcout[rip] #, call _ZNSt13basic_ostreamIwSt11char_traitsIwEE9_M_insertIdEERS2_T_ # movrcx, rax #, D.28217 call _ZSt4endlIwSt11char_traitsIwEERSt13basic_ostreamIT_T0_ES6_ #

  16. βιβλιοθήκη>χρήση>includes>τιμές εισαγόμενες στον χρόνο εκτέλεσης Μεταβλητές: doublec; wcin>>c; leardx, 40[rsp] #, learcx, _ZSt4wcin[rip] #, call _ZNSt13basic_istreamIwSt11char_traitsIwEE10_M_extractIdEERS2_RT_ wcout<<(cos(2*x+3))(c)<<endl; movsdxmm0, QWORDPTR 40[rsp] # tmp68, c addsdxmm0, xmm0 # tmp68, tmp68 addsdxmm0, QWORDPTR .LC0[rip] # tmp68, callcos # learcx, _ZSt5wcout[rip] #, movapdxmm1, xmm0 # D.28230, call _ZNSt13basic_ostreamIwSt11char_traitsIwEE9_M_insertIdEERS2_T_# movrcx, rax #, D.28241 call _ZSt4endlIwSt11char_traitsIwEERSt13basic_ostreamIT_T0_ES6_ #

  17. βιβλιοθήκη>χρήση>includes>τιμές εισαγόμενες στον χρόνο εκτέλεσης Μεταβλητές: Και οι γραμμές που μας απασχολούν: movsdxmm0, QWORDPTR 40[rsp] # tmp68, c addsdxmm0, xmm0 # tmp68, tmp68 addsdxmm0, QWORDPTR .LC0[rip] # tmp68, callcos # είναι ταυτόσημες με αυτές που παράγονται από τον γραμμένο-με-το-χέρι κώδικα: inlinedoublef(doublex) { returncos(2*x+3); } // ... wcout<<f(c)<<endl;

  18. βιβλιοθήκη>εφαρμογές>γενικά Και πού χρησιμεύουν οι λ-εκφράσεις και η παραγώγισή τους; Γενικά οπουδήποτε γνωρίζουμε τον τύπο μιας συνάρτησης στον χρόνο μεταγλώττισης, χρειαζόμαστε την παράγωγό της και δεν θέλουμε να βγούμε από το περιβάλλον ανάπτυξής μας για να κάνουμε αλλού τον υπολογισμό! Αλλά ας δούμε 2 συγγεκριμένα παραδείγματα: Λακωνικές λάμδα εκφράσεις για τους αλγορίθμους της STL. Κλήση μιας Newton-Raphsonχώρίς να πιάσουμε μολύβι ή να ανοίξουμε το Mathematica! Συνδυασμένες γραφικές παραστάσεις συναρτήσεων και των παραγώγων τους ή καλύτερα σχεδίαση εφαπτομένων σε σημεία που επιλέγει ο χρήστης (δεν πρόλαβα να φτιάξω το παράδειγμα)

  19. βιβλιοθήκη>εφαρμογές>λακωνικές λάμδα εκφράσεις Λακωνικές λάμδα εκφράσεις για τους αλγορίθμους της STL. Όταν η έκφρασή σου είναι αρκετά μικρή, το συντακτικό ‘overhead’ των C++11 lambdas δεν είναι αποδεκτό: transform(begin(v1),end(v1),begin(v2),x-0.5); VS transform(begin(v1),end(v1),begin(v2),[](intx){returnx-0.5;});

  20. βιβλιοθήκη>εφαρμογές>newton-raphson>πρινβιβλιοθήκη>εφαρμογές>newton-raphson>πριν Παίρνουμε την παλιά καλή υλοποίηση της Newton-Raphsonαπό τηνεργασία του 3ου εξαμήνου... doubleNewton_Raphson(double(*f)(double),double(*df)(double), doublenew_x,doubleaccuracy,unsignedint*iterations) { doubleold_x; *iterations=0; do { (*iterations)++; old_x=new_x; new_x=old_x-(*f)(old_x)/(*df)(old_x); } while(fabs(new_x-old_x)>accuracy); returnnew_x; } No comments for the pointer parameter! These were the dark ages when we wrote in C!

  21. βιβλιοθήκη>εφαρμογές>newton-raphson>μετάβιβλιοθήκη>εφαρμογές>newton-raphson>μετά ...και την τροποποιούμε για να χρησιμοποιεί την λ&d++: template<typenameFunc> doubleNewton_Raphson(Funcf,doublenew_x,doubleaccuracy, unsignedint*iterations) { doubleold_x; *iterations=0; do { (*iterations)++; old_x=new_x; new_x=old_x-f(old_x)/Differentiate(f)(old_x); } while(fabs(new_x-old_x)>accuracy); returnnew_x; } Βεβαίως μπορούσαμε να κάνουμε και άλλες αλλαγές όπως να επιτρέπουμε στον καλούντα να επιλέγει την αριθμιτική που θα χρησιμοποιηθεί...

  22. βιβλιοθήκη>εφαρμογές>newton-raphson>κλήσηβιβλιοθήκη>εφαρμογές>newton-raphson>κλήση και τέλος υπολογίζουμε: intmain() { Argx; unsignedintiterations=0; wcout<<L"root = " <<Newton_Raphson((x-3)*(x+2),2,1e-6,&iterations) <<L" after "<<iterations<<L" iterations."<<endl; wcout<<L"root = " <<Newton_Raphson((x-3)*(x+2)*(x-2.2)*(x+5)*(x-7)*3.3, 10,1e-6,&iterations)<<L" after " <<iterations<<L" iterations."<<endl; return0; }// end function main Ποιός θέλει να παραγωγίσει την cos(sin(cos(x*sin(x)-x)+2))*(x+5)*(x-7)*3.3-2.5με το χέρι?!!

  23. βιβλιοθήκη>χρήση>includes Βεβαίως όπως σε όλες τις βιβλιοθήκες υπάρχουν περιορισμοί και περιθόριο για μελλοντική βελτίωση. Παραδείγματος χάρη πώς θα εκφράσεις μια λάμδα συνάρτηση που επιστρέφει πάντα την ίδια σταθερή τιμή;

  24. References/Further Reading:

  25. References/Further Reading:

  26. Ευχαριστώ! Καλά Χριστούγεννα!

More Related