Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

Η παρουσίαση φορτώνεται. Παρακαλείστε να περιμένετε

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

Παρόμοιες παρουσιάσεις


Παρουσίαση με θέμα: "Στατική Συμβολική Παραγώγιση Λάμδα Εκφράσεων στην C++ Η βιβλιοθήκη λ&d++."— Μεταγράφημα παρουσίασης:

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

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

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

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

5 βιβλιοθήκη>χρήση>includes & δηλώσεις Για να χρησιμοποιήσουμε την βιβλιοθήκη: 1.Συμπεριλαμβάνουμε το κατάλληλο αρχείο επικεφαλίδας: #include "λnd++.h" 2.Δηλώνουμε μια μεταβλητή τύπου “Arg”: Arg x; (ο τύπος Arg είναι ένας τύπος πολυμορφικής ταυτοτικής συνάρτησης Τ->Τ) 3.Γράφουμε την λάμδα συνάρτηση που θέλουμε. π.χ.: 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 using std::wcout; using std::endl; #include "λnd++.h" int main() { Arg x; wcout << (4*x*x+3*x+2.5)(-2.5) << endl; return 0; } // 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 using std::wcout; using std::endl; #include "λnd++.h" int main() { Arg x; auto f = 4*x*x+3*x+2.5; wcout << f(-2.5) << endl; wcout << f(1) << endl; return 0; } // end function main

8 auto i = 1;  int i = 1; auto x = 2.2;  double x = 2.2; auto y = 2.2f;  float y = 2.2f; Αναγκαίο καθώς κάθε λάμδα έκφραση έχει έναν μοναδικό τύπο που κωδικοποιεί την εσωτερική δομή της έκφρασης βιβλιοθήκη>χρήση>απόδωση ονόματος>ο καθοριστής τύπου auto

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

10 βιβλιοθήκη>χρήση>επιστροφή από συνάρτηση Έτσι όμως μπορείς να επιστρέψεις με ασφάλεια μια λ-έκφραση από μια άλλη συνάρτηση. π.χ.: #include using std::wcout; using std::endl; #include "λnd++.h" template auto sub(T x)->decltype(x-Arg()) { Arg y; return x-y; } // end function sub int main() { wcout << sub(2)(5) << endl; wcout << sub(2.2)(1) << endl; wcout << sub(2)(0.5) << endl; return 0; } // end function main

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

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

13 #include using std::wcout; using std::endl; #include "λnd++.h" int main() { Arg x; auto f = cos(3*x+2); wcout << Differentiate(cos(3*x+2))(0.01) << endl; wcout << Differentiate(f)(0.01) << endl; auto g = Differentiate(cos(3*x+2)); auto h = Differentiate(f); wcout << g(0.01) << endl; wcout << h(0.01) << endl; return 0; } // end function main βιβλιοθήκη>χρήση>παραγώγιση>ονοκληρωμένο πρόγραμμα

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

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

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

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

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

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

20 βιβλιοθήκη>εφαρμογές>newton-raphson>πριν Παίρνουμε την παλιά καλή υλοποίηση της Newton-Raphson από την εργασία του 3 ου εξαμήνου... double Newton_Raphson(double (*f)(double),double (*df)(double), double new_x,double accuracy,unsigned int *iterations) { double old_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); return new_x; } No comments for the pointer parameter! These were the dark ages when we wrote in C!

21 βιβλιοθήκη>εφαρμογές>newton-raphson>μετά...και την τροποποιούμε για να χρησιμοποιεί την λ&d++: template double Newton_Raphson(Func f,double new_x,double accuracy, unsigned int *iterations) { double old_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); return new_x; } Βεβαίως μπορούσαμε να κάνουμε και άλλες αλλαγές όπως να επιτρέπουμε στον καλούντα να επιλέγει την αριθμιτική που θα χρησιμοποιηθεί...

22 βιβλιοθήκη>εφαρμογές>newton-raphson>κλήση και τέλος υπολογίζουμε: int main() { Arg x; unsigned int iterations = 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; return 0; } // end function main Ποιός θέλει να παραγωγίσει την cos(sin(cos(x*sin(x)-x)+2))*(x+5)*(x-7)* με το χέρι?!!

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

24 References/Further Reading: specific embedded languages in C++ library reference ML for the Working Programmer by Lawrence C. Paulson §9.5 introduction to λ-calculus doc/index.htm Boost::uBLAS uses expression templates for efficient abstraction /index.html Boost::Spirit represents LL parsers as inline EBNF in C++ tml/index.html Boost::Phoenix has extensive support of polymorphic lambdas erlangen.de/~pflaum/pflaum/ProSeminar/exprtmpl.html original (?) Expression Templates article tml Boost::Lambda provides support for lambdas as well FC++ library supports functional programming in C++ C++ How to Program (5th Edition) by P.J. DeitelMy first C++ book. A bit outdated.

25 References/Further Reading: Ivor Horton's Beginning Visual C My 2 nd C++ book. Also covers C++/CLI ISO/IEC International StandardThe current C++ standard std.org/JTC1/SC22/WG21/docs/papers/2009/n2927.pdf Final proposal for C++0x Lambdas std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html Final proposal for static assertions std.org/jtc1/sc22/wg21/docs/papers/2006/n2087.pdf A Brief Introduction to Variadic Templates C++11 FAQ

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


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

Παρόμοιες παρουσιάσεις


Διαφημίσεις Google