ΠΑΝΕΠΙΣΤΗΜΙΟ ΜΑΚΕΔΟΝΙΑΣ ΠΡΟΓΡΑΜΜΑ ΜΕΤΑΠΤΥΧΙΑΚΩΝ ΣΠΟΥΔΩΝ ΤΜΗΜΑΤΟΣ ΕΦΑΡΜΟΣΜΕΝΗΣ ΠΛΗΡΟΦΟΡΙΚΗΣ ΥΛΟΠΟΙΗΣΗ ΠΡΟΛΥΤΙΚΩΝ ΔΙΑΔΙΚΑΣΙΩΝ ΚΑΙ ΑΛΓΟΡΙΘΜΩΝ ΤΥΠΟΥ SIMPLEX MΕ PYTHON Διπλωματική Εργασία του Τσιπλίδη Κωνσταντίνου Θεσσαλονίκη, 09/2016
ΥΛΟΠΟΙΗΣΗ ΠΡΟΛΥΤΙΚΩΝ ΔΙΑΔΙΚΑΣΙΩΝ ΚΑΙ ΑΛΓΟΡΙΘΜΩΝ ΤΥΠΟΥ SIMPLEX MΕ PYTHON Τσιπλίδης Κωνσταντίνος Πτυχίο Εφαρμοσμένης Πληροφορικής 1995 Διπλωματική Εργασία υποβαλλόμενη για τη μερική εκπλήρωση των απαιτήσεων του ΜΕΤΑΠΤΥΧΙΑΚΟΥ ΤΙΤΛΟΥ ΣΠΟΥΔΩΝ ΣΤΗΝ ΕΦΑΡΜΟΣΜΕΝΗ ΠΛΗΡΟΦΟΡΙΚΗ Επιβλέπων Καθηγητής Σαμαράς Νικόλαος Εγκρίθηκε από την τριμελή εξεταστική επιτροπή την Σαμαράς Νικόλαος Σιφαλέρας Άγγελος Βεργίδης Κωνσταντίνος Αναπληρωτής Καθηγητής Επίκουρος Καθηγητής Επίκουρος Καθηγητής......... Τσιπλίδης Κωνσταντίνος... iii
Περίληψη Η εργασία αφορά την μελέτη και ανάλυση μεθόδων και τεχνικών που εφαρμόζονται πριν από την επίλυση μεγάλης κλίμακας πραγματικών αραιών προβλημάτων Γραμμικού Προγραμματισμού. Τα αποτελέσματα της υπολογιστικής μελέτης καταδεικνύουν την ανάγκη και την χρησιμότητα των μεθοδολογιών που περιγράφονται, καθώς είναι αναγκαίες για την αποδοτική λειτουργία γνωστών αλγορίθμων αλλά και την βελτίωση που επιφέρουν τόσο στον χρόνο επίλυσης όσο και στους υπολογιστικούς πόρους που απαιτούνται. Γίνεται παρουσίαση του μαθηματικού μοντέλου κάθε μεθόδου, εφαρμογή σε κατάλληλα παραδείγματα ενώ ακολουθεί και ο αντίστοιχος κώδικας προγράμματος. Η υλοποίηση των μεθόδων αποτελεί πρωτότυπη εφαρμογή τους και προγραμματισμός τους στην γλώσσα python. Λέξεις Κλειδιά: Προλυτικές Διαδικασίες, Μέθοδοι Κλιμάκωσης, Αραιές Μήτρες Αλγόριθμος Simplex, Python iv
Abstract The primary concept of this work is to apply modern presolve and scaling techniques prior to solving large scale sparse real life Linear Programming problems, in order to achieve better computational behavior and results, while applying algorithms like the Simplex Method. The mathematical forms are presented along with numerical examples and codes. The methods are implemented in the python programming language. Keywords: Presolve Methods, Scaling Techniques, Simplex Algorithm, Sparse Matrices Technology, Python v
Ευχαριστίες Η παρούσα εργασία δεν θα μπορούσε να ολοκληρωθεί χωρίς την βοήθεια, την καθοδήγηση και την στήριξη του επιβλέποντος καθηγητή κου Σαμαρά Νικόλαου τον οποίο και ευχαριστώ πολύ για την συνεργασία μας. Οφείλω, επίσης, ένα ευχαριστώ στους παλαιούς και νέους Πανεπιστημιακούς Δασκάλους μου που, στα πλαίσια των μαθημάτων του Μεταπτυχιακού Προγράμματος, προσέφεραν επιπλέον νέες γνώσεις, πολύτιμο υλικό για την επιστημονική μου κατάρτιση και την προσωπική επαγγελματική εξέλιξη. Ολοκληρώνοντας τις υποχρεώσεις του Μεταπτυχιακού Προγράμματος με αυτήν την εργασία, ένα θερμό ευχαριστώ ανήκει στην οικογένειά μου για την αμέριστη υποστήριξη και διαρκή συμπαράστασή τους, όχι μόνο κατά την συγγραφή της εργασίας αλλά και καθ όλη τη διάρκεια των μεταπτυχιακών σπουδών μου. vi
Περιεχόμενα 1 Εισαγωγή 1 1.1 Η φύση του προβλήματος 1 1.2 Σκοπός της Διπλωματικής 2 1.3 Θέματα Υλοποίησης 2 2 Σχήματα Αποθήκευσης 6 2.1 Ιστορικά στοιχεία 6 2.2 Το πρότυπο MPS 7 2.2.1 Η δομή των αρχείων 7 2.2.2 Βιβλιοθήκες Αποθετήρια 8 2.2.3 Ανάγνωση αρχείων Κώδικας 8 2.3 Τεχνικές Αραιών Μητρών 12 2.3.1 Μορφές Αποθήκευσης 13 2.3.2 Η υλοποίηση τεχνικών Αραιών Μητρών 16 3 Προλυτικές διαδικασίες 20 3.1 Απαλοιφή μηδενικών γραμμών 20 3.2 Απαλοιφή μηδενικών στηλών 22 3.3 Απαλοιφή περιορισμών ισότητας τύπου singleton 24 3.4 Απαλοιφή ισοτικών περιορισμών τύπου k-ton 26 3.5 Απαλοιφή ανισοτικών περιορισμών τύπου singleton 30 3.6 Απαλοιφή δυϊκού ανισοτικού περιορισμού τύπου singleton 32 3.7 Απαλοιφή εμμέσως ελεύθερων στηλών τύπου singleton 34 3.8 Απαλοιφή πλεονασματικών στηλών 36 3.9 Απαλοιφή έμμεσων ορίων γραμμών 37 3.10 Απαλοιφή πλεονασματικών γραμμών 38 3.11 Κλήση των προλυτικών μεθόδων 39 4 Τεχνικές κλιμάκωσης 41 4.1 Μέθοδος της εξισορρόπησης 41 4.2 Μέθοδος του γεωμετρικού μέσου 44 4.3 Κλήση των διαδικασιών 47 5 Ο αναθεωρημένος αλγόριθμος simplex δύο φάσεων 48 6 Υπολογιστική μελέτη 61 vii
7 Συμπεράσματα 64 Βιβλιογραφία 65 Παράρτημα A - Εγκατάσταση της Python 67 A.1 Εισαγωγή 67 A.2 Επιλέγοντας περιβάλλον εργασίας 68 A.3 Εγκατάσταση 69 A.3.1 Ο διερμηνευτής 69 A.3.1.1 Windows (όλες οι εκδόσεις) 69 A.3.1.2 Linux (κάθε διανομή) 75 A.4 Επιλέγοντας IDE 75 A.5 Εγκατάσταση πακέτων 78 Παράρτημα B - Πληροφορίες MPS αρχείων 81 Παράρτημα C - Απεικόνιση αραιής μορφής αρχείων MPS 90 viii
Κατάλογος Εικόνων Εικόνα 1. Σχηματική παράσταση δεδομένων αραιών μητρών σε python... 12 ix
Κατάλογος Κώδικα Λίστα Κώδικα 1. Εισαγωγή στοιχείων από MPS σε αραιές μήτρες 11 Λίστα Κώδικα 2. Αποθήκευση στατιστικών στοιχείων δοκιμαστικών προβλημάτων 11 Λίστα Κώδικα 3. Διαγραμματική απεικόνιση δεδομένων αραιών μητρών 12 Λίστα Κώδικα 4. Απαλοιφή Μηδενικών γραμμών 22 Λίστα Κώδικα 5. Απαλοιφή Μηδενικών Στηλών 24 Λίστα Κώδικα 6. Απαλοιφή Περιορισμών Ισότητας τύπου Singleton 26 Λίστα Κώδικα 7. Απαλοιφή ισοτικών περιορισμών τύπου k-ton 30 Λίστα Κώδικα 8. Απαλοιφή ανισοτικών περιορισμών Singleton 32 Λίστα Κώδικα 9. Απαλοιφή δυϊκών περιορισμών 34 Λίστα Κώδικα 10. Απαλοιφή ελεύθερων στηλών 36 Λίστα Κώδικα 11. Απαλοιφή πλεονασματικών στηλών 37 Λίστα Κώδικα 12. Απαλοιφή έμμεσων ορίων γραμμών 38 Λίστα Κώδικα 13. Απαλοιφή πλεονασματικών γραμμών 39 Λίστα Κώδικα 14. Κλήση μεθόδων προεπίλυσης 40 Λίστα Κώδικα 15. Κλιμάκωση με την Μέθοδο Εξισορρόπησης 43 Λίστα Κώδικα 16. Μέθοδος της εξισορρόπησης (με βρόγχο) 44 Λίστα Κώδικα 17. Μέθοδος γεωμετρικού μέσου 47 Λίστα Κώδικα 18. Αλγόριθμος 2 Phase Revised Simplex 60 x
Πίνακας αποτελεσμάτων Πίνακας 1 Αποτελέσματα Εφαρμογής Μεθόδων Προεπίλυσης... 62 Πίνακας 2 Χρόνοι Εφαρμογής Μεθόδων Προεπίλυσης & Επαναλήψεις Αλγορίθμου... 63 xi
xii
1 Εισαγωγή 1.1 Η φύση του προβλήματος Η εργασία πραγματεύεται θέματα που ανήκουν στον χώρο του Γραμμικού Προγραμματισμού (Linear Programming). Παρόλο που η έρευνα έχει ξεκινήσει εδώ και αρκετές δεκαετίες (Dantzig (1949)), σημειώνοντας σημαντικές εξελίξεις με βελτιώσεις και ανακαλύψεις μόλις τα τελευταία χρόνια: (Khachiyan (1980)) - Ελλειψοειδής ή ρωσικός αλγόριθμος, (Karmarkar (1984)) - Αλγόριθμος Εσωτερικών Σημείων κα (Bland (1981)). Υπάρχουν θέματα που συνεχίζουν να κινούν το ενδιαφέρον των ερευνητών και να χρίζουν αποτελεσματικότερης αντιμετώπισης με συνεχείς προσπάθειες και την δημιουργία νέων μεθόδων όπως Περιστροφικοί Αλγόριθμοι Pivoting Algorithms (Simplex, Exterior Point, Criss-Cross) αλλά και Αλγόριθμοι Εσωτερικών Σημείων Interior Point Algorithms (Projective and Potential Reduction Methods, Affine Methods, Path-Following Methods). Η φύση του γενικού προβλήματος που επιλύει ο Γραμμικός Προγραμματισμός, που ονομάζεται γραμμικό πρόβλημα (ΓΠ), είναι τέτοια που καθιστά την αντιμετώπιση και την προσπάθεια επίλυσής του αρκετά δύσκολη που σε πολλές περιπτώσεις η εύρεση λύσης σε εφικτό χρόνο αποδεικνύεται αδύνατη. Η γενική μορφή τέτοιων προβλημάτων είναι η εξής: ( ) (Γ.Π.) Όπως αναλύεται σε επόμενο κεφάλαιο, τα πραγματικά προβλήματα (real world problems) που καλείται να επιλύσει ο ερευνητής, είναι εκτός από πολύ μεγάλα σε μέγεθος (αρκετές χιλιάδες εξισώσεις με αντίστοιχες μεταβλητές απόφασης), που οδηγούν σε αδυναμία αποθήκευσής τους ακόμα και σε σύγχρονα υπολογιστικά συστήματα με δεκάδες gigabyte μνήμης, είναι και η δομή τους τέτοια που συνήθως οδηγεί σε συσσώρευση λαθών υπολογισμών ή απλά σε αδυναμία εύρεσης λύσης (μεγάλο πλήθος κενών γραμμών ή στηλών στο βασικό σύστημα εξισώσεων, ύπαρξη πολλαπλών εξαρτήσεων με αποτέλεσμα την αδυναμία λειτουργίας των αλγορίθμων επίλυσής τους, πχ αντιστροφή μήτρας κλπ). 1
1.2 Σκοπός της Διπλωματικής Σκοπός της εργασίας είναι να αντιμετωπιστούν αυτά τα προβλήματα, με τρόπο αποδοτικό και αποτελεσματικό, καθιστώντας την επίλυση ενός οποιουδήποτε τυχαίου γενικού ΓΠ εφικτή σε πεπερασμένο χρονικό διάστημα, χρησιμοποιώντας εκείνες τις κατάλληλες τεχνικές και μεθόδους, εξαλείφοντας τις ιδιομορφίες και αφαιρώντας όλες τις προβληματικές δομές που προκαλούν όλες τις δυσλειτουργίες των μεθόδων επίλυσής τους. Στην πράξη, κατά την πραγματοποίηση της εργασίας, φάνηκαν οι δυσκολίες επίλυσης των ΓΠ που οδηγούσαν σε αδυναμία εύρεσης λύσης χωρίς την χρήση αυτών των τεχνικών. Ο λόγος είναι ότι εφαρμόζοντας αυτές τις τεχνικές, εκτός από την απλοποίηση του προβλήματος, επιτυγχάνεται και μείωση του μεγέθους του, με σημαντικά οφέλη στον χρόνο εκτέλεσης του αλγορίθμου αλλά και στην μείωση των αναγκαίων αποθηκευτικών πόρων του Η/Υ. Εκτός από τα πιο πάνω οφέλη, η αφαίρεση πλεονασματικών δομών, η διαγραφή περιττών περιορισμών και η απαλοιφή μεταβλητών απόφασης μη σχετικών με το πρόβλημα, προκαλεί την μείωση των απαιτούμενων υπολογισμών αλλά και των αντίστοιχων σφαλμάτων στρογγυλοποίησης και αποκοπής, οδηγώντας σε λύσεις μεγαλύτερης ακρίβειας. 1.3 Θέματα Υλοποίησης Στον χώρο των επιστημονικών υπολογισμών οι πιο συνηθισμένες γλώσσες προγραμματισμού ή αυτές που χρησιμοποιήθηκαν περισσότερο τις τελευταίες δεκαετίες είναι η C/C++ και η FORTRAN, σε διάφορες εκδόσεις της (77, 90, HPF κλπ). Βασικό συγκριτικό πλεονέκτημά τους οι ταχύτατοι και βελτιστοποιημένοι (optimized) μεταγλωττιστές και η παρουσία λίγων, αλλά πολύ καλά υλοποιημένων βιβλιοθηκών (όπως το LAPACK) η χρήση των οποίων δεν υπήρξε πάντοτε και η ευκολότερη δυνατή. Με την ανάπτυξη του περιβάλλοντος προγραμματισμού MATLAB, και του αντίστοιχου, ανοιχτού κώδικα, octave, τα τελευταία χρόνια υπήρξε μια στροφή των ερευνητών σε αυτά τα περιβάλλοντα, κάνοντας χρήση των πλεονεκτημάτων τους στην αναπαράσταση των προβλημάτων και στην μεγάλη ποικιλία έτοιμων εργαλείων που βοηθούν στην επίλυσή τους. 2
Κατασκευάστηκαν σημαντικές βιβλιοθήκες κώδικα που αντιμετωπίζουν άμεσα θέματα όπως η αποθήκευση δεδομένων με την χρήση τεχνικών αραιών μητρών. Και αυτό, χωρίς την ανάγκη ο ερευνητής να ασχοληθεί κατασκευαστικά με αυτά αλλά μόνο με την σωστή και αποδοτική χρήση τους, συντελώντας στην αυξανόμενη μέχρι τώρα χρήση τους. Η αλληλεπιδραστική (interactive) μορφή τους καθώς και η ενσωμάτωση διαφόρων βοηθητικών εργαλείων (χειρισμού, επεξεργασίας, οπτικής απόδοσης δεδομένων κλπ) ήταν μερικά από τα πλεονεκτήματα που προσέφεραν. Ωστόσο, το κυριότερο πρόβλημα τους, αν εξαιρέσει κανείς την εκμάθηση μιας διαφορετικής γλώσσας, και ότι συνεπάγεται αυτό, συντακτικό, κανόνες κλπ, και η εξοικείωση με το περιβάλλον του, είναι η εξάρτηση που απορρέει από μια κλειστού τύπου πλατφόρμα ανάπτυξης κώδικα, από τις διαθέσιμες κάθε φορά αναβαθμίσεις ή ανανεώσεις του. Από την άλλη μεριά, εδώ και αρκετά χρόνια, μια άλλη γλώσσα προγραμματισμού βρίσκεται στο επίκεντρο του ενδιαφέροντος και υιοθετείται η χρήση της σε ολοένα και περισσότερους τομείς των επιστημών και της έρευνας. Η γλώσσα python (Downey (2008) και Summerfield (2009)). Μια διερμηνευόμενη (interpreted) γλώσσα, σε αλληλεπιδραστικό περιβάλλον, με πολλά, διαφορετικά και στοχευμένα σε διάφορες χρήσεις περιβάλλοντα ανάπτυξης κώδικα, χρησιμοποιείται σε όλο και περισσότερους τομείς της έρευνας. Σχετικές έρευνες μάλιστα, δείχνουν ότι τα τελευταία χρόνια πολλά από τα κορυφαία πανεπιστήμια της Αμερικής (27 στα 39, πηγή: JavaMagazine.com 1 ) έχουν καθιερώσει ως κύρια γλώσσα προγραμματισμού στα εισαγωγικά μαθήματα της Επιστήμης των Υπολογιστών την γλώσσα python, ρίχνοντας την Java στην 2 η θέση (, το MATLAB στην 3 η και την C στην 4 η ). Πολλές από τις μεγαλύτερες εταιρείες στο χώρο της πληροφορικής (όπως Google, dropbox, Netflix, spotify κά) χρησιμοποιούν πλέον και την python σε συνδυασμό και με άλλες γλώσσες. Χαρακτηριστική είναι και η φράση που αποδίδεται σε μηχανικούς της Google αναφορικά με το ποιες γλώσσες χρησιμοποιεί η εταιρεία: Python where we can, C++ where we must Μερικοί από τους λόγους που κάνουν την python αρκετά ελκυστική στην χρήση της για την ανάπτυξη κώδικα είναι: 1 http://bit.ly/2cvo5zo 3
Είναι εύκολη στην εκμάθηση και στην χρήση της, αλλά και στην ανάγνωση του παραγόμενου κώδικα Είναι κατάλληλη για rapid prototyping, που σημαίνει ότι ο ερευνητής μπορεί άμεσα να μετατρέψει την ιδέα ενός αλγόριθμου σε κώδικα, φτιάχνοντας έτσι εύκολα τον σκελετό του προγράμματος Είναι «εκ φύσεως» αντικειμενοστραφής Διαθέτει μια μεγάλη ποικιλία βιβλιοθηκών σχεδόν για κάθε εργασία, όπως τα numpy, scipy, matplotlib και linalg στους επιστημονικούς υπολογισμούς, που συντηρούνται και ενημερώνονται συχνά (Bressert (2013), Idris (2014), Langtangen (2009), Langtangen (2014), Rojas (2015), Blanco-Silva (2013), Stewart (2014)) Δημιουργία συμπαγούς, σύντομου και εύκολα αναγνώσιμου κώδικα Είναι δωρεάν και διαθέσιμη για κάθε λειτουργικό σύστημα, οποιασδήποτε αρχιτεκτονικής Συνδέεται εύκολα με κώδικα γραμμένο σε άλλες γλώσσες προγραμματισμού Έχει άμεση και αλληλεπιδραστική λειτουργία, που σημαίνει ότι αφού φορτωθούν τα δεδομένα στην κονσόλα, μπορούν να τρέξουν άμεσα μεμονωμένες εντολές ή κομμάτια αυτών, ώστε να γίνουν οι πιθανές αλλαγές ή τροποποιήσεις στον κώδικα Αναφορικά δε με την χρήση της python σε τομείς των επιστημονικών υπολογισμών, σε αντιδιαστολή με τις «παραδοσιακές» C/C++ και FORTRAN, αξίζει να αναφέρουμε την ανάπτυξη και ανανέωση γρήγορων βιβλιοθηκών (συχνά precompiled σε C) κώδικα από την μεγάλη κοινότητα των φίλων της γλώσσας και σε πάρα πολλούς τομείς (από web cloud εφαρμογές μέχρι υλοποιήσεις σε GPUs). Για τους πιο πάνω λόγους, επιλέχθηκε η γλώσσα python για την υλοποίηση των τεχνικών και του αλγορίθμου που περιγράφονται στην παρούσα εργασία. Το γεγονός ότι παρόμοιες υλοποιήσεις σε python, για επίλυση μεγάλης κλίμακας γραμμικών προβλημάτων, δεν υπάρχουν, αποτέλεσε το μεγάλο κίνητρο και πρόκληση αυτής της εργασίας, αλλά ταυτόχρονα, δημιούργησε και πάρα πολλές δυσκολίες. Αυτές είχαν να κάνουν περισσότερο με την σύνδεση διαφορετικών βιβλιοθηκών και το συνδυασμό αυτών, ώστε να προκύψει το επιθυμητό τελικό αποτέλεσμα της έρευνας. Ο κώδικας που δημιουργήθηκε στα πλαίσια της εργασίας αυτής αφορά: 4
1. Την εισαγωγή δεδομένων από αρχεία (MPS) και την αποθήκευσή τους στην μνήμη με τεχνικές αραιών μητρών (sparse matrix techniques), όπως περιγράφονται στο Κεφάλαιο 2. Εκεί παρουσιάζονται και οι γραφικές απεικονίσεις κάποιων προβλημάτων, με εκτενή παρουσίασή τους στα Παραρτήματα 2. Την υλοποίηση των προλυτικών διαδικασιών που παρουσιάζονται στο Κεφάλαιο 3 3. Την εφαρμογή μεθόδων κλιμάκωσης που αναλύονται στο Κεφάλαιο 4 4. Την ανάπτυξη και χρήση του αλγορίθμου Simplex που περιγράφεται στο Κεφάλαιο 5, με την μορφή μητρών, σε μια ή/και δύο Φάσεις, με την μέθοδο μίας τεχνητής μεταβλητής 5. Η γραφική αναπαράσταση των αραιών μητρών των επιλεγμένων Μετροπρογραμμάτων (Benchmarks) παρουσιάζεται, μαζί με κάποια βασικά στατιστικά τους στοιχεία, στα Παραρτήματα 5
2 Σχήματα Αποθήκευσης 2.1 Ιστορικά στοιχεία Το γραμμικό πρόβλημα, όπως παρουσιάστηκε στο προηγούμενο κεφάλαιο, συναντάται σε πάρα πολλούς τομείς της ανθρώπινης δραστηριότητας. Χρησιμοποιούνται κυρίως στον χώρο των μεταφορών, της διανομής προϊόντων, την βιομηχανία, αλλά και την οικονομία γενικά ή το marketing ειδικότερα. Για την επίλυση τέτοιων πραγματικών προβλημάτων (real world), έχουν υλοποιηθεί εμπορικοί ή καθαρά ερευνητικοί λύτες (solvers). Η φύση αυτών των προβλημάτων κάνουν το μέγεθός τους αρκετά μεγάλο, ώστε να προταθούν, από την πρώτη στιγμή που εμφανίστηκαν, διάφοροι τρόποι αποθήκευσής τους. Η λογική στην οποία στηρίχθηκαν, έχει να κάνει με τον προσανατολισμό του κάθε προγράμματος λύτη και διακρίνονται σε δύο κατηγορίες. Από την μια είναι τα συστήματα που επιτρέπουν την πλέον αποδοτική αποθήκευση των τεράστιων ποσοτήτων πληροφορίας και από την άλλη είναι η πιο «φυσική» και πιο κατανοητή στον άνθρωπο εισαγωγή δεδομένων. Η τελευταία προσανατολίζεται στην αποτύπωση της δομής του προβλήματος, ώστε να αναπαραστήσει σωστά τα βασικά δομικά του στοιχεία. Η πρώτη μορφή χρησιμοποιείται από την δεκαετία του 1960 μέχρι και σήμερα, ενώ η δεύτερη εμφανίστηκε τα τελευταία χρόνια, με την ανάπτυξη εργαλείων που ενσωματώνουν κάποια γλώσσα μοντελοποίησης. Στην εργασία χρησιμοποιήθηκε ένα από τα σχήματα αποθήκευσης που χρησιμοποιούν μοντέρνοι, επαγγελματικοί λύτες και είναι το πρώτο που εμφανίστηκε στον χώρο. Το σχήμα αποθήκευσης Mathematical Programming System (MPS) δημιουργήθηκε από την IBM για το σύστημα IBM MPS/360. Παρόλο που στηρίχθηκε στην τεχνολογία εκείνης της εποχής (διάτρητες κάρτες) αποτελεί ακόμα και σήμερα το κυριότερο ερευνητικό πρότυπο. Οι λόγοι είναι ότι χρησιμοποιείται από τις μεγαλύτερες βιβλιοθήκες αποθετήρια, όπως αυτή του Netlib (www.netlib.org), αποτελεί το κύριο μέσο διαμοιρασμού δεδομένων σε ακαδημαϊκό και ερευνητικό επίπεδο και είναι κοινά αποδεκτό και αναγνώσιμο από όλους τους γνωστούς λύτες. 6
2.2 Το πρότυπο MPS Τα MPS αρχεία είναι αρχεία τύπου ASCII, με αυστηρά καθορισμένη δομή (η οποία περιγράφεται αμέσως μετά) για την αποθήκευση μόνο των μη μηδενικών στοιχείων του προβλήματος. 2.2.1 Η δομή των αρχείων Κάθε αρχείο MPS αποτελείται από επιμέρους τμήματα για την αποθήκευση όλων των διαθέσιμων πληροφοριών, όπως μεταβλητές (ονομασία και τιμή), συντελεστές κόστους, δεξιά μέρη ανισοτήτων, τύποι περιορισμών, όρια, διαστήματα τιμών κλπ. Κάθε γραμμή αποτελεί είτε αναγνωριστικό τμήματος είτε εγγραφή με πληροφορίες. Πιο αναλυτικά: Α) τμήμα NAME: έτσι ξεκινάει κάθε αρχείο MPS και περιέχει το όνομα του αρχείου μοντέλου. Στήλες : 1 12: NAME 15 22: το όνομα του μοντέλου 25 36: binary, free ή κενό Β) τμήμα ROWS (στήλες 1 4): περιλαμβάνει τις ονομασίες των γραμμών περιορισμών του προβλήματος καθώς και τον τύπο τους. Η λέξη ROWS σηματοδοτεί την έναρξη του τμήματος. Οι αμέσως επόμενες γραμμές μέχρι την έναρξη επόμενου τμήματος βρίσκονται στις Στήλες : 2 3 : ο τύπος του περιορισμού (Ν:γραμμή κόστους,g:,l:,e:=) 5 12: το όνομα του περιορισμού Γ) τμήμα COLUMNS (στήλες 1 7): πληροφορίες για κάθε στήλη. Το λεκτικό COLUMNS ξεκινάει το τμήμα και ακολουθούν τα περιεχόμενά του σε κάθε γραμμή Στήλες : 5 12 : όνομα στήλης 15 22: όνομα γραμμής 25 36: η τιμή του στοιχείου της μήτρας σε αυτή τη γραμμή και στήλη. Τα επόμενα στοιχεία δεν εμφανίζονται πάντα 40 47: το όνομα μιας 2 ης γραμμής 50 61: η τιμή του στοιχείου της μήτρας Δ) τμήμα RHS (στήλες 1 3): περιλαμβάνει πληροφορίες για δεξιό μέρος των περιορισμών Στήλες : 5 12 : όνομα δεξιού μέρους 7
15 22: όνομα γραμμής - περιορισμού 25 36: η αριθμητική τιμή του δεξιού μέρους του περιορισμού 40 47: το όνομα μιας 2 ης γραμμής 50 61: η αριθμητική τιμή του δεξιού μέρους του 2 ου περιορισμού Ε) τμήμα ENDATA (στήλες 1 7): καθορίζει το τέλος του αρχείου Ορισμένα από τα προβλήματα περιλαμβάνουν και τμήματα που αφορούν όρια (limits - bounds) ή διαστήματα (ranges). Αυτές οι τελευταίες περιπτώσεις αγνοήθηκαν. 2.2.2 Βιβλιοθήκες Αποθετήρια Τα προβλήματα δοκιμών (benchmarks) προέρχονται από διάφορες συλλογές που διατίθενται ελεύθερα στο διαδίκτυο. Αφορούν μόνο προβλήματα του χώρου του Γραμμικού Προγραμματισμού. Μια λεπτομερής παρουσίαση των χαρακτηριστικών αυτών των προβλημάτων γίνεται στα Παραρτήματα. Οι συλλογές αυτές είναι: 1. Netlib: πρόκειται για την κύρια συλλογή προβλημάτων ΓΠ και την παλαιότερη (http://www.netlib.org). Η προσθήκη νέων προβλημάτων έχει σταματήσει, αποτελεί ωστόσο την πιο βασική από τις διαθέσιμες πηγές και σταθερό σημείο αναφοράς των ερευνητών στον χώρο. 2. Συλλογή Kennigton 3. infeasible problems 4. Συλλογή Mittelmann 5. προβληματικά: σετ ΓΠ από την Ακαδημία Επιστημών της Ουγγαρίας (http://www.sztaki.hu/~meszaros/public_ftp/lptestset/), 6. στοχαστικά: σετ ΓΠ από την Ακαδημία Επιστημών της Ουγγαρίας 7. διάφορα: από την Ακαδημία επιστημών της Ουγγαρίας 8. διάφορα: μοντέλα από τον Housam Binous 2.2.3 Ανάγνωση αρχείων Κώδικας Ο κώδικας που δημιουργήθηκε για την χρήση των αρχείων MPS, είναι γραμμένος σε python και πραγματοποιεί το άνοιγμα και φόρτωμα των δεδομένων ενός προβλήματος σε ένα πέρασμα (one pass), σε αντίθεση με άλλες υλοποιήσεις που το κάνουν σε δύο ή σε πολλαπλές αναγνώσεις, καθιστώντας τον αρκετά ταχύ στην λειτουργία του. Για το 8
φόρτωμα των δεδομένων και το πέρασμά τους στην συνέχεια στον λύτη χρησιμοποιήθηκαν βιβλιοθήκες από το πακέτο scipy και συναρτήσεις χειρισμού αραιών μητρών, όπως περιγράφονται στην επόμενη ενότητα. Ακολουθεί ο κώδικας που βρίσκεται στο αρχείο με όνομα fileread.py 1 # -*- coding: utf-8 -*- 2 """ 3 Created on Sat Aug 1 00:30:43 2015 4 1. Read MPS file to Sparse Matrices 5 2. Plot a scatter diagram for Non Zero Elements 6 3. Print basic info about the file 7 4. Σε μορφή csr 8 @author: Tsiplidis Konstantinos 9 """ 10 11 12 def readfile(): 13 ''' 14 Περιγραφή: Γινεται ανάγνωση αρχείου MPS 15 @author: Tsiplidis Konstantinos 16 Συγγραφέας: Τσιπλίδης Κωνσταντίνος 17 Αρχείο: fileread.py 18 Κλήση: a,b,c,eq=readfile() 19 Χρήση - Ενσωμάτωση: from fileread import * 20 Βιβλιοθήκες: numpy, scipy 21 Είσοδος:-a: η μήτρα των συντελεστών του γραμμικού προβλήματος 22 csr scipy matrix μεγέθους mxn 23 -b: το διάνυσμα του δεξιού μέρους csr scipy matrix μεγέθους mx1 24 -c: το διάνυσμα της αντικειμ. συνάρτησης csr scipy matrix μεγέθους nx1 25 -eq: πίνακας με το είδος κάθε περιορισμού 26 Έξοδος: οι τιμές των πινάκων εισόδου (a, b, c) 27 ''' 28 import os 29 print("reading files in directory...") 30 path='/00_mps' 31 mpsfiles=[files for files in os.listdir(path) if files.endswith('.mps')] 32 #Για κάθε αρχείο MPS 33 for mps in mpsfiles: 34 fname=path + '/' + mps 35 #'Ανοιγμα και διάβασμα του αρχείου 36 print('reading from file:',fname ) 37 #Αρχικοποίηση λιστών βασικής επεξεργασίας 38 rows,eqtype,data,rhs,l1=[],[],[],[],[1,2,0,3,4] 39 section=-1 #Διαχείριση των διαφορετικών τμημάτων των αρχείων 40 for line in open(fname): 41 #ανάγνωση κάθε γραμμής του αρχείου 42 words = line.split()#ανάγνωση μιας γραμμής και διαχωρισμός του string 43 nwords = len( words ) #Πόσα καμμάτια έχει κάθε γραμμή 44 if len(words)>2: 45 words=words[0:3] 46 words[0],words[1],words[2]=line[4:12].strip(),line[14:22].strip(),line[24:36] 47 if len(line)>39:# αν μια γραμμή εχει 5 στοιχεία 48 words.append(line[39:47].strip()) 49 words.append(line[49:61]) 50 if words[0] in ["NAME","ROWS","COLUMNS","RHS",'ENDATA'] and len(line)<=23:#εντοπισμός τίτλων 51 section+=1 52 continue 53 elif words[0] in ["RANGES","BOUNDS"]:#Απόρριψη αρχείου με τέτοια στο 54 print(words[0], "found, ending now...") 55 break 9
56 elif words[0] not in ["NAME","ROWS","COLUMNS","RHS"] and section<1: 57 continue 58 if section==0 and len(words)>0: 59 fname=words[1]#το όνομα του αρχείου 60 elif section==1:#τμήμα γραμμών 61 rows.append(line[4:len(line)-1].strip())#ονομασία γραμμής 62 eqtype.append(line[1])#είδος περιορισμού 63 elif section==2:#τμήμα στηλών 64 data.append(words[0])#αριθμητικά δεδομένα 65 end=2 66 t1=0 67 if len(words)>3: end=5#εντοπισμός περισσότερων από μιας τιμής 68 data.append(words[l1[0]]) 69 try: data.append(float(words[l1[1]])) 70 except: data.append(words[l1[1]]) 71 for i in range(2,end): 72 if i <end-1: 73 data.append(words[l1[i]]) 74 else: 75 try: data.append(float(words[l1[i]])) 76 except: data.append(words[l1[i]]) 77 elif section==3:#αριθμητικά δεδομένα για το Δεξιό Μέρος 78 if len(words)==2: 79 words.append(words[1]) 80 words[1]=words[0] 81 for i in range(1,len(words),2):#nwords): 82 rhs.append(words[i]) 83 try: rhs.append(float(words[i+1])) 84 except: rhs.append(words[i+1]) 85 #Κύρια επεξεργασία των δεδομένων των αρχείων 86 if section<4: 87 continue 88 else: 89 i=1 90 cost=[] 91 z_name=rows[eqtype.index('n')]#το όνομα της γραμμής κόστους 92 data2=data[:] 93 fordel=[] 94 #Αφαίρεση των δεδομένων της γραμμής κόστους από το Α 95 for i in range(1,len(data2),3): 96 if z_name == data2[i]: 97 fordel.append(i) 98 cost.append(data2[i-1]) 99 cost.append(data2[i+1]) 100 del data[int((i-1)-(len(cost)/2-1)*3):int((i)-(len(cost)/2-1)*3)+2] 101 data3=data2[:] 102 rows2=list(rows) 103 rows.remove(z_name) 104 for i in reversed(fordel): 105 del data2[i-1:i+2] 106 cols,x,y,d=[],[],[],[] 107 [cols.append(i) for i in data[0:len(data):3] if i not in cols] 108 for i in range(0,len(data2),3): 109 x.append(cols.index(data2[i])) 110 y.append(rows.index(data2[i+1])) 111 d.append(data2[i+2]) 112 #Αποθήκευση των δεδομένων σε sparse μορφή (CSR) 113 import numpy as np 114 from scipy.sparse import csr_matrix 115 col1 = np.array(x)#δείκτες στήλης 116 row1 = np.array(y)#δείκτες γραμμής 117 dat1 = np.array(d)#δεδομένα 118 c,c_cols=list(np.zeros(len(cols))),list(range(0,len(cols))) 119 for i in range(0,len(cost),2): 120 cool=cols.index(cost[i]) 121 c[cool]=cost[i+1] 122 c_rows=np.zeros(len(c)) 10
123 a=csr_matrix((dat1, (row1, col1)), shape=(len(rows), len(cols))) 124 c=csr_matrix((c, (c_cols,c_rows))) 125 126 b,b_rows=list(np.zeros(len(rows))),list(range(0,len(rows))) 127 for i in range(0,len(rhs),2): 128 cool=rows.index(rhs[i]) 129 b[cool]=rhs[i+1] 130 b_cols=np.zeros(len(rows)) 131 b=csr_matrix((b, (b_rows, b_cols))) 132 k=-1 133 for i in ['L','E','G']: 134 eqtype=[k if x==i else x for x in eqtype] 135 k+=1 136 eqtype.remove('n') 137 eqtype=np.array(eqtype) 138 eqtype=eqtype.reshape((len(eqtype),1)) 139 return a,b,c,eqtype Λίστα Κώδικα 1. Εισαγωγή στοιχείων από MPS σε αραιές μήτρες Για την εύρεση και αποθήκευση κάποιων βασικών στατιστικών στοιχείων των αρχείων MPS δημιουργήθηκε ο παρακάτω κώδικας: 1 # -*- coding: utf-8 -*- 2 #Δημιουργία εικόνας - γραφήματος της αραιής μορφής των αρχείων 3 4 def print_file_stat(rows,cols,data,fname): 5 #Μερικά στατιστικά στοιχεία του αρχείου 6 import sys 7 with open("filestats_for_xl.txt", "a") as f: 8 f.write(fname+';') 9 f.write(str(len(rows)-1)+';') 10 f.write(str(len(cols))+';') 11 f.write(str(int(len(data)/3))+';') 12 f.write(str(((len(data)/3))/(len(cols)*len(cols))*100)+"%"+';') 13 f.write(str(sys.getsizeof(data))+';') 14 f.write(str(int(sys.getsizeof(data[::3])/(len(data)/3)* len(rows)*len(cols)))+';') 15 f.write(str(sys.getsizeof(data[::3]))+'\n') Λίστα Κώδικα 2. Αποθήκευση στατιστικών στοιχείων δοκιμαστικών προβλημάτων Τέλος, για την δημιουργία και αποθήκευση της διαγραμματικής παράστασης κάθε προβλήματος και της απεικόνισης της αραιής μορφής των δεδομένων τους έγινε ο επόμενος κώδικας: 1 # -*- coding: utf-8 -*- 2 #Δημιουργία εικόνας - γραφήματος της αραιής μορφής των αρχείων 3 def plot_sparsity(x,y,data,fname): 4 import pylab as pl 5 pl.xlim(min(x), max(x)) 6 pl.ylim(min(y), max(y))# "%.2f" % a 11
7 sp="%.3f" %(((len(data)/3))/(len(cols)*len(cols))*100) 8 pl.title(fname+"-nonzeros:"+str(len(x))+"-sparsity:"+sp+"%"+"\n Tsiplidis Konstantinos & Samaras Nikolaos") 9 pl.xlabel(str(len(set(x)))+' Columns')#μετράει πόσα μοναδικά στοιχεία έχει η λίστα 10 pl.ylabel(str(len(set(y)))+' Rows') 11 pl.plot(x, y, 'b*', markersize=1) 12 pl.show() 13 pl.savefig("scatter_"+fname+"_pylab.png") 14 #ή με το επόμενο, 2ο τρόπο 15 import matplotlib.pyplot as plt 16 fig, ax = plt.subplots(1) 17 fig.axes(0,max(x),0,max(y) 18 ax.scatter(x, y, label="nz",s=1, marker=',', color='b') 19 ax.legend() 20 ax.set_title('scatter Diagramm of '+ fname +"- NonZeros:"+str(len(data)/3)+"\n Tsiplidis Konstantinos") 21 22 fig.savefig("scatter_"+fname+".png") Λίστα Κώδικα 3. Διαγραμματική απεικόνιση δεδομένων αραιών μητρών Το αποτέλεσμα του πιο πάνω κώδικα είναι διαγράμματα της μορφής: Εικόνα 1. Σχηματική παράσταση δεδομένων αραιών μητρών σε python 2.3 Τεχνικές Αραιών Μητρών Όλα τα πραγματικά προβλήματα που υπάρχουν στις συλλογές δοκιμαστικών προβλημάτων (benchmarks) είναι αραιά (sparse). Αυτό πρακτικά σημαίνει ότι ένα μεγάλο ποσοστό, μέχρι και της τάξης του 98%, των αριθμητικών δεδομένων του προβλήματος είναι μηδενικά, οι τεχνικές αραιών μητρών (Sparse Matrix Techniques) επιτρέπουν τα εξής: 1. Δεν αποθηκεύουν τα μηδενικά στοιχεία του προβλήματος, αποφεύγοντας έτσι την αλόγιστη χρήση αποθηκευτικού χώρου και 12
2. Αποφεύγουν την άσκοπη εκτέλεση πράξεων με μηδενικά στοιχεία, κάνοντας τους υπολογισμούς πιο ταχείς από την μια, αυξάνοντας την ακρίβεια των υπολογισμών και χωρίς να συσσωρεύονται σφάλματα υπολογισμών από την άλλη Πέρα από τα πλεονεκτήματα που προσφέρουν αυτές οι τεχνικές, υπάρχουν και μια σειρά άλλων ζητημάτων που ο ερευνητής θα πρέπει να λάβει υπ όψιν του, όπως: 1. Ποια μέθοδος είναι η πλέον κατάλληλη για μια συγκεκριμένη εργασία, πχ μια μέθοδος αποθηκεύει τα στοιχεία μιας μήτρας κατά στήλες ενώ άλλη κατά γραμμή 2. Υπάρχει έτοιμος κώδικας χειρισμού του σχήματος που θα χρησιμοποιηθεί ή θα πρέπει να κατασκευαστεί από την αρχή; 3. Αν υπάρχει, πόσο εύκολα μπορεί να γίνει η χρήση του 4. Τέλος, υπάρχουν ενσωματωμένες (built in) ρουτίνες για τις βασικές πράξεις μητρών (γινόμενα μητρών διανυσμάτων και αριθμών, γραμμοπράξεις κλπ) Οι απαντήσεις σε αυτά τα ερωτήματα θα καθορίσουν και το τελικό εργαλείο γλώσσα υλοποίησης των αλγορίθμων. Σε επόμενη παράγραφο (2.3.3) αναλύεται η χρήση της βιβλιοθήκης sparse του πακέτου scipy της python. 2.3.1 Μορφές Αποθήκευσης Για την αποθήκευση αριθμητικών δεδομένων αραιών μητρών υπάρχουν αρκετές τεχνικές. Ένας από τους πιο σημαντικούς παράγοντες για την επιλογή της πιο κατάλληλης μεθόδου έχει να κάνει και με τον τρόπο εσωτερικής αποθήκευσης των δεδομένων από την ίδια την γλώσσα προγραμματισμού με την οποία θα γίνει η υλοποίηση, αν δηλαδή αποθηκεύονται τα στοιχεία των πινάκων κατά γραμμή ή κατά στήλη. Οι πιο συχνά χρησιμοποιούμενες (Davis (2006), Gondzio (1995), Pissanetzky (1984), Saad (2003), Swietanowski (1995)) είναι οι εξής: Α) συμπιεσμένης αραιής γραμμής Compressed Sparse Row (CSR) Για την αποθήκευση των δεδομένων χρησιμοποιούνται τρία διανύσματα: Data: για τα αριθμητικά δεδομένα Indices: για τον δείκτη στήλης που ανήκει κάθε μη μηδενικό στοιχείο Indptr: το στοιχείο στην κ θέση δείχνει από ποια θέση στους άλλους δύο πίνακες ξεκινούν τα μη μηδενικά στοιχεία της κ γραμμής και εκτείνονται μέχρι μια θέση πριν 13
από αυτή στην οπoία δείχνει το κ+1 στοιχείο. Με άλλα λόγια δηλαδή, το στοιχείο μιας οποιασδήποτε γραμμής k βρίσκονται στο data[indptr[ k ]] μέχρι το data[indptr[ k +1]], αφού στην python δεν συμπεριλαμβάνεται το τελευταίο στοιχείο των διαστημάτων. Για τον πιο κάτω πίνακα Α 1 0 0 0 0 0 0 2 A 0 1 0 0 0 0 0 0 3 0 0 1 Τα αντίστοιχα διανύσματα αναπαράστασής του σε αραιή μορφή είναι: Data=[1,2,1,3,1] Indices=[0,3,1,0,3] Indptr=[0,1,2,3,3,5] Η μέθοδος χρησιμοποιείται όταν γίνεται συχνά η σάρωη του πίνακα κατά γραμμή. Β) συμπιεσμένης αραιής στήλης Compressed Sparse Column(CSC) Παρόμοια μέθοδος με την προηγούμενη, ωστόσο αλλάζει ο προσανατολισμός και αποθηκεύονται τα μη μηδενικά στοιχεία κατά στήλες. Είναι απαραίτητα τρία διανύσματα: Data: για τα αριθμητικά δεδομένα Indices: για τον δείκτη γραμμής που ανήκει κάθε μη μηδενικό στοιχείο Indptr: ακολουθείται η ίδια λογική αλλά ως προς τις στήλες Για παράδειγμα, για το ίδιο με πιο πάνω Α, ισχύει: Data=[1,3,1,2,1] Indices=[0,4,2,1,4] Indptr=[0,2,3,3,5] Γ) συνδεδεμένες λίστες Linked Lists Αυτή η μέθοδος ενδείκνυται για την συχνή σάρωση της μήτρας κατά στήλη και όχι όταν γίνονται συχνά υπολογισμοί. Αυτή η μορφή αποθηκεύει μια λίστα ανά γραμμή της μήτρας, όπου κάθε κόμβος της λίστας περιέχει εκτός από τους απαραίτητους δείκτες επόμενου ή/και προηγούμενου κόμβου και τον δείκτη στήλης και την μη μηδενική τιμή. Η ταξινομημένη διάταξη σύμφωνα με τις στήλες, των στοιχείων της λίστας οδηγεί σε 14
περαιτέρω βελτίωση της απόδοσης για κάθε διαδικασία αναζήτησης και αναφοράς των στοιχείων της. Οι τρείς παραπάνω μέθοδοι είναι και οι πιο διαδεδομένες ειδικά όταν γίνονται πολλαπλές σαρώσεις ή και πράξεις. Υπάρχουν ωστόσο και μερικές ακόμη, πιο απλές αναπαραστάσεις των δεδομένων και χρησιμοποιούνται συνήθως στις περιπτώσεις όπου δεν είναι απαραίτητοι οι συχνοί υπολογισμοί ή όταν απαιτείται βαθμιδωτή ή κλιμακούμενη προσθήκη στοιχείων σε αυτά. Η πιο συνηθισμένη χρήση τους γίνεται στην φάση της δημιουργίας της αραιής δομής και η οποία μετασχηματίζεται στο τέλος σε άλλη, πιο αποδοτική, για τον χειρισμό ή την επεξεργασία της (πχ σε CSR ή CSC). Δ) συντεταγμένες Coordinates Με την μέθοδο αυτή αποθηκεύονται τα στοιχεία σε τριάδες σε έναν πίνακα διάνυσμα μεγέθους 3xnnz θέσεων για μια μήτρα με nnz μη μηδενικά στοιχεία. Για τα στοιχεία του Α του παραδείγματος, κατασκευάζεται το επόμενο διάνυσμα Data=[1,0,0,3,1,1,3,1,2,1,3,4,0] Όπου το κ στοιχείο είναι το μη μηδενικό στοιχείο του Α που βρίσκεται στην κ+1 γραμμή και την κ+2 στήλη. Πρόκειται για μια υπερ απλουστευμένη μέθοδο και την λιγότερο αποδοτική, γιατί δεν είναι άμεσα ορατά τα δομικά στοιχεία της μήτρας (γραμμές, στήλες, διαγώνιοι κλπ). Ε) λεξικό δεικτών/κλειδιών Dictionary of Keys (DOK) Σε αυτή τη μέθοδο τα δεδομένα αποθηκεύονται σε ένα λεξικό (που είναι βασικό δομικό στοιχείο της python μαζί με τις λίστες και τα σύνολα), το οποίο χαρτογραφεί ζεύγη τιμών γραμμής στήλης με την τιμή του μη μηδενικού στοιχείου. Εκτός από τις παραπάνω πιο συνιθισμένες μορφές αποθήκευσης υπάρχουν και κάποιες ακόμη που προορίζονται για πιο εξειδικευμένες μορφές δεδομένων και αντίστοιχους χειρισμούς. Αυτές είναι: Στ) σε τμήματα Blocks Είναι παρόμοια με την CSR με την διαφορά ότι χρησιμοποιείται όταν υπάρχουν υπομήτρες σε πυκνή (dense) μορφή. Σε αυτές τις περιπτώσεις η χρήση αυτής της μεθόδου είναι πολύ πιο αποδοτική σε σχέση με άλλες (Κούρτης ΒΒ). 15
Ζ) Banded Εφαρμόζεται γενικά σε μήτρες όπου τα μη μηδενικά στοιχεία συγκεντρώνονται κοντά ή γύρω από την κύρια διαγώνιό τους και σε μια ή περισσότερες σειρές δεδομένων. Η) διαγώνια Diagonal Η χρήση της γίνεται σχεδόν αποκλειστικά σε διαγώνιες μήτρες, δηλαδή σε μήτρες που τα μη μηδενικά στοιχεία τους βρίσκονται ακριβώς στην διαγώνιό τους, ενώ τα υπόλοιπα είναι μηδέν. Έτσι, για έναν πίνακα nxn χρειάζεται μόνο ένας μονοδιάστατος πίνακας nnzx2 πλήθος στοιχείων για κάθε ζεύγος τιμών (γραμμής ή στήλης και τιμής). Θ) Skyline H χρήση της περιορίζεται σε τριγωνικούς (υπό) πίνακες όπου θα εφαρμοστούν κυρίως μέθοδοι Cholesky ή LU. Συναντάται στο πακέτο BLAS. Ι) συμμετρική Symmetric Συνηθισμένη μορφή που δημιουργείται από ένα μη προσανατολισμένο γράφο, για την αναπαράσταση του αντίστοιχου πίνακα γειτνίασης (adjacency matrix). Αντίστοιχες τεχνικές που υλοποιούνται και στο πακέτο sparse BLAS του Intel Math Kernel Library είναι και οι: μη συμμετρική, δομικά συμμετρική (το μοτίβο εμφάνισης μη μηδενικών στοιχείων είναι συμμετρικό) και κατανεμημένα συμμετρική: η συμμετρική μήτρα διασπάται σε σειριακά υποσύνολα γραμμών, τους λεγόμενους τομείς domains και αντιμετωπίζονται παράλληλα. Κάθε ένας από αυτούς τους τομείς μπορεί να ανήκει σε ένα πολυδιεργασιακό σύστημα ή MPI διεργασία ή νήμα 2. 2.3.2 Η υλοποίηση τεχνικών Αραιών Μητρών Μια από τις πιο πλήρεις βιβλιοθήκες της python για επιστημονικούς υπολογισμούς, είναι το scipy (Scientific Python). Ένα από τα πακέτα του αφορά σχήματα αποθήκευσης και χειρισμό αραιών μητρών, το πακέτο sparse. Αυτό, περιλαμβάνει κλάσεις και μεθόδους (στην λογική της αντικειμενοστραφούς φύσης της python) για τον ορισμό, δημιουργία, μετατροπή διαφόρων τεχνικών (που αναφέρθηκαν στην ενότητα 2.3.1) αλλά και για την επεξεργασία τους ή τον χειρισμό τους, όπως ο 2 Βλ. http://software.intel.com : Intel Developer Reference for Mathematical Kernel Library 16
πολλαπλασιασμός μητρών με διανύσματα και αριθμούς κλπ. Τέλος, το πακέτο scipy.sparse μπορεί να χρησιμοποιηθεί σε συνδυασμό με αυτό του numpy (Numerical Python). Οι μορφές αποθήκευσης που υποστηρίζονται είναι οι εξής 3 : BSD: Διάταξη και επεξεργασία σε ενότητες (blocks) DOK: Λεξικογραφική μέθοδος COO: Μέθοδος των συντεταγμένων LIL: Συνδεδεμένες Λίστες CSR: Μέθοδος συμπίεσης κατά γραμμή CSC: Μέθοδος συμπίεσης κατά στήλη DIA: Διαγώνια μορφή Η χρήση του πακέτου γίνεται εύκολα και μετά την εγκατάστασή του, που περιγράφεται στο Παράρτημα Α, με την ακόλουθη εντολή from scipy import sparse εισάγεται στον κώδικα η συλλογή sparse, οπότε και είναι έτοιμη να χρησιμοποιηθεί. Με τις επόμενες εντολές γίνεται η δημιουργία πίνακα αραιής μορφής >>> import numpy as np >>> from scipy.sparse import csr_matrix >>> csr_matrix((3, 4), dtype=np.int8).toarray() array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], dtype=int8) με μια από τις μεθόδους που υποστηρίζονται. Όπου csr_matrix είναι η μέθοδος δημιουργίας CSR τύπου μήτρας και το πρόθεμα.toarray() μετατρέπει τον αραιό πίνακα (on the fly) σε πυκνό για να εμφανιστεί η δομή και τα περιεχόμενά του στην κονσόλα (οθόνη). Δυναμικά επίσης μπορεί να γίνει και η μετατροπή μιας δομής σε μια άλλη. Το επόμενο παράδειγμα δείχνει έναν από τους τρόπους δημιουργίας αραιού πίνακα τύπου COO και την ταυτόχρονη μετατροπή του σε άλλη μορφή (CSR): >>> from numpy import array >>> from scipy.sparse import coo_matrix >>> row = array([0,0,1,3,1,0,0]) >>> col = array([0,2,1,3,1,0,0]) >>> data = array([1,1,1,1,1,1,1]) >>> A = coo_matrix( (data,(row,col)), shape=(4,4)).tocsr() >>> A.todense() matrix([[3, 0, 1, 0], [0, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1]]) 3 https://www.scipy.org 17
Τέτοιου είδους μετατροπές είναι απαραίτητες στον κώδικα αφού είναι γενικά προτιμότερο, αλλά και πιο γρήγορο, να γίνεται μετατροπή της δομής σε κάποια άλλη, όπως για παράδειγμα μιας δομής σε CSR όπου γίνονται πολλαπλές σαρώσεις κατά γραμμή. Ο χρόνος μετατροπής ή δημιουργία αντιγράφου της δομής CSR είναι πολύ πιο μικρός σε σύγκριση με πολλές σαρώσεις του πίνακα κατά στήλη ή με την μέθοδο του τεμαχισμού (python slicing 4, δουλεύοντας με κομμάτια του πίνακα, όπως στις λίστες της python). Εκτός όμως από την δημιουργία, ανανέωση και αλλαγή αυτών των δομών, υπάρχουν και μέθοδοι για τον χειρισμό τους. Η επόμενη γραμμή πραγματοποιεί πολλαπλασιασμό πινάκων: r = sparse.csr_matrix.dot(a, B) ή πιο απλά: r = Α.dot(Β) όπου το Α είναι αραιός πίνακας ενώ το Β πυκνός (τύπου numpy array). To επόμενο παράδειγμα δημιουργεί δύο αραιούς CSR πίνακες (C και C2) και εμφανίζει το γινόμενό τους (C*C2, πηγή: ipython spyder): In [4]: import numpy as np In [9]: from scipy import sparse In [25]: C = sparse.csr_matrix(np.array([[1,0], [2,2]])) In [26]: C2 = sparse.csr_matrix(np.array([[1,3,2], [6,1,4]])) In [27]: C Out[27]: <2x2 sparse matrix of type '<class 'numpy.int32'>' with 3 stored elements in Compressed Sparse Row format> In [28]: C.A #.Α: μετατροπή σε dense Out[28]: array([[1, 0], [2, 2]], dtype=int32) In [29]: C2.A Out[29]: array([[1, 3, 2], [6, 1, 4]], dtype=int32) In [30]: (C*C2).A Out[30]: array([[ 1, 3, 2], [14, 8, 12]], dtype=int32) Με την κατασκευή μιας αραιής μήτρας, δημιουργείται ένας πίνακας του τύπου matrix. Στον κώδικα της εργασίας χρησιμοποιούνται πίνακες αραιοί ως matrix και πίνακες πυκνοί ως arrays που είναι και η τυπική δομή δεδομένων στο πακέτο numpy.ξεπερνώντας τις αρχικές δυσκολίες από την συνεχή εναλλαγή από τον έναν τύπο στον άλλο, ο χειρισμός και των δύο γίνεται εύκολα. Πέρα από τις ευκολίες και τα εργαλεία που παρέχει το πακέτο sparse, υπάρχουν και κάποιοι περιορισμοί στην χρήση του. Ένας από αυτούς έχει να κάνει με την 4 https://docs.python.org/2.3/whatsnew/section-slices.html 18
αδυναμία χρήσης λογικών μασκών με την μέθοδο np.where (boolean masking), κάτι που διαθέτουν οι πίνακες τύπου array του numpy και όχι το πακέτο sparse (τουλάχιστον στην έκδοση που χρησιμοποιήθηκε). Ωστόσο, οι απλές λογικές μάσκες (χωρίς where) είναι παντού διαθέσιμες: In [50]: Y Out[50]: array([[0, 2], [3, 4]]) In [51]: Y>0 Out[51]: array([[false, True], [ True, True]], dtype=bool) In [52]: C2.A Out[52]: array([[0, 3, 2], [6, 1, 4]], dtype=int32) In [53]: (C2>0).A Out[53]: array([[false, True, True], [ True, True, True]], dtype=bool) In [55]: (C2>0).A & (C2<5).A C:\Anaconda3\lib\site-packages\scipy\sparse\compressed.py:282: SparseEfficiencyWarning: Comparing a sparse matrix with a scalar greater than zero using < is inefficient, try using >= instead. warn(bad_scalar_msg, SparseEfficiencyWarning) Out[55]: array([[false, True, True], [False, True, True]], dtype=bool) 19
3 Προλυτικές διαδικασίες Το βασικότερο πρόβλημα που συναντάται κατά την προσπάθεια επίλυσης των δοκιμαστικών προβλημάτων είναι, πέρα από το μεγάλο μέγεθός τους, η σύνθετη δομή τους και τα πολλά περιττά, πλεονάζοντα ή επαναλαμβανόμενα στοιχεία τους. Τα περισσότερα από τα προβλήματα δοκιμών είναι αδύνατον να λυθούν χωρίς προηγουμένως να επαλειφθούν κάποιες ανωμαλίες και προβλήματα που αυτά περιέχουν. Στις επόμενες παραγράφους περιγράφονται οι πιο συχνά χρησιμοποιούμενες μέθοδοι για την προεπίλυση των προβλημάτων, πριν δηλαδή τα αρχικά προβλήματα δοθούν στον αλγόριθμο επίλυσής τους (Erling - Andersen (1995), Erling (1995), Tomlin (1983), Tomlin (1986)). Αναφορικά με την υλοποίηση των μεθόδων σε python, χρησιμοποιούνται οι εξής όροι: Α: πίνακας των συντελεστών των περιορισμών μεγέθους mxn, τύπου CSR matrix b: διάνυσμα για το δεξιό μέρος των περιορισμών, μεγέθους m, τύπου CSR matrix c: διάνυσμα για τους συντελεστές κόστους, μεγέθους n, τύπου CSR matrix eqtype: πίνακας με το είδος των περιορισμών (-1:, 0:=, 1: ) inf: λογική μεταβλητή για την σήμανση αδύνατου προβλήματος 3.1 Απαλοιφή μηδενικών γραμμών Αναλύοντας την μήτρα των συντελεστών του ΓΠ, εμφανίζονται κενές γραμμές όταν όλοι οι συντελεστές μιας ή περισσότερων γραμμών είναι μηδέν. Έτσι, μια μηδενική γραμμή ορίζεται ως εξής: και μπορεί να διαγραφεί 20 b A x b i i i i όπου i 1,2,..., m και A 0 Μια τέτοια γραμμή στο ΓΠ μπορεί να υποδηλώνει πλεονάζοντα περιορισμό ή μη ύπαρξη λύσης. Διακρίνονται οι πιο κάτω περιπτώσεις: 1. A1x1 A 2x2... A x b και b 0 : ο περιορισμός είναι πλεονασματικός i i in n i και μπορεί να διαγραφεί 2. A1x1 A 2x2... A x b και b 0 : το πρόβλημα είναι αδύνατο i i in n i i i 3. A1x1 A 2x2... A x b και b 0 : ο περιορισμός είναι πλεονασματικός i i in n i i i
4. A1x1 A 2x2... A x b και b 0 : το πρόβλημα είναι αδύνατο i i in n i i 5. A1x1 A 2x2... A x b b b 0: ο περιορισμός είναι πλεονασματικός i i in n i i i και μπορεί να διαγραφεί 6. A1x1 A 2x2... A x b b b 0: το πρόβλημα είναι αδύνατο i i in n i i i Με το επόμενο παράδειγμα φαίνεται η εφαρμογή της μεθόδου. Έστω το παρακάτω ΓΠ: min z x x x 1 2 3 s. t. x x x 3 1 2 3 0x 0x 0x 5 1 2 3 2x x 2x 2 1 2 3 0x 0x 0x 3 1 2 3 x 0, i 1,.., n και, b, c i nxm m n Η μορφή των πινάκων είναι η εξής: 1 1 1 3 1 1 0 0 0 5 1 A, c 1, b, eqtype 2 1 2 2 1 1 0 0 0 3 1 Το πρόβλημα περιέχει δύο γραμμές, την 2 η και την 4 η, με όλα τα στοιχεία τους ίσα με μηδέν. Για την 2 η γραμμή ισχύει: 0x 0x 0x 5, και ισχύει η πιο πάνω περίπτωση (1), οπότε η 2 η γραμμή είναι 1 2 3 περιττή και μπορεί να απαλειφθεί, μαζί με τα αντίστοιχα στοιχεία των υπολοίπων πινάκων. Το νέο πρόβλημα που προκύπτει έχει την πιο κάτω μορφή: 1 1 1 1 3 1 A 2 1 2, c 1, b 2, eqtype 1 0 0 0 1 3 1 Στην υλοποίησή της η μέθοδος δεν χρειάζεται να κάνει αμέσως την διαγραφή αυτής της γραμμής του Α, ώστε να αποφευχθεί η χρονοβόρα αναδιανομή της μνήμης (memory reallocation). Αντί αυτού, προτιμάται το μαρκάρισμα (πχ σε μια λίστα της python) της συγκεκριμένης γραμμής για να γίνει η διαγραφή όλων στο τέλος της διαδικασίας. Για την 3 η γραμμή (αρχικά 4 η ) ισχύει: 21
0x 0x 0x 3, οπότε ισχύει η περίπτωση (4), δηλαδή το πρόβλημα είναι 1 2 3 αδύνατο. Ακολουθεί ο κώδικας της μεθόδου: 1 def delzerorows(a,b,eq,infy): 2 '''Αλλάζει τον πίνακα, σβήνοντας μηδενικές γραμμές 3 γραμμές με όλα τα Αij=0 4 5 Χρόνος Εκτέλεσης: 100 loops, best of 3: 125 µs per loop 6 ''' 7 print(' CASE 1 ') 8 mask = np.concatenate(([true], a.indptr[1:]!= a.indptr[:-1])) 9 infy=findinfinity(a,b,eq) 10 if not infy: 11 a=updatevectors(a, mask) 12 b=updatevectors(b, mask) 13 eq=eq[mask[1:]] 14 15 print('found and Eliminated',len(mask)-1-len(eq),'Rows') 16 return a,b,eq,infy 17 18 def findinfinity(a,b,eq):#οκ 19 '''Επιστρέφει T/F αν το πρόβλημα είναι αδύνατο 20 Χρόνος Εκτέλεσης: 100 loops, best of 3: 868 µs per loop 21 ''' 22 return np.any((((b.a.t*eq[:,0])>0) ((eq[:,0]==0) & (b.a!=0)) ) & (a.indptr[1:] == a.indptr[:-1])) 23 24 25 def updatevectors(b, mask): 26 '''Ενημερώνεται ο πίνακας ή το διάνυσμα b σε sparse μορφή 27 σύμφωνα με την λογική μάσκα 28 ''' 29 return csr_matrix(b)[mask[1:],:] Λίστα Κώδικα 4. Απαλοιφή Μηδενικών γραμμών 3.2 Απαλοιφή μηδενικών στηλών Με αυτή τη μέθοδο μπορεί να γίνει άμεση ανίχνευση απεριόριστων λύσεων ή πλεονασματικών μεταβλητών. Μια στήλη είναι μηδενική όταν όλοι οι συντελεστές σε αυτή τη στήλη είναι μηδέν, δηλαδή A j =0, όπου j 1, 2,..., n. Διακρίνονται οι πιο κάτω περιπτώσεις: 1. c j 0, όπου j 1,2,..., n : η μεταβλητή x j είναι περιττή και μπορεί να διαγραφεί 22
2. c <0, όπου j 1,2,..., n : το ΓΠ πρόβλημα είναι απεριόριστο, οπότε j σταματάει η διαδικασία Έστω το παρακάτω ΓΠ πρόβλημα: Η μορφή των πινάκων είναι η εξής: min z 2x x x x 1 2 3 4 s. t. 0x x 2x 5 1 2 3 0x 2x x 2 1 2 3 0x x x 1 1 2 3 x 0, i 1,.., n και, b, c i nxm m n 2 0 1 2 0 5 1 1 A 0 2 1 0, c, b 2, eqtype 1 1 0 1 1 0 1 1 1 Δύο στήλες είναι μηδενικές (η 1 η και η 4 η ). για την 1 η στήλη ισχύει η περίπτωση (1), c1 2 0, οπότε, η μεταβλητή x1 μπορεί να αφαιρεθεί από το πρόβλημα και κατά συνέπεια να αφαιρεθεί η 1 η T στήλη του A, ( A 1) και το αντίστοιχο στοιχείο της z (c 1 ). Προκύπτει έτσι το επόμενο, νέο ΓΠ: 1 2 0 1 5 1 A 2 1 0, c 1, b 2, eqtype 1 1 1 0 1 1 1 Για την 3 η στήλη (4 η στο αρχικό πρόβλημα) ισχύει η περίπτωση (2), A 3 0 και c3 1 0 που σημαίνει ότι το αρχικό πρόβλημα είναι απεριόριστο. Ακολουθεί ο κώδικας της μεθόδου: 1 def delzerocols(a,c,unbound): 2 '''Αλλάζει τον πίνακα, σβήνοντας μηδενικές στήλες 3 100 loops, best of 3: 125 µs per loop 4 ''' 5 print(' CASE 2 ') 6 m,n=np.shape(a) 7 a=a.tocsc() #μετατροπή σε csc 8 mask = np.concatenate(([true], a.indptr[1:]!= a.indptr[:-1])) 9 mask1 = np.concatenate(([true], a.indptr[1:] == a.indptr[:-1])) 10 mask2=c.a<0 11 unbound=np.any(mask2.t & mask1[1:]) 12 if not unbound: 13 a=csc_matrix((a.data, a.indices, a.indptr[mask])) 14 c=csr_matrix((c.data, c.indices, c.indptr[mask])) 15 A=a.tocsr() 16 m,n=np.shape(a) 17 else: 23
18 print("unbound found...stopping") 19 print('found and Eliminated',len(mask1)-1-n,'Columns') 20 return A,c,unbound Λίστα Κώδικα 5. Απαλοιφή Μηδενικών Στηλών 3.3 Απαλοιφή περιορισμών ισότητας τύπου singleton Όταν στην μήτρα των συντελεστών ενός προβλήματος εμφανίζονται γραμμές περιορισμοί ισότητας με ένα μόνο συντελεστή μη μηδενικό, αυτές οι γραμμές ονομάζονται singleton. Μια τέτοια γραμμή έχει την γενική μορφή: A x A x A x b i1 1 i2 2... in n i όπου i 1,2,..., m και A 0 A 0 με j k ή A x b ή x b / A ik k i k i ik ik Διακρίνονται δύο περιπτώσεις, ανάλογα με την τιμή του x k : ij 1. xk 0: η γραμμή i και η στήλη k είναι πλεονάζουσες και μπορούν να διαγραφούν από το πρόβλημα 2. xk 0: το πρόβλημα είναι αδύνατο Στην 1 η περίπτωση και προτού διαγραφεί η μεταβλητή x k, η τιμή της αντικαθίσταται σε όλους τους υπόλοιπους περιορισμούς στους οποίους εμφανίζεται. Έτσι, ανανεώνεται το b ως εξής: b b xka k Η συνάρτηση κόστους ανανεώνεται στην περίπτωση που ck 0. Σε αυτήν την περίπτωση ο σταθερός όρος c0 ανανεώνεται ή δημιουργείται αν δεν υπάρχει ως εξής: c0 c0 ck ( bi / Aik ) Μετά την ενημέρωση των πιο πάνω στοιχείων, διαγράφεται η γραμμή i του A, καθώς και τα i στοιχεία των b και eqtype, όπως και η k στήλη του A μαζί με το k στοιχείο του διανύσματος c. Η διαδικασία αυτή επαναλαμβάνεται μέχρι να μην εμφανίζονται πια άλλοι ισοτικοί singleton περιορισμοί, αφού μπορεί να εμφανιστούν εκ νέου κατά την διάρκεια εφαρμογής της μεθόδου. Έστω το παρακάτω ΓΠ πρόβλημα: 24
min z x x x 2x 1 2 3 4 s. t. x x 2x 4x 5 x 1 2 3 4 1 25 3 1 2 3 2x 4 2 2x x x 2 x 0, i 1,.., n και, b, c i Η μορφή των πινάκων είναι η εξής: nxm m n 1 1 2 4 1 5 1 0 0 2 0 1 4 0 A, c, b, eqtype 1 0 0 0 1 2 0 2 1 1 0 2 2 1 Σε δύο γραμμές εμφανίζονται singleton ισοτικοί περιορισμοί, στις γραμμές 2 και 3. Για τον 2 ο περιορισμό ισχύει: 0x1 0x 4 2 2x3 0x4 4 ή x3 2 2 Επειδή ισχύει x x3 0, η γραμμή 2 και η στήλη 3 είναι περιττές και μπορούν να k επαλειφθούν, αφού πρώτα γίνει η ενημέρωση του προβλήματος με την τιμή του x 3 : 5 2 1 4 2 0 b b x3a 3 2 2 0 2 2 1 4 και c0 0 1(4 / 2) 0 2 2 επειδή c3 0. Μετά από αυτές τις αλλαγές μπορεί να γίνει η ενημέρωση των πινάκων. Διαγράφονται η γραμμή 1 και η στήλη 3 του A, όπως και το 1 ο στοιχείο του b, το 3 ο στοιχείο του c και το 1 ο στοιχείο του eqtype. Η νέα μορφή του προβλήματος είναι η παρακάτω: 1 1 4 1 4 1 A 1 0 0, c 1, b 2, eqtype 0 2 1 0 2 2 1 Η ίδια διαδικασία επαναλαμβάνεται μέχρι να μην υπάρχει άλλος singleton ισοτικός περιορισμός στην μήτρα των συντελεστών του προβλήματος. Σε αυτήν την μορφή του το πρόβλημα έχει τον 2 ο περιορισμό του ισοτικού singleton, οπότε θα πρέπει να συνεχιστεί η διαδικασία που χρησιμοποιήθηκε και για την 2 η γραμμή αρχικά.
1 def elimsingeq(a,b,c,c0,eq,infy): 2 print(' CASE 3 ') 3 k=0 4 m,n=np.shape(a) 5 m0=m 6 lindr=list(range(0,m)) 7 lindc=list(range(0,n)) 8 mask=(a.indptr[1:] - a.indptr[:-1]) 9 eq2=eq.transpose() 10 rowss=np.where((mask==1) & (eq2[0]==0)) 11 s=0 12 while len(rowss[0])>=1: 13 s+=1 14 i=rowss[0][0] 15 j=a.indices[a.indptr[i]] 16 xk=(b.a[i]/a.a[i,j])[0] 17 if xk<0: 18 infy=true 19 break 20 else: 21 b=b-xk*a[:,j] 22 if c[j]!=0: 23 c0-=c.a[j]*(b.a[i]/a.a[i,j]) 24 lindr.remove(i) 25 lindc.remove(j) 26 k+=1 27 a=csr_matrix(a)[lindr,:] 28 a=csr_matrix(a)[:,lindc] 29 b=csr_matrix(b)[lindr] 30 c=csr_matrix(c)[lindc] 31 eq=eq[lindr] 32 eq2=eq.transpose() 33 m,n=np.shape(a) 34 lindr=list(range(0,m)) 35 lindc=list(range(0,n)) 36 mask=(a.indptr[1:] - a.indptr[:-1]) 37 rowss=np.where((mask==1) & (eq2[0]==0)) 38 print('found and Eliminated',k,'redudant rows') 39 print('found and Eliminated',k,'redudant columns') 40 return a,b,c,c0,eq,infy Λίστα Κώδικα 6. Απαλοιφή Περιορισμών Ισότητας τύπου Singleton 3.4 Απαλοιφή ισοτικών περιορισμών τύπου k-ton Οι τύπου k-ton περιορισμοί είναι οι ισοτικοί περιορισμοί στους οποίους υπάρχουν μόνο k μη μηδενικοί συντελεστές του προβλήματος, όπως φαίνεται από τον επόμενο τύπο: A x A x A x b i1 1 i2 2... in n i όπου i 1,2,..., m και A 0 A 0 και έστω k το πλήθος των μη μηδενικών στοιχείων που αναζητούνται στους περιορισμούς. Αν k=1 τότε η διαδικασία μετατρέπεται σ αυτήν της περίπτωσης 3.3 με τύπου singleton, διαφορετικά, για κάθε i γραμμή ισότητα με k μη μηδενικά στοιχεία ik ij 26
εντοπίζεται η j στήλη όπου εμφανίζεται το k τελευταίο μη μηδενικό στοιχείο. Η ανανέωση της μήτρας A και του διανύσματος b γίνεται ως εξής: εξής: A A / A και i i ij b b / A i i ij Ακόμη, αν c j 0 τότε ενημερώνονται και τα στοιχεία της γραμμής κόστους ως c c c A 0 0 j T i c c c b j i Προτού γίνει η διαγραφή στοιχείων που αφορούν την x j μεταβλητή, γίνεται ενημέρωση των περιορισμών (εκτός του i ) όπου x j 0. Συμβολίζοντας με t το διάνυσμα με τους δείκτες γραμμών όπου x j 0, εκτός της i γραμμής και με την προϋπόθεση ότι bi 0, η ενημέρωση γίνεται ως εξής: b b A b t t tj t A A A A t t tj i Μετά την ενημέρωση αυτή είναι δυνατή η διαγραφή της x j μεταβλητής από τα A και c. H διαδικασία ακολουθείται με την συνεχή μείωση του k. Αν k 1 τότε η μέθοδος μπορεί να οδηγήσει είτε σε εντοπισμό πλεονάζοντος περιορισμού, είτε σε αδυναμία επίλυσης του προβλήματος. Σε αυτό το σημείο η διαδικασία μοιάζει με αυτήν του εντοπισμού singleton ισοτικών περιορισμών, όπου διακρίνονται οι εξής περιπτώσεις: κόστους: 1. xk 0: το ΓΠ είναι αδύνατο 2. xk 0: γίνεται διαγραφή της γραμμής i και της στήλης k ως πλεονάζουσες. Το x k ωστόσο, αντικαθίσταται σε κάθε περιορισμό: b b xka k Επίσης, αν c j 0, τότε γίνεται ανανέωση του σταθερού όρου της γραμμής c c c b A 0 0 j i / ik 27
eqtype 1. i Ο τύπος του i περιορισμού αλλάζει και μετατρέπεται σε τύπου, οπότε τίθεται Όπως ειπώθηκε στην πιο πάνω περίπτωση (2) διαγράφονται από το πρόβλημα η γραμμή περιορισμός i, το στοιχείο i του δεξιού μέρους και του eqtype, η στήλη k από την μήτρα των συντελεστών A, καθώς και το στοιχείο k της αντικειμενικής συνάρτησης z. Μετά την εξέταση όλων των περιπτώσεων και την διαγραφή κάποιων περιορισμών, μπορεί να προκύψουν εκ νέου k-ton γραμμές, οπότε, κρίνεται απαραίτητο να επαναληφθεί η διαδικασία μέχρις ότου να μην υπάρχει κανένας k-ton περιορισμός στο τελικά διαμορφωμένο πρόβλημα. Η μέθοδος θα εφαρμοστεί στο παρακάτω ΓΠ πρόβλημα: min z 4x x 2x x 1 2 3 4 s. t. 2x x 4x 10 1 3 4 2x 6 2 8x 4x 4 1 3 3x x 3x 12 1 2 4 x 0, i 1,.., n και, b, c i Η μορφή των πινάκων είναι η εξής: nxm m n 2 0 1 4 4 10 0 0 2 0 0 1 6 0 A, c, b, eqtype και c0 0 8 0 4 0 2 4 0 3 1 0 3 1 12 0 Έστω ότι ερευνάται η ύπαρξη k-ton ισοτικών περιορισμών με k=2. Στην 3 η γραμμή εμφανίζονται μόνο k=2 μη μηδενικά στοιχεία. Εντοπίζεται η στήλη j 3 όπου βρίσκεται το τελευταίο μη μηδενικό στοιχείο αυτής της γραμμής και ακολουθεί η ενημέρωση των A και b: b b / A 4 / 4 1 3 3 33 A A / A [8 0 4 0] / 4 [2 0 1 0] 3 3 34 eqtype[3] 1 Προτού διαγραφεί η μεταβλητή x 3 από το πρόβλημα, απαλείφεται αυτή και από τους υπόλοιπους περιορισμούς όπου υφίσταται, όπως στον 1 ο : 28
A A / A [2 0 1 4] 1*[2 0 1 0] [0 0 0 4] 1 1 13 b b A b 10 1*1 9 1 1 13 3 c c c b 0 2*1 2 0 0 3 3 c c c A [-4 1 2 1] 2 [2 0 1 0] [ 8 1 0 1] T T T T 3 3 Διαγράφοντας την 3 η μεταβλητή από το πρόβλημα, προκύπτουν: 0 0 4 9 0 8 0 2 0 6 0 A, c 1, b, eqtype και c0 2 2 0 0 1 1 1 3 1 3 12 0 Το k μειώνεται κατά ένα (k=1) και ακολουθείται η διαδικασία 3.3. 1 def elimkton(a,b,c,c0,eq,kton,infy): 2 ''' 3 Επαναληπτική απαλοιφή ισοτικών περιορισμών και μεταβλητών του προβλήματος 4 με k μη μηδενικά στοιχεία 5 ''' 6 print(' CASE 4 ') 7 #Οι διαστασεις του προβλήματος 8 m,n=np.shape(a) 9 lindr=list(range(0,m))#λίστα των προς διαγραφή γραμμών 10 lindc=list(range(0,n))#λίστα των προς διαγραφή στηλών 11 for k in range(kton,0,-1):#για κάθε περιορισμό με k μη μηδενικά στοιχεία 12 mask=(a.indptr[1:] - a.indptr[:-1])#πόσα μη μηδενικά έχει κάθε γραμμή 13 rows=np.where((mask==k) & (eq[:,0]==0))#ποιές γραμμές έχουν το πολύ k στοιχεία 14 rows=rows[0]#παίρνει το array των δεικτών γραμμών από το tuple του where 15 rows = rows[::-1]#αντιστροφή των στοιχείων του πίνακα 16 for d in rows:# Για κάθε kton γραμμή 17 j=a.indices[a.indptr[d]+k-1]#σε ποιά στήλη βρίσκεται το k μη μηδενικό στοιχείο 18 idx2=[]#βοηθητική λίστα με τις γραμμές με μη μηδενικά στοιχεία στην στήλη j 19 m3,n3=np.shape(a)#η τρέχουσα διάσταση του Α 20 for g in range(m3): 21 if a[g,j]!=0 and g!=d: 22 idx2.append(g) 23 if idx2==[]:#αν η στήλη j (εκτός από από το στοιχείο d)δεν έχει καθόλου στοιχεία 24 b[d]=b[d]/(a[d,j])#ενημέρωση των πινάκων 25 a[d,:]=a[d,:]/a[d,j] 26 for g in range(m3): 27 if a[g,j]!=0 and g!=d: 28 b[g]-=a[g,j]*b[d] 29 a[g,:]-=a[g,j]*a[d,:] 30 if j in lindc: 31 lindc.remove(j)#διαγραφή της μεταβλητής j 32 eq[d]=-1#αλλαγή του τύπου του d περιορισμού 33 if c[j][0]!=0: 34 c0+=(c[j].a*b[d].a)[0] 35 c-=(c[j][0]*a[d,:]).t 36 a=csr_matrix(a).tocsr() 37 b=csr_matrix(b).tocsr() 38 if b[d]<0: 39 print('infeasible found') 40 infy=true 41 break 42 else: 43 lindr.remove(d) 44 a=csr_matrix(a)[lindr,:] 29
45 b=csr_matrix(b)[lindr] 46 a=csr_matrix(a)[:,lindc] 47 eq=eq[lindr] 48 c=csr_matrix(c)[lindc] 49 print('found and Eliminated',m-len(lindr),'redudant Rows') 50 print('found and Eliminated',n-len(lindc),'redudant Columns') 51 print('infeasibility found:',infy) 52 return a,b,c,c0,eq,k,infy Λίστα Κώδικα 7. Απαλοιφή ισοτικών περιορισμών τύπου k-ton 3.5 Απαλοιφή ανισοτικών περιορισμών τύπου singleton Παρόμοια με την μέθοδο της παραγράφου 3.3, ένας ανισοτικός περιορισμός είναι τύπου singleton, εάν στην αντίστοιχη γραμμή της μήτρας Α των συντελεστών υπάρχει μόνο ένα μη μηδενικό στοιχείο. Η μέθοδος μπορεί να οδηγήσει σε προσδιορισμό αδυναμίας επίλυσης του αρχικού προβλήματος ή στην διαγραφή γραμμών αλλά και στηλών, μειώνοντας έτσι αρκετά την διάσταση του προβλήματος. Μια τέτοια ανισότητα έχει την εξής μορφή: b A x A x A x b i i1 1 i2 2... in n i όπου i 1,2,..., m και A 0 A 0, j k, j 1,2,..., n Σε αυτή τη μορφή διακρίνονται οι πιο κάτω περιπτώσεις: 1. Ανισότητες τύπου bi a. Aik 0 b. Aik 0 2. Ανισότητες τύπου bi a. Aik 0 b. Aik 0 i. bi 0 : το ΓΠ είναι αδύνατο ik ii. bi 0 : διαγραφή γραμμής i και στήλης k i. bi 0 : διαγραφή γραμμής i i. bi 0 : διαγραφή γραμμής i i. bi 0 : το ΓΠ είναι αδύνατο 30 ij
ii. bi 0 : διαγραφή γραμμής i και στήλης k Η μέθοδος θα εφαρμοστεί στο παρακάτω ΓΠ πρόβλημα: min z x x 2x 4x 1 2 3 4 s. t. x 0 2 2x 2x x 5 1 2 3 x x x x 10 1 2 3 4 2x 2x 4 2 4 x 0, i 1,.., n και, b, c i Η μορφή των πινάκων είναι η εξής: nxm m n 0 1 0 0 1 0 1 2 2 1 0 1 5 1 A, c, b, eqtype 1 1 1 1 2 10 0 0 2 0 2 4 4 1 Υπάρχει μόνο μια γραμμή, η 1 η, με ένα μόνο μη μηδενικό στοιχείο, το A 12. Η περίπτωση στην οποία αναφέρεται είναι η 2.b.ii, οπότε η γραμμή 1 και η στήλη 2 διαγράφονται. Το νέο πρόβλημα που προκύπτει είναι: 2 1 0 1 5 1 A 1 1 1, c 2, b 10, eqtype 0 0 0 2 4 4 1 Στο νέο πρόβλημα προέκυψε νέα ανισότητα τύπου singleton, στην γραμμή 3, που ανήκει στην περίπτωση 1.b.i, οπότε η γραμμή 3 μπορεί να διαγραφεί. Το νέο πρόβλημα έχει την μορφή: 1 2 1 0 5 1 A, c 2, b, eqtype 1 1 1 10 0 4 Ακολουθεί ο αντίστοιχος κώδικας: 1 def delsingineq(a,b,c,eq,infy): 2 print(' CASE 5 ') 3 m,n=np.shape(a) 4 lindr=list(range(0,m)) 5 lindc=list(range(0,n)) 6 mask=(a.indptr[1:] - a.indptr[:-1]) 7 rows=np.where(mask==1) 8 rows=np.where((mask==1) & (eq[:,0]!=0)) 9 for i in rows[0]: 31
10 j=a.indices[a.indptr[i]] 11 if (eq[i]==-1 and a[i,j]>0 and b[i]<0) or(eq[i]==1 and a[i,j]<0 and b[i]>0): 12 infy=true 13 elif (eq[i]==-1 and a[i,j]<0 and b.a[i]>=0) or(eq[i]==1 and a[i,j]>0 and b.a[i]<=0): 14 lindr.remove(i) 15 elif (eq[i]==-1 and a[i,j]>0 and not b[i]!=0) or(eq[i]==1 and a[i,j]<0 and not b[i]!=0): 16 if j in lindc: 17 lindc.remove(j) 18 lindr.remove(i) 19 a=csr_matrix(a)[lindr,:] 20 a=csr_matrix(a)[:,lindc] 21 b=csr_matrix(b[lindr]) 22 c=csr_matrix(c[lindc]) 23 eq=eq[lindr] 24 print('found and Eliminated',m-len(lindr),'redudant Rows') 25 print('found and Eliminated',n-len(lindc),'redudant Columns') 26 print('infeasibility found:',infy) 27 return a,b,c,eq,infy Λίστα Κώδικα 8. Απαλοιφή ανισοτικών περιορισμών Singleton 3.6 Απαλοιφή δυϊκού ανισοτικού περιορισμού τύπου singleton Μετατρέποντας το αρχικό πρόβλημα στο αντίστοιχο δυϊκό του, ένας δυϊκός ανισοτικός περιορισμός είναι τύπου singleton αν έχει ένα μη μηδενικό στοιχείο και έχει την παρακάτω μορφή: A w A w A w c j1 1 j2 2... jm m j όπου j 1,2,..., n και A 0 A 0, i k, i 1,2,..., m jk ji Η παρουσία τέτοιων περιορισμών μπορεί να δηλώνει τον πλεονασμό τους ή ότι το δυϊκό πρόβλημα είναι απεριόριστο και το αρχικό αδύνατο. Χωρίς να είναι απαραίτητο να μετατραπεί το αρχικό πρωτεύον πρόβλημα στο δυϊκό του, και εξετάζοντας στήλες του πρωτεύοντος αντί γραμμές του δυϊκού, προκύπτουν οι παρακάτω περιπτώσεις: 1. Ανισότητες τύπου a. Akj 0 b. Akj 0 2. Ανισότητες τύπου a. Akj 0 i. c j 0 : πλεονάζουσα στήλη j i. c j 0 : το ΓΠ είναι αδύνατο ii. c j 0 : διαγραφή στήλης j i. c j 0 : το ΓΠ είναι αδύνατο 32 που μπορεί να επαλειφθεί και γραμμής
b. Akj 0 ii. c j 0 : διαγραφή στήλης j i. c j 0 : πλεονάζουσα στήλη j και γραμμής k που μπορεί να επαλειφθεί Η διαδικασία μπορεί να επαναληφθεί από την αρχή, μετά το πέρας των αναζητήσεων τέτοιων δυϊκών ανισοτικών περιορισμών, καθώς μπορεί μετά την διαγραφή γραμμών και στηλών, να εμφανιστούν νέοι τέτοιου τύπου περιορισμοί. Η μέθοδος θα εφαρμοστεί στο παρακάτω ΓΠ πρόβλημα: min z 2x x 3x x 1 2 3 4 s. t. x x 2x 5 1 2 4 2x x 3 1 3 3x x x 12 1 2 4 x 0, i 1,.., n και, b, c i Η μορφή των πινάκων είναι η εξής: nxm m n 2 1 1 0 2 5 1 1 A 2 0 1 0, c, b 3, eqtype 1 3 3 1 0 1 12 1 1 Αναζητώντας στήλες με μόνο ένα μη μηδενικό στοιχείο εντοπίζεται μόνο η 3 η. σύμφωνα με την περίπτωση 1.a.i., η στήλη j 3 είναι πλεονάζουσα και μπορεί να διαγραφεί, όπως και το στοιχείο c 3 της γραμμής κόστους. Έτσι, προκύπτει το νέο πρόβλημα: min z 2x x x 1 2 4 s. t. x x 2x 5 1 2 4 2x 3 1 3x x x 12 1 2 4 1 def deldualsing(a,b,c,eq,infy): 2 print(' CASE 6 ') 3 m,n=np.shape(a) 4 lindr=list(range(0,m)) 5 lindc=list(range(0,n)) 6 a=a.tocsc() 7 mask=(a.indptr[1:] - a.indptr[:-1]) 8 cols=np.where(mask==1)#παρε τους δείκτες stilis μόνο 9 for j in cols[0]: 10 i=a.indices[a.indptr[j]] 11 if (eq[i]<0 and a[i,j]<0 and c[j]<0) or(eq[i]>0 and a[i,j]>0 and c[j]<0): 12 infy=true 33
13 elif (eq[i]<0 and a[i,j]>0 and c.a[j]>=0) or(eq[i]>0 and a[i,j]<0 and c.a[j]>=0): 14 lindc.remove(j) 15 elif (eq[i]<0 and a[i,j]<0 and not c[j]!=0) or(eq[i]>0 and a[i,j]>0 and not c[j]!=0): 16 lindr.remove(i) 17 lindc.remove(j) 18 a=csr_matrix(a)[lindr,:] 19 a=csr_matrix(a)[:,lindc] 20 b=csr_matrix(b[lindr]) 21 c=csr_matrix(c[lindc]) 22 eq=eq[lindr] 23 print('found and Eliminated',m-len(lindr),'redudant Rows') 24 print('found and Eliminated',n-len(lindc),'redudant Columns') 25 print('infeasibility found:',infy) 26 return a,b,c,eq,infy Λίστα Κώδικα 9. Απαλοιφή δυϊκών περιορισμών 3.7 Απαλοιφή εμμέσως ελεύθερων στηλών τύπου singleton Υπάρχουν περιορισμοί που μπορεί να παρουσιάζουν ελεύθερες στήλες singleton, δηλαδή να περιέχουν το μοναδικό μη μηδενικό στοιχείο μιας στήλης, έχοντας όμως και τα πιο κάτω χαρακτηριστικά: A x A x b i 1 is s όπου i 1,2,..., m και A 0 A { A } 0 is s is Οι περιπτώσεις κατά τις οποίες η s στήλη του A είναι πλεονάζουσα είναι: 1. A 0 A 0, j s ή is 2. A 0 A 0, j s ή is Επιπλέον, και ο ij ij i περιορισμός μπορεί να απαλειφθεί. Πριν ολοκληρωθεί η απαλοιφή αυτών των στοιχείων, γίνεται έλεγχος αν cs 0, ώστε να ενημερωθεί κατάλληλα η γραμμή κόστους: c0 c0 ( cs / Ais ) bi T c c ( cs / Ais ) Ai Η μέθοδος θα εφαρμοστεί στο παρακάτω ΓΠ πρόβλημα: min z 2x x 2x x 1 2 3 4 s. t. 3x 4x x 8 2 3 4 x x 2x 6 1 2 4 2x 3x x 6 2 3 4 xi 0, i 1,..,4 και, b, c 3x4 3 4 Η μορφή των πινάκων είναι η εξής: 34
2 0 3 4 1 8 1 1 A 1 1 0 2, c, b 6, eqtype 1 2 0 2 3 1 6 1 1 Υπάρχει μια singleton στήλη, η 1 η ( s ), όπου το μη μηδενικό στοιχείο της, βρίσκεται στην 2 η γραμμή (i ) για την οποία ισχύει η περίπτωση (1). Επειδή c1 2 0 γίνεται ενημέρωση της γραμμής κόστους z : c c ( c / A ) b 0 2 /16 12 0 0 1 21 2 2 c c ( c / A ) A [2 1 2-1] [1-1 0-2] [0 3 2 3] 2 T T T T 1 21 2 Έτσι, διαγράφεται η 1 η στήλη και η 2 η γραμμή του A, το 1 ο στοιχείο το c και το 2 ο στοιχείο των b και eqtype. Το νέο, ισοδύναμο, πρόβλημα είναι το παρακάτω: min z 3x 2x 3x 12 2 3 4 s. t. 3x 4x x 8 2 3 4 2x 3x x 6 2 3 4 Ακολουθεί ο αντίστοιχος κώδικας σε python. 1 def delimpliedfreesing(a,b,c,c0,eq): 2 print(' CASE 7 ') 3 m,n=np.shape(a) 4 lindr=list(range(0,m)) 5 lindc=list(range(0,n)) 6 a=a.tocsc() 7 mask=(a.indptr[1:] - a.indptr[:-1]) 8 cols=np.where(mask==1)#παρε τους δείκτες stilis μόνο 9 for k in cols[0]: 10 i=a.indices[a.indptr[k]] 11 row=a[i,:].a 12 ais=a[i,k] 13 row=np.delete(row,k) 14 if ais>0: 15 m2=np.all(row<=0) 16 else: 17 m2=np.all(row>=0) 18 if m2: 19 lindr.remove(i) 20 lindc.remove(k) 21 if c[k]!=0: 22 cs=c[k].toarray()[0][0] 23 c=c-(cs/ais)*np.transpose(a[i,:]) 24 c0=c0+(cs/ais)*b[i].a 25 elif not m2: 26 lindr.remove(i) 27 a=csr_matrix(a)[lindr,:] 28 a=csr_matrix(a)[:,lindc] 29 b=csr_matrix(b[lindr]) 30 c=csr_matrix(c[lindc]) 31 eq=eq[lindr] 32 print('found and Eliminated',m-len(lindr),'redudant Rows') 33 print('found and Eliminated',n-len(lindc),'redudant Columns') 35
34 return a,b,c,c0,eq Λίστα Κώδικα 10. Απαλοιφή ελεύθερων στηλών 3.8 Απαλοιφή πλεονασματικών στηλών Ένας ισοτικός περιορισμός με μηδενικό δεξιό μέρος, που έχει όλους τους συντελεστές του με ίδιο πρόσημο, υποδηλώνει την ύπαρξη πλεονασματικών μεταβλητών οι οποίες δεν επηρεάζουν την επίλυση του προβλήματος και μπορούν να διαγραφούν. Πιο συγκεκριμένα: Ai 1x1 Ai 2x2... Ain xn 0 όπου i 1,2,..., m και A 0 ή A 0, j 1,2,..., n Αυτή η περίπτωση εξετάζεται στο επόμενο παράδειγμα: min z 3x 2x x x 1 2 3 4 s. t. 2x x 3x x 6 ij 1 2 3 5 x x 3x 0 2 3 5 x x 3x x 3 1 2 3 4 x 2 4 ij 3x 4 x 0, i 1,.., n και, b, c i Η μορφή των πινάκων είναι η εξής: nxm m n 3 2 1 3 0 1 6 1 2 0 1 1 0 3 0 0 A, c 1, b, eqtype 1 1 3 1 0 3 1 1 0 1 0 3 0 4 1 0 Για την 2 η γραμμή ( i 2) ισχύει A2 0 και b2 0, eqtype2 0. Οπότε, μπορεί να γίνει διαγραφή των μεταβλητών x2, x3 και x 5 και των αντίστοιχων στοιχείων του c. Έτσι, προκύπτει το ακόλουθο πρόβλημα: Ακολουθεί ο αντίστοιχος κώδικας: min z 3x x 1 4 s. t. 2x 6 1 x x 3 1 4 3x 4 4 36
1 def delredudantcols(c,a,eq): 2 print(' CASE 8 ') 3 m1=np.where(eq==0) 4 m,n=np.shape(a) 5 lind=list(range(0,n)) 6 for i in m1[0]: 7 m2=np.where(np.where(a.a[i,:]>0,np.all(a.a[i,:]>=0),np.all(a.a[i,:]<=0))) 8 lind=delind(lind,m2) 9 a=csr_matrix(a)[:,lind] 10 c=csr_matrix(c[lind]) 11 print('found and Eliminated',n-len(lind),'redudant Columns') 12 return c,a,eq Λίστα Κώδικα 11. Απαλοιφή πλεονασματικών στηλών 3.9 Απαλοιφή έμμεσων ορίων γραμμών Ένας περιορισμός που υποδηλώνει νεα όρια για τις μεταβλητές, μπορεί να θεωρηθεί πλεονασματικός και να διαγραφεί. Πιο συγκεκριμένα, διακρίνονται οι παρακάτω περιπτώσεις: 1. Περιορισμός τύπου, 0 και b 0 ή Ai 2. Περιορισμός τύπου, 0 και b 0 Στις οποίες η γραμμή i είναι πλεονασματική και διαγράφεται. Ai min z x x 3x i i 1 2 3 s. t. 2x x x 10 1 2 3 x 3x x 5 1 2 3 2x 2x 3x 4 1 2 3 x 0, i 1,.., n και, b, c i nxm m n Με μορφή πινάκων το ΓΠ ξαναγράφεται ως εξής: 2 1 1 1 10 1 A 1 3 1, c 1, b 5, eqtype 1 2 2 3 1 4 1 Η περίπτωση (1) συναντάται στον περιορισμό 2, ο οποίος και διαγράφεται. Το νέο πρόβλημα που προκύπτει είναι το εξής: min z x x 3x 1 2 3 s. t. 2x x x 10 1 2 3 2x 2x 3x 4 1 2 3 Στην επόμενη λίστα παρουσιάζεται ο κώδικας της μεθόδου. 1 def delimplied(a,b,eq): 2 print(' CASE 9 ') 37
3 m,n=np.shape(a) 4 lind=list(range(0,m)) 5 rowsl=np.where(eq==-1) 6 rowsg=np.where(eq==1) 7 for i in rowsl[0]: 8 m0=(np.all(a.a[i,:]<=0)) and (b.a[i]>=0)#& (b[i]>=0) 9 if m0: 10 lind.remove(i) 11 for i in rowsg[0]: 12 m0=(np.all(a.a[i,:]>=0)) and (b.a[i]<=0)#& (b[i]>=0) 13 if m0: 14 lind.remove(i) 15 a=csr_matrix(a)[lind,:] 16 b=csr_matrix(b[lind]) 17 print('found and Eliminated',m-len(lind),'redudant Rows') 18 return a,b,eq Λίστα Κώδικα 12. Απαλοιφή έμμεσων ορίων γραμμών 3.10 Απαλοιφή πλεονασματικών γραμμών Η συγκεκριμένη μέθοδος αφορά τον εντοπισμό γραμμικώς εξαρτημένων γραμμών στο σύστημα των ανισοτήτων του ΓΠ, όταν δηλαδή για τις γραμμές i και k με i k, ισχύει: A A με και i, k {1,2,..., m} i k Η μέθοδος εφαρμόζεται όταν το ΓΠ βρίσκεται στην τυποποιημένη του μορφή, αφού δηλαδή προστεθούν όλες οι χαλαρές μεταβλητές και όλοι οι περιορισμοί είναι ισοτικοί. Η πιο γνωστή μέθοδος είναι αυτή της απαλοιφής του Gauss. Εδώ χρησιμοποιείται μια παραλλαγή αυτής, όπου με συνεχείς γραμμοπράξεις εντοπίζονται γραμμικώς εξαρτημένες γραμμές οι οποίες αφού εντοπιστούν σημειώνονται (σε λίστα) και αφαιρούνται στο τέλος. Έστω για παράδειγμα, δύο περιορισμοί ενός ΓΠ: και το αντίστοιχο κομμάτι του A : 2x 3x 4x x 5 1 2 3 4 4x 6x 8x 2x 10 1 2 3 4 ( ) Η 1 η γραμμή πολλαπλασιάζεται με 4 / 2 και προστίθεται στην 2η. Προκύπτει ο επόμενος πίνακας: ( ) Αν προκύψει γραμμή όπως η 2 η, με Ak 0, διακρίνουμε περιπτώσεις: 38
1. Αν bk 0 : το πρόβλημα είναι αδύνατο, και 2. Αν bk 0 : η k γραμμή μπορεί να διαγραφεί. Ακολουθεί ο αντίστοιχος κώδικας. 1 def elimredrows(a,b,eq,infy):#ok pali 2 '''Εντοπίζει γραμμικώς εξαρτημένες γραμμές και τις διαγράφει 3 Δεν χρησιμοποιεί την μέθοδο Gauss Jordan αλλά ελέγχει για 4 εξαρτήσεις των γραμμών χωρίς να αλλάζει τον πίνακα Α, παρά μόνο 5 σβήνει, στο τέλος της διαδικασίας, τις πλεονάζουσες γραμμές 6 ''' 7 print(' CASE 10 ') 8 m,n=np.shape(a) 9 mask=(a.indptr[1:] - a.indptr[:-1])#πλήθος μη μηδενικών στοιχείων ανά γραμμή 10 rows=np.where(mask!=0)#ποιές γραμμές δεν είναι κενές 11 r=list(rows[0]) 12 r2=list(r) 13 for i in r:#rows[0]:#lind: 14 m2,n2=np.shape(rows) 15 idx=r.index(i)#np.where(rows[0]==i) 16 j=a.indices[a.indptr[i]] 17 aij=a.data[a.indptr[i]] 18 for ii in r[idx+1:n2]: 19 t1=(-a[ii,j]/aij)*a[i,:]+a[ii,:] 20 bt=b[i]/aij*(-a[ii,j])+b[ii] 21 if np.all(t1.a[0]==0): 22 if bt!=0: 23 infy=true 24 print('adynaton!!!!') 25 else: 26 r.remove(ii) 27 r2.remove(ii) 28 a=csr_matrix(a)[r2,:] 29 b=csr_matrix(b[r2]) 30 eq=eq[r2] 31 print('found and Eliminated',m-len(r2),'redudant rows') 32 print('the rank of the matrix A is now',len(r2),'or',min([m,len(r2)])) 33 print('infeasibility found:',infy) 34 return a,b,eq,infy Λίστα Κώδικα 13. Απαλοιφή πλεονασματικών γραμμών 3.11 Κλήση των προλυτικών μεθόδων Μετά την ανάγνωση του προβλήματος και την εισαγωγή χαλαρών μεταβλητών, γίνεται κλήση των προηγούμενων μεθόδων με την σειρά που αναφέρθηκαν. Η εκτέλεσή τους σταματά όταν η διάσταση του προβλήματος παραμείνει η ίδια μεταξύ δύο διαδοχικών κλήσεων, ακολουθεί ο κώδικας κλήσης των προλυτικών διαδικασιών. 1 def presolver(a,b,c,eq,infy): 2 count=0 3 c0=0 39
4 m1,n1=np.shape(a) 5 m0,n0=m1,n1 6 m=m1+1 7 infy=false 8 while m1!=m and m!=0 and not infy: 9 count+=1 10 m1=m 11 print('entering ',count,'times','m=',m1) 12 a,b,eq,infy=delzerorows(a,b,eq,infy) 13 a,c,unbound=delzerocols(a,c,false) 14 a,b,c,c0,eq,infy=elimsingeq(a,b,c,c0,eq,infy) 15 k=4 16 a,b,c,c0,eq,k,infy=elimkton2(a,b,c,c0,eq,k,infy) 17 a,b,c,eq,infy=delsingineq(a,b,c,eq,infy) 18 a,b,c,eq,infy=deldualsing(a,b,c,eq,infy) 19 a,b,c,c0,eq=delimpliedfreesing(a,b,c,c0,eq) 20 c,a,eq=delredudantcols(c,a,eq) 21 a,b,eq=delimplied(a,b,eq) 22 a,b,eq,infy=elimredrows(a,b,eq,infy) 23 m,n=np.shape(a) 24 25 print('entered ',count,'times','m=',m,'n=',n) 26 print('found and Eliminated',m0-m,'redudant rows &',n0-n,'redudant Columns') 27 return a,b,c,eq,infy,c0 Λίστα Κώδικα 14. Κλήση μεθόδων προεπίλυσης Ο παραπάνω κώδικας βρίσκεται στο αρχείο presolve.py και καλείται ως εξής: import presolve as pr a,b,c,eq,infy,c0=pr.presolver(a,b,c,eq,false) ενώ για την κλήση της απαιτούνται και τα πιο κάτω πακέτα from scipy.sparse import csr_matrix from scipy.sparse import csc_matrix 40
4 Τεχνικές κλιμάκωσης Ένα από τα χαρακτηριστικά των πραγματικών ΓΠ είναι η μεγάλη ανομοιογένεια των αριθμητικών δεδομένων. Οι μεγάλες αποκλίσεις που συναντώνται στις τιμές των δεδομένων τις περισσότερες φορές οδηγούν σε μια σειρά από προβλήματα, που μπορεί να οδηγήσουν σε σημαντικές αποκλίσεις στις λύσεις τους. Αυτά τα προβλήματα συσσωρεύονται με τους συνεχείς υπολογισμούς που λαμβάνουν χώρα κατά την διάρκεια επίλυσης. Η κλιμάκωση των προβλημάτων εξομαλύνει τις διαφορές των αριθμητικών τιμών των δεδομένων και, αν και απαιτεί κάποιο υπολογιστικό κόστος για την εφαρμογή τους, προσφέρει καλύτερη αριθμητική ακρίβεια στις λύσεις των προβλημάτων. 4.1 Μέθοδος της εξισορρόπησης Η πιο συχνή μέθοδος είναι αυτή της εξισορρόπησης (equilibration). Έχει ιδιαίτερα χαμηλές απαιτήσεις σε υπολογιστικούς πόρους και διαμορφώνει τις τιμές των δεδομένων της μήτρας των συντελεστών του ΓΠ να κυμαίνονται από -1 μέχρι 1. Το πρώτο βήμα έχει να κάνει με την εύρεση του μεγαλύτερου κατ απόλυτη τιμή στοιχείου κάθε γραμμής. Στην συνέχεια υπολογίζονται οι λεγόμενοι παράγοντες κλιμάκωσης γραμμής ως οι αντίστροφοι αριθμοί των μεγίστων των γραμμών του προηγούμενου βήματος. Με αυτούς τους παράγοντες πολλαπλασιάζονται τα στοιχεία κάθε γραμμής και του δεξιού μέρους. Με παρόμοιο τρόπο, για κάθε στήλη της μήτρας των συντελεστών υπολογίζεται το μεγαλύτερο κατά απόλυτη τιμή στοιχείο. Οι αντίστροφοι αυτών των τιμών χρησιμοποιούνται για να πολλαπλασιάσουν κάθε στήλη και τα αντίστοιχα στοιχεία της γραμμής κόστους. Ακολουθεί η εφαρμογή της μεθόδου στο πιο κάτω ΓΠ: min z 5x 600x 20x 1 2 3 s. t. 12x 44x 12 1 3 4x 150x 52x 55 1 2 3 48x 22x 12x 22 xi 1 2 3 0, i 1, 2,3 Με μορφή πινάκων το ΓΠ ξαναγράφεται ως εξής: 41
12 0 44 5 12 A 4 150 52, c 600, b 55 48 22 12 20 22 Υπολογίζονται τα μεγαλύτερα σε απόλυτη τιμή στοιχεία κατά γραμμή: 44 max r 150 48 Ο πίνακας των παραγόντων κλιμάκωσης γραμμών: 1/ 44 0.023 1 r 1/150 0.007 max r 1/ 48 0.021 Στη συνέχεια, πολλαπλασιάζονται οι γραμμές του A και τα στοιχεία του b με τον r. Ο νέος πίνακας A είναι: 0.2727 0 1 A 0.0267 1 0.3467 1 0.4583 0.25 Αμέσως μετά υπολογίζονται οι μεγαλύτεροι συντελεστές ανά στήλη: 1 max c 1 1 και ο πίνακας παραγόντων ανά στήλη: 1/1 1 1 s 1/1 1 max c 1/1 1 τα στοιχεία του οποίου θα πολλαπλασιάσουν κάθε αντίστοιχη στήλη του A και του c. Στο παράδειγμα, επειδή κάθε στοιχείο του s είναι μονάδα ( s 1, j 1, 2,3 ), τα A και c δεν θα αλλάξουν. Έτσι, το νέο κλιμακωμένο πρόβλημα είναι το εξής: 0.2727 0 1 5 0.2727 A 0.0267 1 0.3467, c 600, b 0.3667 1 0.4583 0.25 20 0.25 Ακολουθεί ο κώδικας υλοποίησης της μεθόδου σε python. j 42
1 # -*- coding: utf-8 -*- 2 import numpy as np 3 from scipy.sparse import csr_matrix 4 from scipy.sparse import csc_matrix 5 import scipy.sparse as sp 6 7 """ 8 Created on Sun Feb 21 09:25:17 2016 9 10 @author: Tsiplidis Konstantinos 11 """ 12 13 def equilibration(a,b,c): 14 ''' 15 Περιγραφή: Εφαρμόζεται η μέθοδος equilibration για την κλιμάκωση μεγάλου μεγέθους 16 προβλημάτων προκειμένου να λυθούν με κάποιο λύτη Γραμμικού Προγραμματισμού. 17 Κάθε γραμμή και κάθε στήλη πολλαπλασιάζεται διαδοχικά με το μέγιστο μη 18 μηδενικό στοιχείο της 19 @author: Tsiplidis Konstantinos 20 Συγγραφέας: Τσιπλίδης Κωνσταντίνος 21 Πηγή: Ploskas & Samaras 22 Αρχείο: scaling.py 23 Κλήση: a,b,c=equilibration(a,b,c) 24 Χρήση - Ενσωμάτωση: from scaling import equilibration 25 Βιβλιοθήκες: numpy, scipy 26 Είσοδος:-a: η μήτρα των συντελεστών του γραμμικού προβλήματος 27 csr scipy matrix μεγέθους mxn 28 -b: το διάνυσμα του δεξιού μέρους csr scipy matrix μεγέθους mx1 29 -c: το διάνυσμα της αντικειμενικής συνάρτησης csr scipy matrix μεγέθους nx1 30 Έξοδος: οι νέες τιμές των πινάκων εισόδου (a, b, c) 31 Χρόνος Εκτέλεσης: a=sp.rand(10000,1000, density=0.0001,format='csr') 32 timeit -n 100 equilibration(a,b,c) 33 100 loops, best of 3: 1.13 s per loop 34 Περιορισμός του δυνατού μεγέθους του Α σε 10.000x1.000 στοιχεία 35 ''' 36 #Επιλέγεται το μεγαλύτερο από κάθε γραμμή 37 max_per_row = abs(a).a.max(axis=1)#το ".Α" μετατρέπει το a σε dense μήτρα 38 #με αποτέλεσμα να καθυστερεί χρονικά και να περιορίζει ΠΟΛΥ το μέγιστο μέγεθος του Α 39 #αντικαθίστανται τα 0 με 1 40 max_per_row =np.where(max_per_row==0,1,max_per_row) 41 #πολλαπλασιάζεται κάθε γραμμή με τον συντελεστή 1/max 42 a=csr_matrix((a.transpose().a *1.0/ max_per_row).transpose()) 43 #Επιλέγεται το μεγαλύτερο από κάθε στήλη 44 max_per_col = abs(a).a.max(axis=0) 45 #αντικαθίστανται τα 0 με 1 46 max_per_col =np.where(max_per_col==0,1,max_per_col) 47 #πολλαπλασιάζεται κάθε στήλη με τον συντελεστή 1/max 48 a=csr_matrix(a.a*1.0/max_per_col) 49 #Ενημερώνονται τα διανύσματα b και c 50 b=csr_matrix((b.transpose()*1.0/max_per_row).transpose()) 51 c=csr_matrix((c.transpose()*1.0/max_per_col).transpose()) 52 return a,b,c Λίστα Κώδικα 15. Κλιμάκωση με την Μέθοδο Εξισορρόπησης Ακολουθεί μια 2 η έκδοση του κώδικα με την χρήση βρόγχων: 1 def equilibration2(a,b,c): 2 ''' 43
3 Περιγραφή: Εφαρμόζεται η μέθοδος equilibration για την κλιμάκωση μεγάλου μεγέθους 4 προβλημάτων προκειμένου να λυθούν με κάποιο λύτη Γραμμικού Προγραμματισμού. 5 Κάθε γραμμή και κάθε στήλη πολλαπλασιάζεται διαδοχικά με το μέγιστο μη 6 μηδενικό στοιχείο της 7 Συγγραφέας: Τσιπλίδης Κωνσταντίνος 8 Πηγή: Ploskas & Samaras 9 Αρχείο: scaling.py 10 Κλήση: a,b,c=equilibration(a,b,c) 11 Χρήση - Ενσωμάτωση: from scaling import equilibration 12 Βιβλιοθήκες: numpy, scipy 13 Είσοδος:-a: η μήτρα των συντελεστών του γραμμικού προβλήματος 14 csr scipy matrix μεγέθους mxn 15 -b: το διάνυσμα του δεξιού μέρους csr scipy matrix μεγέθους mx1 16 -c: το διάνυσμα της αντικειμενικής συνάρτησης csr scipy matrix μεγέθους nx1 17 Έξοδος: οι νέες τιμές των πινάκων εισόδου (a, b, c) 18 Χρόνος Εκτέλεσης: a=sp.rand(1000000,1000, density=0.00001,format='csr') 19 timeit -n 100 equilibration2(a,b,c) 20 100 loops, best of 3: 252 ms per loop 21 100 loops, best of 3: 312 ms per loop μαζι με τα b, c 22 a=sp.rand(1000000,1000, density=0.0001,format='csr') 23 10 loops, best of 3: 2.01 s per loop 24 a=sp.rand(10000,1000, density=0.0001,format='csr') 25 timeit -n 100 equilibration2(a,b,c) 26 100 loops, best of 3: 34.7 ms per loop 27 Περιορισμός του δυνατού μεγέθους του Α σε 1.000.000x1.000 στοιχεία 28 ''' 29 m,n=np.shape(a)#οι διαστάσεις του Α 30 mask=(a.indptr[1:] - a.indptr[:-1])#πόσα μη μηδενικά έχει κάθε γραμμή 31 rows=np.where((mask!=0) )#Ποιές γραμμές δεν είναι μηδενικές 32 max_per_row=np.ones(m)#αρχικοποίηση με 1 του διανύσματος με τα max κάθε γραμμής 33 for i in rows[0]:#για κάθε μη μηδενική γραμμή 34 max_per_row[i]=np.max(abs(a.data[a.indptr[i]:a.indptr[i+1]]))#εύρεση του max 35 a.data[a.indptr[i]:a.indptr[i+1]]*=1.0/ max_per_row[i]#ενημέρωση του Α 36 max_per_col=np.ones(n)#αρχικοποίηση με 1 του διανύσματος με τα max κάθε στήλης 37 a2=csc_matrix(a)# μετατροπή του Α σε csc 38 #επιβάρυνση από την μετατροπή του Α σε csc 39 #timeit -n 100 a2=csc_matrix(a) 40 #100 loops, best of 3: 7.73 ms per loop 41 mask=(a2.indptr[1:] - a2.indptr[:-1])#πόσα μη μηδενικά έχει κάθε στήλη 42 cols=np.where((mask!=0) )#Ποιές στήλες δεν είναι μηδενικές 43 for i in cols[0]:#για κάθε μη μηδενική στήλη 44 max_per_col[i]=np.max(abs(a2.data[a2.indptr[i]:a2.indptr[i+1]]))#εύρεση του max 45 a2.data[a2.indptr[i]:a2.indptr[i+1]]*=1.0/ max_per_col[i]#ενημέρωση του Α 46 b=csr_matrix((b.transpose()*1.0/max_per_row).transpose())#ενημέρωση του b 47 c=csr_matrix((c.transpose()*1.0/max_per_col).transpose())#ενημέρωση του c 48 a=csr_matrix(a2)# μετατροπή του Α σε csr 49 50 return a,b,c,max_per_col,max_per_row Λίστα Κώδικα 16. Μέθοδος της εξισορρόπησης (με βρόγχο) 4.2 Μέθοδος του γεωμετρικού μέσου Στόχος αυτής της τεχνικής είναι να ελαχιστοποιήσει την διακύμανση τιμών των μη μηδενικών στοιχείων της μήτρας A των συντελεστών του ΓΠ. Και σε αυτήν την 44
μέθοδο, όπως και στην προηγούμενη, χρησιμοποιούνται δύο βοηθητικοί πίνακες παράγοντες κλιμάκωσης, η κατασκευή των οποίων γίνεται με το παρακάτω τρόπο: r max x min x k 1 k k i ij ij jni jni και αφορά την κλιμάκωση γραμμών, ενώ για τις στήλες, υπολογίζεται ως εξής: s x x 1 2 1 1 k 1 k k 2 2 j max ij min ij jm j jm j απαιτείται δηλαδή η εύρεση του μεγαλύτερου και του μικρότερου μη μηδενικού κατά απόλυτη τιμή στοιχείου κάθε γραμμής και κάθε στήλης. min z 5x 600x 20x 1 2 3 1 3 1 2 3 1 2 3 1 2 s. t. 12x 44x 12 4x 150x 52x 55 48x 22x 12x 22 xi 0, i 1, 2,3 Με μορφή πινάκων το ΓΠ ξαναγράφεται ως εξής: 12 0 44 5 12 A 4 150 52, c 600, b 55 48 22 12 20 22 Υπολογίζονται τα μεγαλύτερα και τα μικρότερα σε απόλυτη τιμή στοιχεία κατά γραμμή και στην συνέχεια ο πίνακας των παραγόντων κλιμάκωσης γραμμών: 1 (4412) 2 0.044 1 r (150 4) 2 0.041 1 (48 12) 2 0.042 τα στοιχεία του οποίου θα κλιμακώσουν τα A και b, και θα αποκτήσουν τις επόμενες τιμές: 0.522 0 1.914 0.522 A 0.163 6.123 2.122, b 2.245 2 0.916 0.5 0.916 Πάλι επιλέγονται τα μεγαλύτερα και μικρότερα στοιχεία κάθε στήλης για να δημιουργηθεί ο πίνακας παραγόντων στηλών s : 45
1 (20.052) 2 0.978 1 s (6.123 0.916) 2 0.422 1 (2.122 0.5) 2 0.971 Με τα στοιχεία του οποίου θα πολλαπλασιαστεί κάθε στήλη του A. Τελικά, μετά και την νέα κλιμάκωση και των στηλών, η τελική μορφή των πινάκων του προβλήματος θα είναι: 0.511 0 1.873 4.892 0.522 A 0.069 2.585 0.896, c 253.243, b 2.245 1.941 0.889 0.485 19.412 0.916 Η μέθοδος υλοποιείται με τον παρακάτω κώδικα: 1 def geometric(a,b,c): 2 ''' 3 Περιγραφή: Εφαρμόζεται η μέθοδος equilibration για την κλιμάκωση μεγάλου μεγέθους 4 προβλημάτων προκειμένου να λυθούν με κάποιο λύτη Γραμμικού Προγραμματισμού. 5 Κάθε γραμμή και κάθε στήλη πολλαπλασιάζεται διαδοχικά με το μέγιστο μη 6 μηδενικό στοιχείο της 7 Συγγραφέας: Τσιπλίδης Κωνσταντίνος 8 Πηγή: Ploskas & Samaras 9 Αρχείο: scaling.py 10 Κλήση: a,b,c=equilibration(a,b,c) 11 Χρήση - Ενσωμάτωση: from scaling import equilibration 12 Βιβλιοθήκες: numpy, scipy 13 Είσοδος:-a: η μήτρα των συντελεστών του γραμμικού προβλήματος 14 csr scipy matrix μεγέθους mxn 15 -b: το διάνυσμα του δεξιού μέρους csr scipy matrix μεγέθους mx1 16 -c: το διάνυσμα της αντικειμενικής συνάρτησης csr scipy matrix μεγέθους nx1 17 Έξοδος: οι νέες τιμές των πινάκων εισόδου (a, b, c) 18 Χρόνος Εκτέλεσης: a=sp.rand(1000000,1000, density=0.00001,format='csr') 19 timeit -n 100 equilibration2(a,b,c) 20 100 loops, best of 3: 252 ms per loop 21 100 loops, best of 3: 312 ms per loop μαζι με τα b, c 22 a=sp.rand(1000000,1000, density=0.0001,format='csr') 23 10 loops, best of 3: 2.01 s per loop 24 a=sp.rand(10000,1000, density=0.0001,format='csr') 25 timeit -n 100 equilibration2(a,b,c) 26 100 loops, best of 3: 34.7 ms per loop 27 Περιορισμός του δυνατού μεγέθους του Α σε 1.000.000x1.000 στοιχεία 28 ''' 29 m,n=np.shape(a)#οι διαστάσεις του Α 30 mask=(a.indptr[1:] - a.indptr[:-1])#πόσα μη μηδενικά έχει κάθε γραμμή 31 rows=np.where((mask!=0) )#Ποιές γραμμές δεν είναι μηδενικές 32 max_per_row=np.ones(m)#αρχικοποίηση με 1 του διανύσματος με τα max κάθε γραμμής 33 min_per_row=np.ones(m) 34 per_row_coef=np.ones(m) 35 for i in rows[0]:#για κάθε μη μηδενική γραμμή 36 min_per_row[i]=np.min(abs(a.data[a.indptr[i]:a.indptr[i+1]])) 37 max_per_row[i]=np.max(abs(a.data[a.indptr[i]:a.indptr[i+1]]))#εύρεση max 38 a.data[a.indptr[i]:a.indptr[i+1]]*=(max_per_row[i]*min_per_row[i])**(- 1.0/2) 46
39 b[i]*=(max_per_row[i]*min_per_row[i])**(-1.0/2) 40 per_row_coef=(max_per_row[i]*min_per_row[i])**(-1.0/2) 41 max_per_col=np.ones(n)#αρχικοποίηση με 1 του διανύσματος με τα max κάθε στήλης 42 min_per_col=np.ones(n) 43 per_col_coef=np.ones(n) 44 a2=csc_matrix(a)# μετατροπή του Α σε csc 45 #επιβάρυνση από την μετατροπή του Α σε csc 46 #timeit -n 100 a2=csc_matrix(a) 47 #100 loops, best of 3: 7.73 ms per loop 48 mask=(a2.indptr[1:] - a2.indptr[:-1])#πόσα μη μηδενικά έχει κάθε στήλη 49 cols=np.where((mask!=0) )#Ποιές στήλες δεν είναι μηδενικές 50 for i in cols[0]:#για κάθε μη μηδενική στήλη 51 min_per_col[i]=np.min(abs(a2.data[a2.indptr[i]:a2.indptr[i+1]])) 52 max_per_col[i]=np.max(abs(a2.data[a2.indptr[i]:a2.indptr[i+1]]))#εύρεση του max 53 a2.data[a2.indptr[i]:a2.indptr[i+1]]*=(max_per_col[i]*min_per_col[i])**(- 1.0/2)#Ενημέρωση του Α 54 c[i]*=(max_per_col[i]*min_per_col[i])**(-1.0/2) 55 per_col_coef=(max_per_col[i]*min_per_col[i])**(-1.0/2) 56 a=csr_matrix(a2)# μετατροπή του Α σε csc 57 return a,b,c,per_col_coef,per_row_coef Λίστα Κώδικα 17. Μέθοδος γεωμετρικού μέσου 4.3 Κλήση των διαδικασιών Το αρχείο scaling.py περιλαμβάνει τον κώδικα που παρουσιάστηκε στις προηγούμενες ενότητες με την μορφή συναρτήσεων της python και είναι διαθέσιμο σαν εξωτερική βιβλιοθήκη για κάθε άλλο πρόγραμμα. Για την χρήση τους αρκούν οι πιο κάτω εντολές: import scaling as sc a,b,c,per_col_coef,per_row_coef=sc.geometric(a,b,c) a,b,c,max_per_col,max_per_row=sc.equilibration2(a,b,c) 47
5 Ο αναθεωρημένος αλγόριθμος simplex δύο φάσεων Για την επίλυση των δοκιμαστικών μετροπροβλημάτων χρησιμοποιήθηκε ο αναθεωρημένος αλγόριθμος simplex δύο φάσεων με μια τεχνητή μεταβλητή revised two phase simplex algorithm (Bazaraa (2005), Hillier (2001), Papadimitriou (1982), Παπαρρίζος (2009)). Το γενικό ΓΠ που επιλύεται με τον αλγόριθμο είναι: ( ) (Γ.Π.) T ή πιο σύντομα: min{ c x : Ax b, x 0} Ο αλγόριθμος κατασκευάζει μια ακολουθία βασικών εφικτών λύσεων, ξεκινώντας από μια από αυτές. Αν δεν υπάρχει εξ αρχής μια εφικτή λύση, τότε χρησιμοποιείται η μέθοδος των δύο φάσεων, όπου αντί για το αρχικό πρόβλημα, λύνεται ένα τεχνητό αλλά εφικτό με την προσθήκη μιας νέας τεχνητής μεταβλητής. Η επίλυση του νέου αυτού προβλήματος γίνεται ανεξάρτητα στην ονομαζόμενη Φάση Ι. Η έξοδος από αυτή τη διαδικασία μπορεί να οδηγήσει στην Φάση ΙΙ, όπου, αφού βρεθεί μια εφικτή πλέον λύση, επιλύεται το αρχικό πρόβλημα, ή να προσδιοριστεί αδυναμία επίλυσής του. Ο αλγόριθμος με την μορφή βημάτων σε φυσική γλώσσα είναι ο εξής: ΒΗΜΑ 0 Αρχικοποίηση (Initialization) 1. Επιλογή μιας βασικής επιμέρισης ( BN), 2. Υπολογισμός των κάτωθι μητρών και διανυσμάτων: c c A x A b w c A s c w A 1 1 1,,,, T T, T T T B N B B B B N N N Όπου 1 A B μεταβλητές. είναι η αντίστροφη μήτρα του A, σχετική με τις βασικές 3. Αν x Bi 0, τότε η βασική διαμέριση δεν είναι εφικτή, οπότε και ξεκινάει η Φάση Ι. Διαφορετικά, επιλέγεται το ΒΗΜΑ 1. ΒΗΜΑ 1 Έλεγχοι 1. Έλεγχος Βελτιστότητας (Optimality Test): Τίθεται: J { j : j N και s j 0}. Αν J, ο αλγόριθμος σταματά και το τρέχον σημείο είναι βέλτιστο. 48
Διαφορετικά, επιλέγεται η εξερχόμενη της βάσης μεταβλητή x, l N[ t], όπου t επιλέγεται από έναν κανόνα περιστροφής. 2. Έλεγχος ελαχίστου λόγου (minimum ratio test): Υπολογίζονται τα: h A a και I i : 1 i m και h il 0. 1 l B l Αν I ο αλγόριθμος τερματίζεται, το πρόβλημα είναι απεριόριστο. l Διαφορετικά, επιλέγεται ως εξερχόμενη της βάσης μεταβλητή η τον τύπο: x Br x με k 1 1 AB b AB b i i xl min : i I hrl hil ΒΗΜΑ 2 Περιστροφή (pivot) Τίθεται N[] t έλεγχος στο ΒΗΜΑ 0.1. k και B[] r l ως νέα βασική διαμέριση και επιστρέφεται ο Η Φάση Ι του αλγορίθμου είναι η εξής: ΒΗΜΑ 0 Αρχικοποίηση (Initialization) 1. Εισάγεται μια νέα μεταβλητή απόφασης, η xn 1, με διάνυσμα συντελεστών d A e, όπου e 1 i 1,2,..., m, που ονομάζεται τεχνητή. B i 2. Τίθεται fi 0, i 1,2,..., n και fn 1 1 για τους συντελεστές της νέας γραμμής κόστους (του τεχνητού προβλήματος). 1 3. Υπολογίζεται το r arg minab b N N B r, B r : εξερχόμενη μεταβλητή και 4. Αλλάζει η βασική διαμέριση, B B [ n 1] Br 5. Υπολογίζονται τα νέα x A b, w f A και s f w A 1 T T 1 T T T B B B B N N N ΒΗΜΑ 1 Έλεγχος τερματισμού T 1. Αν s 0 ο αλγόριθμος σταματά. Αν x 1 0 ο αλγόριθμος σταματά, το N πρόβλημα είναι αδύνατο. Διαφορετικά, γίνεται επιστροφή στην Φάση ΙΙ από το τρέχον σημείο. n 49
T 2. Αν 0, επιλέγεται εισερχόμενη μεταβλητή με τον έλεγχο ελαχίστου s N i λόγου του Dantzig: sl min s j : s j 0 j N Υπολογισμός του h A a 1 l B l 3. Επιλογή εξερχόμενης από την βάση μεταβλητής με τον έλεγχο ελαχίστου λόγου: xb min i : i B hli ΒΗΜΑ 2 Περιστροφή T T T T Γίνεται περιστροφή και ανανέωση των B, N, f, f, x, w, s. Επιστροφή στο ΒΗΜΑ 1. B N B N Στην πράξη, όπως φαίνεται και στον κώδικα, υπάρχουν κάποια σημεία τα οποία είναι απαραίτητο να υπολογιστούν έμμεσα ή να γίνουν κάποιες τροποποιήσεις: Α) ο υπολογισμός της αντίστροφης μήτρας, 1 A B, δεν υπολογίζεται άμεσα ή από συνάρτηση (όπως η inv()). Αντί αυτού, χρησιμοποιείται η μορφή γινομένου της αντίστροφης (product form of the inverse) από τον τύπο: και E 1 B BE E B 1 1 1 1 1 Β) Μπαίνουν κάποια όρια ανοχές (tolerances) που αν ξεπεραστούν από κάποιο στοιχείο, τότε αυτό τίθεται ως μηδέν (πχ το 6 10 ). Γ) οι τιμές των μεταβλητών απόφασης στο βέλτιστο σημείο αφορούν το αλλαγμένο, κλιμακωμένο, πρόβλημα και όχι το αρχικό. Επειδή όμως δεν θα υπάρξει περαιτέρω ανάλυση της λύσης, όπως για παράδειγμα, ανάλυση ευαισθησίας, δεν γίνεται χρήση των τιμών των μεταβλητών. Αν κάτι τέτοιο ήταν επιθυμητό, θα έπρεπε να τηρηθεί πίνακας με τους παράγοντες κλιμάκωσης (κάτι που γίνεται στον κώδικα που παρουσιάστηκε στο κεφάλαιο 4) για την αποκλιμάκωσή τους στην τελική λύση. 50 h h 1l 1 h ml h r r h r 1
Παράδειγμα εφαρμογής του αλγορίθμου χωρίς Φάση Ι: min z x x 1 2 s. t. x x x 5 1 2 3 2x 3x x 3 xi 1 2 4 0, i 1,2,3,4 0 1 1 1 0 5 0 1 0 1 1 A, b, c, AB, AB 2 3 0 1 3 1 0 1 2 3 2 ΒΗΜΑ 0.1.υπάρχει βασική λύση, η B 3,4, οπότε 1,2 Υπολογίζονται: N. x B 1 1 1 0 5 1 0 5 5 AB b 0 1 3 0 1 3 3 Άρα το τρέχον βασικό σημείο είναι εφικτό. T T T T 2. c, c -1, -2 w c A 1, 0 0,, 0 0, B N B B s c w A T T N N N -1, -2 ΒΗΜΑ 1. 1. s j 0, άρα ο αλγόριθμος συνεχίζεται. N Επιλέγεται l 1, οπότε x 1 η εισερχόμενη μεταβλητή και t 1, αφού 1 l 1 1 1 0 1 1 2. υπολογίζεται το hl h1 AB a1 0, άρα η διαδικασία 0 1 2 2 δεν σταματά. Επιλέγεται εξερχόμενη μεταβλητή με τον επόμενο έλεγχο: οπότε, 2 1 xb 5 3 3 i x min : i B min, h 1 2 2 h r και k B B2 i1 21 2 4 και xk x4 : εξερχόμενη μεταβλητή. ΒΗΜΑ 2. Ανανεώνεται η βάση: Br B2 l 1 και νέα βάση που προκύπτει είναι η B 3,1 και N 4,2. N t N 1 k 4, οπότε, η 51
Επιστροφή στο ΒΗΜΑ 0.2 ΒΗΜΑ 0 (3 η επανάληψη) 2. T T 1 T T 1 cb 0, 1, cn 0, -1, w cb A B 0,, 2 s c w A T T N N N 1 2, -1 2 1 1 1 2 A B 0 0 1 2 x B 7 / 2 3 / 2 ΒΗΜΑ 1. 1. s j 0, άρα ο αλγόριθμος συνεχίζεται. Επιλέγεται ως εισερχόμενη η x 2. ΒΗΜΑ 2 1 2 2. h2, εξερχόμενη η x 3 1 αφού r 2 και k 1. 2 Τίθεται Br B2 l 2 και ΒΗΜΑ 0 (2 η επανάληψη) 2. T T 1 T T 2 cb 0, 1, cn 0, -2, w cb A B 0,, 3 s c w A T T T N N N N t N 1 k 1. Επιστροφή στην αρχή. 1 1 1 3 A B 0 1 3 2 3, 1 3 x B 4 1 ΒΗΜΑ 1. 1. sn 0, άρα ο αλγόριθμος σταματά εδώ, το τρέχον σημείο είναι βέλτιστο, με βέλτιστη τιμή της αντικειμενικής συνάρτησης: z c x T B B 2 Το επόμενο παράδειγμα επιλύεται χρησιμοποιώντας την Φάση Ι. 52
min z x x 1 2 s. t. x x 2x x x 5 1 2 3 4 6 2x 2x x x 3 1 2 5 6 xi 0, i 1,2,3,4 ΒΗΜΑ 0.1. Βασική διαμέριση η B 4,5 και N 1,2,3 x B 2 0, άρα ξεκινάει η Φάση Ι. 4 1 ΦΑΣΗ Ι. 1. A b i B x Άρα, 1 min : min min 2, 4 2. B i B i B r 4 x x εξερχόμενη. r και 4 B r Προστίθεται η τεχνητή μεταβλητή x 6 και υπολογίζεται το διάνυσμα των συντελεστών της: 1 1 01 1 d A B e 0 11 1 Οπότε, το νέο πρόβλημα, αυτό της Φάσης Ι, είναι: min z x x 1 2 s. t. x x 2x x x 5 1 2 3 4 6 2x 2x x x 3 1 2 5 6 με B 4,5 6 4 5,6 και 1,2,3 4 1,2,3,4 T T 2. f 0 1, f 0 0 0 0 B N N. 1 1 B, N, B, B 0 1 1 1 2 1 0 1 1 1 6 A A A x 1 1 2 2 0 0 1 1 1 0 2 T 1 1 w 0 1 1 0 1 0 T T T 1 1 2 1 sn fn w AN 2 2 0 0 0 0 0 0 1 0 1 1 2 1 T ΒΗΜΑ 1.1.επειδή s 0 ο αλγόριθμος συνεχίζεται. N Εισερχόμενος δείκτης ο και xl, l 4. s 0, άρα N4 4 οπότε η x 4 είναι εισερχόμενη μεταβλητή T N4 53
2. υπολογίζεται το 1 1 1 1 1 hl AB al 1 0 0 1 και αφού hl 0, ο αλγόριθμος συνεχίζεται. Ο έλεγχος ελαχίστου λόγου δίνει: x x 6 2 2 x min, min, h h 1 1 1 h B1 B2 B2 l1 l 2 l 2 και είναι r 2, k B 2 6. Η μεταβλητή x 6 είναι εξερχόμενη. ΒΗΜΑ 2. Τίθεται Br B2 l 4 και είναι: B 5,4 και N 1, 2,3,6 Φάση Ι Επανάληψη 2 η N t N 4 k 6. Οπότε τα νέα Β και Ν T T ΒΗΜΑ 0.1. f f f 0 0, f f f f f 0 0 0 1 B 5 4 N 1 2 3 6 0 1 1 1 2 1 1 0 1 4 AB, AN, AB, xb 1 0 2 2 0 1 1 0 2 T 0 1 w 0 0 0 0 1 0 T T T 1 1 2 1 sn fn w AN 2 2 0 1 0 0 0 1 0 0 0 0 0 1 ΒΗΜΑ 1.1. Επειδή sn 0 η τρέχουσα λύση είναι βέλτιστη και αφού η τεχνητή μεταβλητή x 6 έχει φύγει από την βάση και είναι μηδέν, η Φάση Ι σταματά. Τίθεται N N x 6 1 2 3 και γίνεται επιστροφή στην Φάση ΙΙ, όπου συνεχίζεται ο αλγόριθμος για την επίλυση του αρχικού προβλήματος με την τρέχουσα λύση B 5,4. Ακολουθεί ο αλγόριθμος κωδικοποιημένος σε python. 1 # -*- coding: utf-8 -*- 2 """ 3 Created on Sat May 21 20:42:01 2016 4 5 Algorithm: 2 Phases Revised Simplex with 1 artificial variable 6 @author: Tsiplidis Konstantinos 7 """ 8 import fileread as fr 54
9 import presolve as pr 10 import scaling as sc 11 import numpy as np 12 from scipy.sparse import csr_matrix 13 from scipy.sparse import csc_matrix 14 from scipy.sparse import hstack 15 from sympy import Matrix 16 import scipy.sparse.linalg as spsl 17 import scipy.sparse as sps 18 from numpy.linalg import inv 19 import os 20 import time 21 tol=0.00000001 22 #Εισαγωγή Δεδομένων 23 c0=0 24 print("reading files in directory...") 25 path='/mps_files/' 26 mpsfiles=[files for files in os.listdir(path) if files.endswith('.mps')] 27 #Για κάθε αρχείο MPS 28 for mps in mpsfiles:#[1]:#mps in 29 fname=path + '/' + mps 30 print('reading from file:',fname ) 31 start_time = time.time() 32 #Άνοιγμα του αρχείου 33 a,b,c,eq=fr.readfile(fname) 34 freadtime=(time.time() - start_time) 35 m0,n0=np.shape(a) 36 nnz1=len(a.data) 37 #Scaling Methods 38 start_time = time.time() 39 a,b,c,per_col_coef,per_row_coef=sc.geometric(a,b,c) 40 a,b,c,max_per_col,max_per_row=sc.equilibration2(a,b,c) 41 scaletime=(time.time() - start_time) 42 #presolve Technigues 43 start_time = time.time() 44 a,b,c,eq,infy,c0=pr.presolver(a,b,c,eq,false) 45 presolvetime=(time.time() - start_time) 46 start_time = time.time() 47 m,n=np.shape(a) 48 nnz2=len(a.data) 49 print('original problem dimensions:',m0,'x',n0) 50 print('reduced problem dimensions:',m,'x',n) 51 print("problem's dimension reduction:",m0-m,'rows &',n0- n,'columns') 52 stopped=false 53 ph1=false 54 #Εισαγωγή Χαλαρών Μεταβλητών 55 #για να παρει μόνο τον πινακα απο το tuple 56 mask=np.where(eq!=0)[0] 57 #Συνένωση των 3 διανυσμάτων στον Α 58 for i in mask: 59 ey=np.eye(m, 1, -i)*-eq[i]#+ή- πλεονασμ ή ελλειματική χαλαρή μτβ 60 a=hstack((a,ey),format='csr') 61 #B,Ν: set of indices 62 B=list(range(n,n+m))#Αν έχω μόνο χαλαρές 63 N=list(range(n)) 64 #Εύρεση (αν χρειάζεται) RREF του Α 65 #Απόσπαση των ισοτικών γραμμών 55
66 if len(mask)!=m: 67 print("computing RREF of A") 68 mask2=np.where(eq==0)[0] #για να παρει μόνο τον πινακα απο το tuple 69 #mask12 = list(set(mask).difference(set(np.arange (len(eq))))) 70 #λιστα με τον δεικτη καθε ισοτητας 71 mask12=list(set(np.arange(len(eq)))-set(mask)) 72 aeq=csr_matrix(a.a[mask12,0:n]) 73 #augmenting aeq with corresponding b elements 74 aeq=hstack((aeq,b.a[mask12]),format='csr') 75 aeq2=matrix(aeq.a).rref() 76 #Δημιούργησε το Β και το Ν 77 B=np.repeat(-1,m)#Αρχικοποίηση του Β 78 #Για κάθε ανισοτικό περιορισμό προσθέτω χαλαρή στο Β στην αντίστοιχη θέση 79 B[mask]=list(range(n,n+len(mask))) 80 B=list(B) 81 for i in range(len(mask12)): 82 B[mask12[i]]=aeq2[1][i] 83 B=list(range(n,n+len(mask))) 84 for i in aeq2[1]: 85 B.append(i) 86 B.sort() 87 N=list(range(n)) 88 N=list(set(N) - set(b)) 89 #ΒΗΜΑ 0: Υπολογισμός Β, Ν, ΑΒ, xb 90 #Ενημέρωση του C με τις χαλαρές μτβ =0 91 if len(mask)!=0: 92 c=sps.vstack((c,np.zeros((len(mask),1))),format='csr' 93 #Υπολογισμός του ΑΒ ή B-1 94 AB=a[:,B] 95 #Για να αποφύγω το warning. Δουλεύει πιο καλά σε csc 96 #Binv = spsl.inv(ab.tocsc()) ή 97 Binv = csr_matrix(inv(ab.a)) 98 xb=binv*b 99 bbinv=binv.a 100 xb=csr_matrix(np.where(np.abs(xb.a)<tol,0.0,xb.a)) 101 #Αν κάποιο xb<0 τότε πήγαινε στην Φάση Ι 102 if any(xb<0): 103 print('entering Phase I...') 104 ph1=true 105 # Φάση Ι 106 #Εισαγωγή τεχνητής μτβ 107 d=-binv*np.ones((m,1))#διάνυσμα συντελεστών του Xn+1 108 # d=csr_matrix(np.where(np.abs(d)<tol,0.0,d)) # ή κατ'ευθείαν: 109 a=hstack((a,d),format='csr') 110 t=np.argmin(xb.a) 111 r=b[t] 112 count=0 113 # ΦΙ Βήμα 0 114 N.append(r)#Βγάζω μια μτβ και 115 B[t]=n+len(mask)#Βάζω την τεχνητή μτλ στην βάση 116 AB=a[:,B] 117 AN=a[:,N] 118 fb=csr_matrix(np.zeros((m,1)))#αρχικοποίηση διανυσμάτων 119 fn=csr_matrix(np.zeros((len(n),1))) 120 fb[t]=1#επειδή είναι se csr matrix container 121 E=csr_matrix(np.eye(m)) 56
122 hl=binv*a[:,r] 123 hl=csr_matrix(np.where(np.abs(hl.a)<tol,0.0,hl.a)) 124 E[:,t]=-hl.A/hl[t].A#-hl/hl[r] 125 E[t,t]=1/hl[t].A 126 E2=E.A 127 Ehl=hl.A 128 E=csr_matrix(np.where(np.abs(E.A)<tol,0.0,E.A)) 129 bb4=binv.a 130 Binv=E*Binv 131 Binv = csr_matrix(inv(ab.a)) #το Ε παραμενει Ι και δεν δουλευει αλλιως 132 bb3=binv.a 133 xb=binv*b 134 xb=csr_matrix(np.where(np.abs(xb.a)<tol,0.0,xb.a)) 135 art=n+len(mask) 136 while True: # ΦΑΣΗ 1 137 count+=1 138 wt=fb.t*binv 139 sn=fn.t-wt*a[:,n] 140 sn=csr_matrix(np.where(np.abs(sn.a)<tol,0.0,sn.a)) 141 #ΒΗΜΑ 1 142 #Checking optimality 143 # sn=csr_matrix(np.allwherewhere(sn.a<0,-sn.a,sn.a)) 144 if all(sn.a[0]>=0): 145 stopped=false 146 print("found Optimal Solution in Phase I!") 147 if xb[b.index(n+len(mask))]!=0.0: 148 print("initial problem is infeasible. Exiting...") 149 stopped=true 150 break#βγες από την ΦΙ 151 #ΒΗΜΑ 2 - Επιλογή εισερχόμενης μεταβλητής 152 t=np.argmin(sn.a)#[0]#min{sj:sj<0 k jen} 153 # t=np.argmin(sn.a[sn.a<0])#[0] 154 # snlist=np.where(sn.a<0)[1] 155 # min1=np.min(sn.a[snlist]) 156 l=np.min(sn.a) 157 l2=np.where(sn.a==l) 158 l3=np.array(n)[l2[1]][0] 159 mmin2=10000000000 160 for i in range(len(n)): 161 if sn[0,i] < mmin2: 162 mmin2=sn[0,i] 163 th2=i 164 l=n[t] 165 #Yπολόγισε hl 166 hl=binv*a[:,l] 167 hl=csr_matrix(np.where(np.abs(hl.a)<tol,0.0,hl.a)) 168 if all(hl.a<=0): 169 #if np.greater_equal(sn[0],np.zeros(n)): 170 print('found Unbounded Solution') 171 stopped=true 172 break 173 #Επιλογή Εξερχόμενης μτβ min{xb/hl: hl>0} 174 # k=np.argmin(xb/hl>=0) 175 # m2=np.where(hl.a>0) 176 # k=np.argmin(xb[m2[0]]/hl[m2[0]]) 177 t1=xb[hl>0]/hl[hl>0] 178 minval = np.min(t1[np.nonzero(t1)]) 179 #min3 = min(i for i in t1[0] if i > 0) 57
180 r=np.where(minval==t1)[1]#[0] 181 if len(r)>1: 182 k=np.min(b[r[0]]) 183 k=b[r[0]] 184 xb2=xb.a 185 hl2=hl.a 186 mmin=100000000000 187 for i in range(0,m): 188 if hl2[i]>0: 189 if xb2[i]/hl2[i]<=mmin: 190 mmin=xb2[i]/hl2[i] 191 th=i 192 rr=r[0] 193 rr=th 194 k=b[th] 195 #ΒΗΜΑ 3 196 B[rr],N[t]=l,k 197 E=csr_matrix(np.eye(m)) 198 E[:,rr]=-hl.A/hl[rr].A#-hl/hl[r] 199 E[rr,rr]=1/hl[rr].A 200 E=csr_matrix(np.where(np.abs(E.A)<tol,0.0,E.A)) 201 Binv=E*Binv 202 xb=binv*b 203 xb=csr_matrix(np.where(np.abs(xb.a)<tol,0.0,xb.a)) 204 if k==art:#βγήκε η τεχν μτβ απο την βαση 205 print('art has gone. Exiting Phase I') 206 N.remove(art) 207 break 208 # Φάση ΙΙ 209 if not ph1: 210 print('no phase I') 211 a=a[:,0:n+len(mask)]#βγάζω την τεχν στήλη απο το τέλος του Α 212 if n+len(mask) in B:#αν ειναι ακόμη μεσα στην βάση η τεχν μτλ 213 print('akoma stin basi') 214 infy=true 215 r=np.where(xb/hl==np.min(xb[hl>0]/hl[hl>0]))[0] 216 t=np.argmin(sn.a)#[0] 217 rr=b.index(art) 218 B[rr]=N[t] 219 N.remove(N[t]) 220 if not stopped: 221 infy=false 222 print('entering Phase II...') 223 else: 224 infy=true 225 count=0 226 while not stopped: 227 #Yπολογισμός των cb και cn 228 cb,cn=c[b],c[n] 229 count+=1 230 #Υπολογισμός του wt 231 wt=cb.t*binv 232 #Υπολογισμός του st 233 st=c.t-wt*a 234 st=csr_matrix(np.where(np.abs(st.a)<tol,0.0,st.a)) 235 sn=cn.t-wt*a[:,n] 236 sn=csr_matrix(np.where(np.abs(sn.a)<tol,0.0,sn.a)) 237 #ΒΗΜΑ 1 238 #Checking optimality 239 # sn=csr_matrix(np.where(sn.a<0,-sn.a,sn.a)) 58
240 if np.all(sn.a>=0): 241 # if np.greater_equal(sn[0],np.zeros(n)): 242 print("found Optimal Solution!") 243 #Υπολογισμός της βέλτιστης τιμής 244 z=cb.t*xb+c0 245 print('z=',z.a) 246 stopped=true 247 continue 248 #ΒΗΜΑ 2 249 t=min(st.a[0,n]) 250 t=np.argmin(st.a[0,n])# O δείκτης του min 251 tt=np.argmin(sn.a[0])# O δείκτης του min 252 z=cb.t*xb+c0 253 l=n[t] 254 mmin=10000000000 255 for i in range(len(n)): 256 if sn[0,i] < mmin: 257 mmin=sn[0,i] 258 th=i 259 l=n[t] 260 l=n[th] 261 #Yπολόγισε hl 262 hl=binv*a[:,l] 263 hl=csr_matrix(np.where(np.abs(hl.a)<tol,0.0,hl.a)) 264 if all(hl.a<=0): 265 #Υπολογισμός της βέλτιστης τιμής 266 z=cb.t*xb 267 print('found Unbounded Solution') 268 stopped=true 269 continue 270 #Επιλογή Εξερχόμενης μτβ 271 min2=np.min(xb[hl>0]/hl[hl>0]) 272 minth2=np.where((xb.a/hl.a==min2) & (hl.a>0))[0][0] 273 minth2=np.where((xb.a/hl.a==np.min(xb[hl>0]/hl[hl>0])) & (hl.a>0))[0][0] 274 r=np.where(xb/hl==np.min(xb[hl>0]/hl[hl>0]))[0] 275 if len(r)!=0: 276 k=b[r[0]] 277 hl2=hl.a 278 xb2=xb.a 279 mmin=100000000000 280 for i in range(0,m): 281 if hl[i]>0: 282 if xb2[i]/hl2[i]<mmin: 283 mmin=xb2[i]/hl2[i] 284 th=i 285 th=minth2 286 r=th 287 k=b[th] 288 #ΒΗΜΑ 3 289 B[th],N[t]=l,k 290 E=csr_matrix(np.eye(m)) 291 E[:,r]=-hl.A/hl[r].A#-hl/hl[r] 292 E[r,r]=1/hl[r].A 293 E=csr_matrix(np.where(np.abs(E.A)<tol,0.0,E.A)) 294 Binv=E*Binv 295 if count%300==0: 296 AB=a[:,B] 297 Binv = csr_matrix(inv(ab.a)) 298 Binv=csr_matrix(np.where(np.abs(Binv.A)<tol,0.0,Binv.A)) 59
299 xb=binv*b 300 xb=csr_matrix(np.where(np.abs(xb.a)<tol,0.0,xb.a)) 301 solutiontime=(time.time() - start_time) 302 if not infy: 303 z=cb.t*xb Λίστα Κώδικα 18. Αλγόριθμος 2 Phase Revised Simplex 60
6 Υπολογιστική μελέτη Για την δοκιμή των αλγορίθμων έχει επιλεγεί από τα προβλήματα που υπάρχουν στα παραρτήματα, μια ομάδα αυτών με το μικρότερο δυνατό μέγεθος. Αποκλείστηκαν προβλήματα με όρια ή εύρος τιμών, καθώς και κάποια προβλήματα με ιδιαιτερότητες στην δομή τους (όπως για παράδειγμα το zed.mps, που περιλαμβάνει δύο αντικειμενικές συναρτήσεις). Η εφαρμογή των μεθόδων κλιμάκωσης έγινε χωρίς προβλήματα παρουσιάζοντας ταχύτητα στην εκτέλεσή τους. Αντίθετα, οι τεχνικές προεπίλυσης είχαν μια αυξητική τάση στον χρόνο εκτέλεσης ανάλογα με το μέγεθος των προβλημάτων. Ωστόσο, για μεγαλύτερα προβλήματα, είναι απαραίτητη η χρήση και η εφαρμογή τους πριν από την εκτέλεση μεθόδων επίλυσης. Και αυτό γιατί τα περισσότερα προβλήματα περιέχουν περιττές πχ γραμμές, γραμμικώς εξαρτημένες, κάτι που οδηγεί σε αδυναμία εύρεσης αντιστρόφου της βασικής μήτρας των συντελεστών και κατ επέκταση και σε αδυναμία εκτέλεσης του αλγορίθμου επίλυσής τους. Στην στήλη όνομα υπάρχει το όνομα κάθε προβλήματος χωρίς την επέκτασή του (.mps). Στην στήλη m φαίνεται ο αριθμός των περιορισμών του προβλήματος και αντίστοιχα στην στήλη n ο αριθμός των μεταβλητών απόφασης. Το χαρακτηριστικό nnz αφορά το πλήθος των μη μηδενικών στοιχείων του πίνακα των περιορισμών. Οι επόμενες τρεις στήλες παρουσιάζουν τα αντίστοιχα στοιχεία του μεγέθους των προβλημάτων μετά την εφαρμογή των μεθόδων προεπίλυσης. Στις επόμενες στήλες δίνεται η μεταβολή (μείωση) του μεγέθους και η ποσοστιαία μεταβολή τους. Στον παρακάτω πίνακα (Πίνακας 1) φαίνονται τα αποτελέσματα εκτέλεσης των μεθόδων προεπίλυσης στην επιλεγμένη ομάδα προβλημάτων σχετικά με την μεταβολή στο αρχικό τους μέγεθος. Ανάλογα με την δομή κάθε αρχείου, παρατηρούνται σαφείς διαφοροποιήσεις στην επίδραση των τεχνικών προεπίλυσης. Έτσι, σε κάποια προβλήματα δεν υπήρξε καμία αλλαγή, ενώ σε κάποια άλλα μειώθηκε κατά πολύ το μέγεθός τους, μέχρι και της τάξης του 60%. Αυτό που δεν παρουσιάζεται στον πίνακα, είναι η μεγαλύτερη επίδραση των τεχνικών σε πολύ μεγαλύτερα προβλήματα που παρατηρήθηκε κατά τις δοκιμές. 61
α/α Όνομα Συλλογή Περιορισμοί Στήλες Διαφορά Διαφορά Διαφορά nnz m' n' nnz' Αρχείου m n Δm Δn % 1 afiro netlib 27 32 83 27 32 83 0 0 0,00% 2 agg netlib 488 163 2410 468 163 2348 20 0-2,57% 3 beaconfd netlib 173 262 3375 120 209 2861 53 53-15,23% 4 bgprtr infeasible 20 34 64 18 32 58 2 2-9,38% 5 blend netlib 74 83 491 71 80 446 3 3-9,16% 6 farm misc 7 12 36 6 10 32 1 2-11,11% 7 farm misc 7 12 36 6 10 32 1 2-11,11% 8 israel netlib 174 142 2269 174 142 2269 0 0 0,00% 9 itest2 infeasible 9 4 17 9 4 17 0 0 0,00% 10 itest6 infeasible 11 8 20 6 2 8 5 6-60,00% 11 kleemin3 misc 3 3 6 3 3 6 0 0 0,00% 12 kleemin4 misc 4 4 10 4 4 10 0 0 0,00% 13 kleemin5 misc 5 5 15 5 5 15 0 0 0,00% 14 kleemin6 misc 6 6 21 6 6 21 0 0 0,00% 15 kleemin7 misc 7 7 28 7 7 28 0 0 0,00% 16 kleemin8 misc 8 8 36 8 8 36 0 0 0,00% 17 klein1 infeasible 54 54 696 54 54 696 0 0 0,00% 18 lotfi netlib 153 308 1078 133 288 809 20 20-24,95% 19 sc105 netlib 105 103 280 104 103 280 1 0 0,00% 20 sc205 netlib 205 203 551 203 202 550 2 1-0,18% 21 sc205-2r-16 stochlp 365 366 990 364 366 990 1 0 0,00% 22 sc205-2r-27 stochlp 607 608 1650 606 608 1650 1 0 0,00% 23 sc205-2r-32 stochlp 717 718 1950 716 718 1950 1 0 0,00% 24 sc205-2r-4 stochlp 101 102 270 100 102 270 1 0 0,00% 25 sc205-2r-8 stochlp 189 190 510 188 190 510 1 0 0,00% 26 sc50a netlib 50 48 130 49 48 130 1 0 0,00% 27 sc50b netlib 50 48 118 48 48 118 2 0 0,00% 28 share1b netlib 117 225 1151 102 210 1026 15 15-10,86% 29 share2b netlib 96 79 694 96 79 694 0 0 0,00% 30 stocfor1 netlib 117 111 447 102 96 367 15 15-17,90% Πίνακας 1 Αποτελέσματα Εφαρμογής Μεθόδων Προεπίλυσης Στον επόμενο πίνακα παρουσιάζονται οι χρόνοι εκτέλεσης των τεχνικών που αναφέρθηκαν σε προηγούμενες ενότητες, του αλγορίθμου Simplex και ο αριθμός των επαναλήψεων που χρειάστηκε με ή χωρίς προεπίλυση. 62
α/α Όνομα Περιορισμοί Στήλες Φόρτωμα Χρόνος Χρόνος Χρόνος Αρ.Επαναλήψεων Αρ.Επαναλήψεων Αρχείου m n Αρχείου Κλιμάκωσης Προεπίλυσης Επίλυσης Χωρίς Προεπίλυση με Προεπίλυση 1 afiro 27 32 0,006999 0,038001776 1,483086348 0,5040324 10 10 2 agg 488 163 0,16001 0,42702508 225,0685785 1,8091035 51 0 3 beaconfd 173 262 0,183012 0,265016079 29,97297812 31,32082 42 39 4 bgprtr 20 34 0,004 0,043000221 0,678405285 0,6670399 0 17 5 blend 74 83 0,011999 0,112004519 10,00959015 9,4278624 91 111 6 farm 7 12 0,003 0,014000654 0,121989727 0,1010056 5 3 7 farm 7 12 0,004998 0,014000654 0,121989727 0,1010056 5 3 8 israel 174 142 0,086008 0,189994335 64,59404039 19,704614 275 150 9 itest2 9 4 0,002001 0,01100111 0,207010269 0,072005 0 0 10 itest6 11 8 0,003001 0,014000654 0,15900898 0,0550048 0 0 11 kleemin3 3 3 0,003 0,007000446 0,059004307 0,0400021 8 2 12 kleemin4 4 4 0,002 0,008997679 0,074005127 0,040004 16 2 13 kleemin5 5 5 0,002 0,009000778 0,100004196 0,0490031 32 2 14 kleemin6 6 6 0,003 0,016000986 0,177009821 0,0440021 64 2 15 kleemin7 7 7 0,003001 0,012998343 0,147009611 0,0820053 128 2 16 kleemin8 8 8 0,004 0,015001059 0,215011597 0,050004 256 2 17 klein1 54 54 0,014 0,103008509 6,000358105 3,218169 0 0 18 lotfi 153 308 0,042003 0,283016443 54,50385404 47,291964 144 254 19 sc105 105 103 0,011001 0,247014284 30,64775372 8,231472 64 68 20 sc205 205 203 0,027001 0,406023741 140,5108011 67,448986 165 155 21 sc205-2r-16 365 366 0,042001 0,443023682 265,5880902 53,137043 107 107 22 sc205-2r-27 607 608 0,095004 0,708057165 765,4497273 161,0382 78 72 23 sc205-2r-32 717 718 0,132006 1,525087833 1786,72017 453,52447 203 203 24 sc205-2r-4 101 102 0,029001 0,233674049 34,04786968 6,3943682 35 35 25 sc205-2r-8 189 190 0,031001 0,379020691 120,3537464 21,140737 59 59 26 sc50a 50 48 0,015002 0,113006115 8,249606848 3,3291926 33 33 27 sc50b 50 48 0,014 0,100008011 7,889451504 3,8532214 38 38 28 share1b 117 225 0,105005 0,212009907 30,59437418 34,656513 146 214 29 share2b 96 79 0,076004 0,104006052 17,9236474 6,2493594 98 68 30 stocfor1 117 111 0,079004 0,147009134 32,48967862 8,5594914 59 65 Πίνακας 2 Χρόνοι Εφαρμογής Μεθόδων Προεπίλυσης & Επαναλήψεις Αλγορίθμου Όπως φαίνεται και από τον πίνακα, σε ορισμένα από τα προβλήματα δεν υπάρχει ουσιαστική διαφοροποίηση του μεγέθους τους, με αντίστοιχη μείωση του χρόνου εκτέλεσης. Σε μερικά όμως προβλήματα, κυρίως σε αυτά με μεγαλύτερο μέγεθος, υπάρχει αισθητή μείωση των δεδομένων, κάτι που οδηγεί σε μικρότερες απαιτήσεις σε αποθηκευτικό χώρο αλλά και σε ταχύτερη επίλυσή τους. Στην πλειονότητά τους (εκτός από τρία) η επίλυση των προβλημάτων πραγματοποιήθηκε με την εφαρμογή του αλγορίθμου simplex σε λιγότερα βήματα επαναλήψεις μετά την χρήση των μεθόδων προεπίλυσης. Χαρακτηριστικά, για το πρόβλημα kleemin8, χρειάστηκαν 2 αντί για 256 επαναλήψεις για την επίλυσή του. Όλες οι δοκιμές έγιναν σε Η/Υ Intel Core 2 Duo T7250 2GHz, 3GB DDR2 667ΜHz, σε Windows 10 32bit. Όλοι οι κώδικες και τα αρχεία δεδομένων που χρησιμοποιήθηκαν είναι διαθέσιμα online. 5 5 https://1drv.ms/u/s!ak3h3jpxwzxum1xw3dwpy6qjfmlb 63
7 Συμπεράσματα Από τα κυριότερα προβλήματα στην επίλυση των δοκιμαστικών ΓΠ είναι το μεγάλο τους μέγεθος, η αραιή μορφή των δεδομένων αλλά και η ίδια η δομή τους. Στοιχεία τα οποία συντελούν στην δυσκολία επίλυσής τους με τους γνωστούς αλγόριθμους. Είναι επομένως αναγκαία επιλογή η εφαρμογή τέτοιων μεθόδων προεπίλυσης. Ένα από τα κυριότερα συμπεράσματα που προέκυψαν μέσα από την συγγραφή της εργασίας, ήταν και η ανάγκη εφαρμογής των μεθόδων που περιγράφησαν σε προηγούμενα κεφάλαια. Χωρίς αυτές, η επίλυση μεγάλης κλίμακας προβλημάτων παραμένει σχεδόν αδύνατη. Από την άλλη, οι μέθοδοι κλιμάκωσης βοήθησαν στην αποφυγή σφαλμάτων υπολογισμών κατά την διάρκεια πολλαπλών εφαρμογών των μεθόδων επίλυσης. Κατά την υλοποίηση των αλγορίθμων, σχετικά μεγάλη χρονική διάρκεια είχε η εύρεση της αρχικής αντιστρόφου της βάσης με την μέθοδο Reduced Row Echelon Form of the Inverse. Αφήνεται η βελτίωση του συγκεκριμένου κομματιού για μελέτη σε επόμενη ερευνητική εργασία. Ορισμένοι από τους υπολογισμούς θα μπορούσαν να δώσουν καλύτερους χρόνους με μια υλοποίηση στραμμένη στον παράλληλο προγραμματισμό πολυπύρηνων συστημάτων ή GPU s. Αναφορικά με θέματα σχετικά με την υλοποίηση των αλγορίθμων στην γλώσσα προγραμματισμού python, προέκυψαν αρκετά στοιχεία για την χρήση της σε επιστημονικούς υπολογισμούς και την επίλυση προβλημάτων μεγάλης κλίμακας. Ένα από τα πλεονεκτήματα που έχει η συγκεκριμένη υλοποίηση έχει να κάνει με την ποικιλία εργαλείων της γλώσσας, με την μορφή έτοιμων βιβλιοθηκών όπως είναι αυτό της διαχείρισης αραιών μητρών (scipy.sparse). Η ίδια η φύση της γλώσσας διευκόλυνε κατά πολύ την διαδικασία συγγραφής κώδικα. Οι κυριότερες δυσκολίες και τα προβλήματα παρουσιάστηκαν στην συνεργασία αυτών των έτοιμων πακέτων μεταξύ τους, αφού ορισμένα στοιχεία των προβλημάτων απεικονίζονταν με την μορφή μητρών (scipy matrices) και άλλα με την μορφή πινάκων (numpy arrays) ενώ κάποια άλλα με βασικά δομικά στοιχεία της python όπως λίστες, σύνολα (sets) και πλειάδες (tuples). 64
Βιβλιογραφία [1]. Bazaraa, M., Jarvis, J., Sherali, H. (2005). Linear Programming and Network Flows, 3rd edition, Wiley-Interscience [2]. Bland Robert G., Goldfarb Donald, Todd Michael J., (1981) The Ellipsoid Method: A Survey. Operations Research 29(6):1039-1091 [3]. Bressert Eli (2013) Numpy and Scipy - O Reilly [4]. Dantzig, B.G., (1949), Programming in a linear structure,econometrica,vol.17, pp.73-74 [5]. Davis Timothy A. (2006) Direct Methods for Sparse Linear Systems CIAM [6]. Downey Allen, Elkner Jeffrey, Meyers Chris (2008) How to Think Like a Computer Scientist - Learning with Python, Green Tea Press [7]. Erling D. Andersen, Andersen Knud D. (1995) Presolving in linear programming Mathematical Programming 71 221-245 [8]. Erling D. Andersen (1995): Finding all linearly dependent rows in large-scale linear programming, Optimization Methods and Software, 6:3, 219-227 [9]. Hillier and Lieberman (2001). Introduction to Operations Research (7th ed.), McGraw-Hill. [10]. Idris Ivan (2014) Learning NumPy Array Packt Publishing [11]. Gondzio Jacek (1995) HOPDM - A fast LP solver based on a primal-dual interior point method European Journal of Operational Research 85 221 225 [12]. Khachiyan L.G., (1980) Polynomial algorithms in linear programming, USSR Computational Mathematics and Mathematical Physics, Volume 20, Issue 1, P53-72 [13]. Karmarkar Narendra (1984). "A New Polynomial Time Algorithm for Linear Programming", Combinatorica, Vol 4, nr. 4, p. 373 395 [14]. Langtangen Hans Petter (2009), Python Scripting for Computational Science (Texts in Computational Science and Engineering) 3rd Edition, Springer [15]. Langtangen Hans Petter (2014), A Primer on Scientific Programming with Python (Texts in Computational Science and Engineering) 4th ed. 2014 Edition, Springer [16]. Papadimitriou, H.C., Steiglitz, K. (1982). Combinatorial Optimization: Algorithms and Complexity, Prentice-Hall, Inc., Englewood Cliffs, N.J. 65
[17]. Rojas Sergio J. G. Christensen Erik A, Francisco J. Blanco-Silva (2015 ) Learning SciPy for Numerical and Scientific Computing Second Edition, Packt Publishing [18]. Pissanetzky Sergio (1984) Sparse Matrix Technology Acad. Press [19]. Saad Yousef (2003) Iterative Methods for Sparse Linear Systems Second Edition Society for Industrial and Applied Mathematics [20]. F. J. Blanco-Silva (2013) Learning SciPy for Numerical and Scientific Computing Packt Publishing [21]. Stewart John M. (2014) Python for Scientists, Cambridge University Press; 1 edition [22]. Summerfield Mark (2009), Programming in Python 3, 2nd Edition, Addison- Wesley [23]. Swietanowski Artur (1995) A modular pre solve procedure for large scale Linear Programming IIASA [24]. Tomlin J.A. and J.S. Welch (1983) Formal optimization of programming problems mathematical programming 27 232-240 [25]. Tomlin J.A. and J.S. Welch (1986), Finding duplicate rows in a linear programming model, Volume 5, Operations Research Letters [26]. Παπαρρίζος Κωνσταντίνος (2009) Γραμμικός Προγραμματισμός: Μια προσέγγιση με MATLAB Εκδόσεις Ζυγός 66
Παράρτημα A - Εγκατάσταση της Python A.1 Εισαγωγή Η γλώσσα προγραμματισμού python είναι μια γλώσσα σεναρίων (scripting) που βασίζεται στην χρήση του κατάλληλου διερμηνευτή (interpreter). Ανάλογα με το περιβάλλον εργασίας που χρησιμοποιείται, απαιτείται η παρουσία της αντίστοιχης έκδοσης διερμηνευτή. Έτσι, υπάρχουν εκδόσεις της python κατάλληλες για Windows, Linux και OS X, αλλά και ανάλογα με την αρχιτεκτονική του λειτουργικού συστήματος (32 ή 64 bit). Αναφορικά με την έκδοση της γλώσσας, αυτή έχει δύο βασικές παραλλαγές, την 2.x και την 3.x, όπου και εμφανίζονται αρκετές διαφοροποιήσεις και αλλαγές. Στις επόμενες ενότητες περιγράφεται η χρήση της έκδοσης 3.x στα 64bit. Η διαδικασία εγκατάστασης είναι, ανάλογα με το λειτουργικό σύστημα, απλή και γίνεται όπως για κάθε άλλο πρόγραμμα που εγκαθίσταται στον υπολογιστή. Έτσι, σε ένα Linux σύστημα, χρησιμοποιείται το αντίστοιχο πρόγραμμα διαχείρισης πακέτων, γραφικά ή μέσω της γραμμής εντολών ενός τερματικού, ενώ σε υπολογιστές windows (σε όλες τις εκδόσεις) γίνεται χρήση ενός κατάλληλου προγράμματος εγκατάστασης σε γραφικό περιβάλλον (installer). Επειδή οι εκδόσεις 2.x και 3.x έχουν αρκετές διαφορές και η χρήση πακέτων δεν είναι πάντα εφικτή και στις δύο (υπάρχουν πακέτα που διατίθενται για την μία και όχι για την άλλη έκδοση της γλώσσας), είναι δυνατόν να εγκατασταθούν και οι δύο στο ίδιο σύστημα. Μάλιστα, μέσα από ένα ολοκληρωμένο γραφικό περιβάλλον ανάπτυξης (IDE - GUI) μπορεί να γίνει χρήση του κατάλληλου, κάθε φορά, διερμηνευτή της γλώσσας, ανάλογα με τις ανάγκες του χρήστη. Είναι δυνατή επομένως η δημιουργία σεναρίων (scripts) που θα υλοποιούνται και στις δύο εκδόσεις της γλώσσας. Κάτι που προκαλεί συχνά σύγχυση, είναι αυτή η αυτόνομη διαχείριση πακέτων από την γλώσσα, που ταυτόχρονα όμως, δίνει και την ελευθερία επιλογών στο γράψιμο κώδικα. Έτσι, άλλα πακέτα μπορεί να έχει η μία έκδοση και άλλα η άλλη. Στις επόμενες παραγράφους περιγράφεται η εγκατάσταση και διαχείριση όλων των βασικών αλλά και των απαραίτητων στοιχείων για την κωδικοποίηση σε python προβλημάτων επιστημονικών υπολογισμών (scientific computation). 67
A.2 Επιλέγοντας περιβάλλον εργασίας Η γλώσσα είναι διαθέσιμη σε ένα μεγάλο και διαφορετικό στο είδος τους αριθμό εργαλείων ανάπτυξης κώδικα που δίνουν την δυνατότητα για εκτέλεση μεμονωμένων εντολών με αλληλεπιδραστικό (interactive) χαρακτήρα ή την σύνταξη ολοκληρωμένων προγραμμάτων. Ο τρόπος χρήσης της καθορίζει και σε μεγάλο βαθμό το είδος της απαιτούμενης, κάθε φορά, εγκατάστασης. Έτσι, είναι διαθέσιμα μια σειρά από εργαλεία που, ανάλογα με τον επιθυμητό τρόπο εργασίας, μπορούν να εγκατασταθούν σε οποιοδήποτε υπολογιστικό σύστημα. Ένας ακόμα παράγοντας που προσδιορίζει την μορφή των εργαλείων που θα χρησιμοποιηθούν, είναι και το είδος της εργασίας για την οποία προορίζεται. Από την δοκιμή μεμονωμένων εντολών (notebooks), μέχρι την συγγραφή σεναρίων σε πολυχρηστικά περιβάλλοντα (github, bitbucket), την δημιουργία εφαρμογών ιστού (web apps, Django) ή την ανάλυση επιστημονικών δεδομένων (scipy), την γραφική απεικόνιση (matplot lib) και διαχείριση εξωτερικών δεδομένων (pandas) αλλά και την χρήση έτοιμων πακέτων ή δημιουργία και διάθεση (deployment) νέων, το περιβάλλον προγραμματισμού μπορεί να διαφοροποιηθεί κατά πολύ. Στις επόμενες ενότητες περιγράφεται η βασική εγκατάσταση και λειτουργία της γλώσσας, μέσα από εικόνες και πολύ απλά παραδείγματα, μαζί με την προσθήκη μερικών επιπρόσθετων πακέτων απαραίτητων για την επίλυση μαθηματικών προβλημάτων. Ωστόσο, για την εκμάθηση της γλώσσας είναι δυνατή η χρήση ακόμα και ορισμένων διαδικτυακών (on line) διερμηνευτών. Σ αυτή την περίπτωση, δεν χρειάζεται καμία προσθήκη ή τροποποίηση του συστήματος του χρήστη, το IDE είναι εκεί, άμεσα διαθέσιμο και έτοιμο για χρήση. Η συγγραφή κώδικα γίνεται άμεσα και η εκτέλεσή του δεν προαπαιτεί απολύτως τίποτα. Την χρονική στιγμή που γράφονταν αυτές οι γραμμές, τα πλέον ενδιαφέροντα, αλλά όχι τα μοναδικά, εργαλεία online IDE, είναι με σειρά προτίμησης του γράφοντα και ανάλογα με τα ενδιαφέροντα του χρήστη τα πιο κάτω: 1. Sourcelair 6. 2. Trinket.io 7. Έτοιμο, με δυνατότητα να χρησιμοποιηθούν άμεσα και τα πακέτα numpy και scipy 6 http://www.sourcelair.com/ 7 https://trinket.io/python 68
3. Ide one 8 4. Python fiddle 9 5. Sculp 10. Το ενδιαφέρον με το συγκεκριμένο εργαλείο έχει να κάνει με την δυνατότητά του να ενσωματωθεί εύκολα σε οποιαδήποτε ιστοσελίδα. Χαρακτηριστικά αναφέρεται η παρακάτω διεύθυνση http://bit.ly/1nwjxbh όπου ενσωματώθηκε σε άρθρο του Joomla 3.x ένας απλός αλλά πλήρους λειτουργικότητας διερμηνευτής της γλώσσας. A.3 Εγκατάσταση A.3.1 Ο διερμηνευτής Η εγκατάσταση της γλώσσας μπορεί να γίνει με διαφορετικούς τρόπους ανάλογα με το λειτουργικό σύστημα που χρησιμοποιείται. Στην συνέχεια περιγράφεται η διαδικασία για κάθε ένα. A.3.1.1 Windows (όλες οι εκδόσεις) Κανένα σύστημα με windows (οποιαδήποτε έκδοση, από XP μέχρι IoT Core) δεν έρχεται με προ εγκατεστημένη την python, κάτι που οφείλεται και στην γενικότερη φιλοσοφία υποστήριξης ανοιχτού κώδικα εργαλείων ανάπτυξης λογισμικού της κατασκευάστριας εταιρείας και που συναντάται και σε περιπτώσεις άλλων γλωσσών όπως Ruby, perl, κά. Αυτό το γεγονός δεν αποτελεί ιδιαίτερο πρόβλημα για το «στήσιμο» της γλώσσας σε τέτοια περιβάλλοντα, ωστόσο περιπλέκει την κατάσταση όταν θα χρειαστεί να γίνει η διάθεση (deployment) μιας εμπορικά διαθέσιμης εφαρμογής για τοπική χρήση (stand alone εφαρμογές) και όχι ίσως κάτω από κάποιον web server ή στο σύννεφο. Και σε αυτές όμως τις περιπτώσεις, η ιδιαίτερα μεγάλη open source κοινότητα και φίλοι της python, διαθέτουν πακέτα (όπως το py2exe) που παράγουν το απαραίτητο byte code μορφής πρόγραμμα προς διανομή. Αναφορικά δε με την χρήση της γλώσσας για την εκτέλεση σεναρίων σε δικτυακές εφαρμογές, η εγκατάστασή της γίνεται εύκολα και σε όλα τα συστήματα 8 https://ideone.com 9 http://pythonfiddle.com 10 http://www.skulpt.org 69
εξυπηρετητή ιστού (web server). Ένας σύντομος και περιεκτικός οδηγός (tutorial) που περιγράφει την χρήση της γλώσσας σε web server Apache μπορεί να βρεθεί εδώ URL Για να γίνει η εγκατάσταση (τοπικά) σε ένα μηχάνημα με windows, το μόνο που χρειάζεται είναι να «κατέβει» το αρχείο εγκατάστασης από την διεύθυνση https://www.python.org/ Με την εκτέλεση του εγκαταστάτη (installer) επιλέγεται η θέση στον δίσκο, ποιοι χρήστες θα έχουν πρόσβαση στον διερμηνευτή της γλώσσας και το αν θα ενημερωθεί η μεταβλητή συστήματος (PATH) για την διαδρομή όπου θα βρίσκονται τα στοιχεία της γλώσσας, ώστε αυτή να μπορεί να εκτελεστεί από οπουδήποτε στην γραμμή εντολών ενός τερματικού. Στο επόμενο βήμα επιλέγουμε αν θα εγκατασταθούν και μερικά ακόμη πακέτα 70
Μετά και τις επόμενες επιλογές ξεκινά η εγκατάσταση. Η ολοκλήρωση της διαδικασίας δημιουργεί μια ομάδα εικονιδίων εφαρμογών 71
στην γραμμή έναρξης, απ όπου είναι δυνατή η εκκίνηση του περιβάλλοντος εργασίας που μπορεί να έχει τις εξής μορφές: Α) Γραμμή εντολών i) Αλληλεπιδραστικά Με τον συνδυασμό πλήκτρων win+r, γράφουμε CMD και ανοίγουμε την οθόνη γραμμής εντολών. Για να ξεκινήσει το περιβάλλον της python (κέλυφος) απλά γράφουμε python και στο σήμα >>> μπορούμε να πληκτρολογήσουμε εντολές σε Python. Με την εντολή exit() βγαίνουμε από το κέλυφος της python. Αν εμφανιστεί κάποιο μήνυμα όπως το πιο κάτω Θα πρέπει να γίνει ενημέρωση της μεταβλητής path με την διαδρομή όπου βρίσκεται εγκατεστημένη η Python (πχ c:\>python27\) 72
ii) Εκτέλεση σεναρίων Σε επόμενες ενότητες θα γίνει η περιγραφή των τρόπων με τους οποίους μπορεί να γραφεί ένα ολοκληρωμένο πρόγραμμα σε python. Αυτά βρίσκονται σε αρχεία αμορφοποίητου κειμένου (ASCII) με την κατάληξη.py. Για παράδειγμα, φτιάχνουμε στο c: ένα φάκελο python examples και εκεί δημιουργούμε ένα αρχείο κειμένου από το σημειωματάριο που θα περιέχει μια πολύ απλή εντολή print( Hello World ) και αποθηκεύουμε το αρχείο ως hello.py. Για να εκτελεστεί ένα τέτοιο πρόγραμμα κάνουμε τα παρακάτω. Στον φάκελο όπου βρίσκεται το αρχείο.py κάνουμε δεξί κλικ + shift και επιλέγουμε και πληκτρολογούμε python hello.py. Το αποτέλεσμα της εκτέλεσης του προγράμματος φαίνεται στην πιο κάτω εικόνα. 73
Β) Γραφικό περιβάλλον (IDLE) Και οι δύο προηγούμενοι τρόποι εργασίας με την python συμπεριλαμβάνονται σε ένα γραφικό περιβάλλον εργασίας που εγκαθίσταται μαζί με τον διερμηνευτή της γλώσσας. Από το μενού έναρξης επιλέγουμε Python IDLE και ανοίγει το το επόμενο παράθυρο. Στην συνέχεια, μπορούμε να δουλέψουμε ως εξής: i) Αλληλεπιδραστικά Όπως φαίνεται στην πιο πάνω εικόνα, στο σήμα προτροπής της python (>>>), μπορούμε να πληκτρολογήσουμε εντολές και να δούμε άμεσα τα αποτελέσματά τους. ii) Εκτέλεση σεναρίων Από το μενού file επιλέγουμε New File, γράφουμε το πρόγραμμά μας 74
και επιλέγουμε Run/Run Module. To αποτέλεσμα της εκτέλεσης φαίνεται στο παράθυρο του IDLE: A.3.1.2 Linux (κάθε διανομή) Σχεδόν σε κάθε διανομή Linux υπάρχει ήδη εγκατεστημένη η python (τουλάχιστον η έκδοση 2.x). Για να ελέγξουμε αν είναι εγκατεστημένη, ανοίγουμε ένα τερματικό και γράφουμε $python ή python3 Ή εναλλακτικά, $ python --version Για να μπούμε στο κέλυφος (shell) της python Αν εμφανιστεί κάποιο μήνυμα σφάλματος τότε θα πρέπει να γίνει εγκατάσταση με έναν από τους παρακάτω τρόπους i) Από την γραμμή εντολών Ανοίγουμε ένα τερματικό και γράφουμε για διανομές τύπου Debian (Ubuntu, mint κά): sudo apt-get install python για διανομές που βασίζονται σε Red Hat Package Manager (RPM) όπως opensuse κλπ : http://bit.ly/1x0vvn9 ii) Από τον διαχειριστή πακέτων Από μια διανομή Linux Mint είναι η επόμενη εικόνα του Διαχειριστή Πακέτων A.4 Επιλέγοντας IDE Στις προηγούμενες ενότητες έγινε περιγραφή της διαδικασίας βασικής εγκατάστασης της γλώσσας. Αυτό αρκεί για να μπορέσει κάποιος να κάνει χρήση της 75
Python.ωστόσο, υπάρχουν διαθέσιμα, τόσο ανοιχτού κώδικα όσο και εμπορικά εργαλεία, που σκοπό έχουν την αύξηση της παραγωγικότητας, την ευκολία και την καλύτερη οργάνωση της εργασίας με την Python. Τα ολοκληρωμένα περιβάλλοντα ανάπτυξης λογισμικού που είναι διαθέσιμα, μπορούν να καλύψουν τις διαφορετικές ανάγκες του προγραμματιστή, έχοντας το καθένα την δική του φιλοσοφία, τις δικές του ιδιαιτερότητες και τα δικά του κάθε φορά εργαλεία, όπως, debugger, profiler, επιλογή interpreter, διαχείριση πακέτων κλπ. Τα πιο σημαντικά από αυτά, που υπάρχουν και είναι ελέυθερα διαθέσιμα, είτε για προσωπική είτε για εκπαιδευτική χρήση, είναι τα παρακάτω. Α) Enthough Canopy 11 Είναι ένα εμπορικό πακέτο που περιλαμβάνει εκτός από το βασικό περιβάλλον (editor, debugger) και επιπλέον επιμέρους εργαλεία. Είναι διαθέσιμο για αγορά αλλά και δωρεάν στην έκδοση «κοινότητας» (community). Διατίθεται και ως πλήρες εκπαιδευτικό πακέτο, αποκλειστικά για εκπαιδευτικά ιδρύματα (για μαθητές, φοιτητές και καθηγητές) με απλή εγγραφή, η οποία δίνει πρόσβαση και σε μια πολύ αξιόλογη σειρά βίντεο μαθημάτων πάνω σε θέματα σχετικά με τα προϊόντα της εταιρείας και την χρήση τους, αλλά και για πολλά στοιχεία της γλώσσας python. Η εκπαιδευτική έκδοση περιλαμβάνει εκτός από την ετήσια δωρεάν πρόσβαση στα online tutorials, την πλήρη έκδοση του πακέτου σε δύο μορφές. Την σύντομη που περιέχει ένα μικρό σχετικά αριθμό βασικών πακέτων και την πλήρη που ενσωματώνει όλα τα διαθέσιμα πακέτα. Το πρόγραμμα εγκατάστασης που μπορεί να επιλέξει κάποιος έχει να κάνει με την αρχιτεκτονική του συστήματος (32 ή 64 bit) και την έκδοση της γλώσσας (2.x ή 3.x). Στο πακέτο περιλαμβάνεται και ο διερμηνευτής, οπότε δεν χρειάζεται προηγουμένως να εγκατασταθεί τίποτα άλλο. Στην εικόνα που ακολουθεί φαίνεται το περιβάλλον εργασίας. 11 https://www.enthought.com/products/canopy/ 76
Β) Anaconda Spyder 12 Το πακέτο περιλαμβάνει μια συλλογή προγραμμάτων, που εκτός από το βασικό πρόγραμμα που ονομάζεται spyder (Scientific Python Development Environment), περιέχει και εξειδικευμένα εργαλεία για την οπτικοποίηση δεδομένων, την εργασία σε δωρεάν (δημόσια) ή επί πληρωμή (ιδιωτικά) bit buckets, αλλά και την χρήση του Ipython, ενός περιβάλλοντος προγραμματισμού σε βιβλία (notebooks) σε web περιβάλλον. Το πακέτο είναι ελεύθερα διαθέσιμο, σε Linux και Windows, 32 ή 64 bit, με δικό του διερμηνευτή (2.x ή 3.x). ακολουθεί εικόνα από το περιβάλλον του spyder. Γ) JetBrains PyCharm 13 Με την έκδοση community είναι ελεύθερα διαθέσιμο το συγκεκριμένο εμπορικό προϊόν, το οποίο δεν περιλαμβάνει interpreter και για αυτό μπορεί ο χρήστης να επιλέξει κάθε φορά όποιον θέλει. Αυτό επιτρέπει, σε ένα project με πολλά αρχεία python, να επιλέγεται κάθε φορά και διαφορετική έκδοση της γλώσσας, αλλά και διαφορετικός διερμηνευτής (python native ή anaconda πχ). Το δυνατό σημείο του PyCharm είναι ο ολοκληρωμένος και εύχρηστος debugger του. Άλλα αξιόλογα περιβάλλοντα είναι και τα Pydev για το Eclipse, Eric (από το μέλος των Monty Python, Eric Idle) κά. 12 https://www.continuum.io/downloads 13 https://www.jetbrains.com/pycharm/ 77
Συνοψίζοντας, και πέρα από το γεγονός ότι για την συγγραφή κώδικα δεν απαιτείται ούτε καν ένας απλός κειμενογράφος (λειτουργόντας αλληλεπιδραστικά στο ίδιο το κέλυφος της python), υπάρχει μια πληθώρα λύσεων σε ολοκληρωμένα περιβάλλοντα ανάπτυξης κώδικα. Οι λόγοι για να εγκατασταθεί ένα τέτοιο περιβάλλον είναι πολλοί: 1. Πολλαπλά παράθυρα ή καρτέλες 2. Αυτόματη συμπλήρωση κώδικα (code completion) 3. Χρωματική απόδοση συντακτικού (color syntax) 4. Αυτόματη δημιουργία και εύκολη διαχείριση εσοχών (auto indentation) 5. Δημιουργία σημείων διακοπής (breakpoints) 6. Προβολή τιμών μεταβλητών, πινάκων κλπ (variable browser watcher) 7. Ενσωματωμένο τερματικό (ά) και κονσόλας λειτουργικού 8. Παροχή άμεσης βοήθειας για το συντακτικό (tooltips) 9. Εντοπισμός λαθών (debugger) 10. Αναλυτής κώδικα (profiler analyzer) 11. Περιηγητής αρχείων και συναρτήσεων βιβλιοθηκών (file class/function browser) 12. Πλήρης συντάκτης (editor) 13. Διαχείριση πρόσθετων πακέτων (plugins) 14. Επιλογή εναλλακτικών στοιχείων προβολής κύριας οθόνης 15. Διαμόρφωση του περιβάλλοντος εργασίας σύμφωνα με τις ανάγκες του χρήστη 16. Ελεύθερα, ανοικτού κώδικα προγράμματα (free open source) 17. Ενσωμάτωση γραφικών απεικονίσεων (integrated plotting) 18. Παροχή βοήθειας A.5 Εγκατάσταση πακέτων 78
Ο τρόπος με τον οποίο έχει εγκατασταθεί η γλώσσα καθορίζει και τον τρόπο εγκατάστασης ή ενημέρωσης πακέτων που είναι διαθέσιμα για χρήση. Στις επόμενες παραγράφους περιγράφεται η διαδικασία εγκατάστασης των πακέτων Numpy και Scipy. Α) Python Package Index (pip) Το συγκεκριμένο εργαλείο εγκαθίσταται με την βασική εγκατάσταση της γλώσσας. Το pip είναι πρόγραμμα που τρέχει στην γραμμή εντολών και δέχεται διάφορες παραμέτρους. Η εντολή $pip εμφανίζει την λίστα των παραμέτρων της Με την εντολή $pip list εμφανίζονται όλα τα διαθέσιμα πακέτα Για την εμφάνιση λεπτομερειών σε σχέση με κάποιο πακέτο γράφουμε $pip show numpy Ενώ, για την εγκατάσταση ενός πακέτου αρκεί η εντολή $pip install numpy Β) Spyder conda Το εργαλείο διαχείρισης πακέτων conda, έρχεται με την εγκατάσταση του spyder. Λειτουργεί μα παρόμοιο τρόπο με το pip Γ) μέσω του IDE Σε περιβάλλοντα όπως το Canopy η διαχείριση των πακέτων γίνεται εύκολα και μέσω του ίδιου του προγράμματος, όπως φαίνεται και στην πιο κάτω εικόνα Δ) σε Linux Η εγκατάσταση πακέτων μπορεί να γίνει από τον διαχειριστή πακέτων του ίδιου του λειτουργικού συστήματος ή από την γραμμή εντολών όπως παρακάτω $sudo apt-get install python_numpy python_scipy 79
Η πιο πάνω εντολή έχει ως αποτέλεσμα την εγκατάσταση των πακέτων Numpy και Scipy. Ε) Σε Windows Σε περιβάλλοντα με Windows είναι προτιμότερη και ασφαλέστερη η χρήση ενός IDE που θα περιλαμβάνει όλες εκείνες τις βιβλιοθήκες που είναι απαραίτητες (όπως το spyder ή το canopy) ή ένα γραφικό περιβάλλον εγκατάστασης του πακέτου. Για τα Numpy και Scipy που είναι απαραίτητα για κωδικοποίηση επιστημονικών υπολογισμών, οι installers βρίσκονται στις πιο κάτω διευθύνσεις http://sourceforge.net/projects/scipy/files/scipy/0.16.1/ http://sourceforge.net/projects/numpy/files/numpy/1.10.4/ 80
Παράρτημα B - Πληροφορίες MPS αρχείων Α) Netlib: Name Equations Variables Nonzeros Solution 25fv47 821 1571 11127 5501,85 80bau3b 2262 9799 29063 987224,19 adlittle 56 97 465 225494,96 afiro 27 32 88-464,75 agg 488 163 2541-35991770,00 agg2 516 302 4515-20239250,00 agg3 516 302 4531 10312116,00 bandm 305 472 2659-158,63 beaconfd 173 262 3476 33592,49 blend 74 83 521 0,00 bnl1 643 1175 6129 1977,63 bnl2 2324 3489 16124 1811,24 boeing1 351 384 3865-901,32 boeing2 166 143 1339-872,87 bore3d 233 315 1525 1373,08 brandy 220 249 2150 1518,51 capri 271 353 1786 2690,01 cycle 1903 2857 21322-5,23 czprob 929 3523 14173 2185196,70 d2q06c 2171 5167 35674 122784,21 d6cube 415 6184 43888 315,49 degen2 444 534 4449-1435,18 degen3 1503 1818 26230-987,29 dfl001 6071 12230 41873 0,00 e226 223 282 2767-18,75 etamacro 400 688 2489-755,72 fffff800 524 854 6235 555679,56 finnis 497 614 2714 172791,07 fit1d 24 1026 14430-9146,38 fit1p 627 1677 10894 9146,38 fit2d 25 10500 138018-68464,29 fit2p 3000 13525 60784 68464,29 forplan 70 83 38 ganges 1309 1681 7021-109585,74 gfrd-pnc 616 1092 3467 0,00 greenbea 2392 5405 31499-72555250,00 greenbeb 2392 5405 31499-4302260,00 grow15 300 645 5665-106870900,00 grow22 440 946 8318-160834300,00 grow7 140 301 2633-47787810,00 israel 174 142 2358-896644,82 kb2 43 41 291-1749,90 lotfi 153 308 1086-25,26 maros 846 1443 10006-58063,74 maros-r7 3136 9408 151120 1497185,17 modszk1 687 1620 4158 320,62 nesm 662 2923 13988 14076034,00 perold 625 1376 6026-9380,76 pilot 1441 3652 43220-557,49 pilot4 410 1000 5145-2581,14 pilot87 2030 4883 73804 301,71 pilot-ja 940 1988 14706-6113,14 pilotnov 975 2172 13129-4497,28 pilot-we 722 2789 9218-2720108,00 qap08 912 1632 8304 203,50 qap12 3192 8856 44244 qap15 6330 22275 110700 81
recipe 91 180 752-266,62 sc105 105 103 281-52,20 sc205 205 203 552-52,20 sc50a 50 48 131-64,58 sc50b 50 48 119-70,00 scagr25 471 500 2029-14753430,00 scagr7 129 140 553-2331390,00 scfxm1 330 457 2612 18416,76 scfxm2 660 914 5229 36660,26 scfxm3 990 1371 7846 54901,25 scorpion 388 358 1708 1878,12 scrs8 490 1169 4029 904,30 scsd1 77 760 3148 8,67 scsd6 147 1350 5666 50,50 scsd8 397 2750 11334 905,00 sctap1 300 480 2052 1412,25 sctap2 1090 1880 8124 1724,81 sctap3 1480 2480 10734 1424,00 seba 515 1028 4874 13697,40 share1b 117 225 1182-76589,32 share2b 96 79 730-415,73 shell 536 1775 4900 1208825300,00 ship04l 402 2118 8450 1793324,54 ship04s 402 1458 5810 1798714,70 ship08l 778 4283 17085 1909055,21 ship08s 778 2387 9501 1920098,21 ship12l 1151 5427 21597 1470187,92 ship12s 1151 2763 10941 1489236,13 sierra 1227 2036 9252 0,00 stair 356 467 3857-251,27 standata 359 1075 3038 1257,70 standgub 361 1184 3146 1257,70 standmps 467 1075 3686 1406,02 stocfor1 117 111 474-41131,98 stocfor2 2157 2031 9492-39024,41 stocfor3 16675 15695 74004-39976,78 truss 1000 8806 36642 458815,85 tuff 333 587 4523 0,29 vtp-base 198 203 914 129831,46 wood1p 244 2594 70216 1,44 woodw 1098 8405 37478 1,30 Β) Συλλογή Kennigton Name Equations Variables Nonzeros Solution cre-a 3516 4067 19054 23595407,00 cre-b 9648 72447 328542 23129640,00 cre-c 3068 3678 16922 25275116,00 cre-d 8926 69980 312626 24454970,00 ken-07 2426 3602 11981-679520400,00 ken-11 14694 21349 70354-6972382000,00 ken-13 28632 42659 139834-10257400000,00 ken-18 105127 154699 512719-52217000000,00 osa-07 1118 23949 167643 535722,52 osa-14 2337 52460 367220 1106462,84 osa-30 4350 100024 700160 2142139,87 osa-60 10280 232966 1630758 4044072,50 pds-02 2953 7535 21252 28857860000,00 pds-06 9881 28655 82269 27761040000,00 pds-10 16558 48763 140063 26727090000,00 pds-20 33874 105728 304153 23821660000,00 Γ) infeasible problems Name Equations Variables Nonzeros bgdbg1 348 407 1485 bgetam 400 688 2489 bgindy 2671 10116 75019 82
bgprtr 20 34 90 box1 231 261 912 ceria3d 3576 824 17604 chemcom 288 720 2190 cplex1 3005 3221 10664 cplex2 224 221 1059 ex72a 197 215 682 ex73a 193 211 668 forest6 66 95 270 galenet 8 8 16 gosh 3632 10433 93475 gran 2658 2520 20151 itest2 9 4 17 itest6 11 8 23 klein1 54 54 696 klein2 477 54 4585 klein3 994 88 12107 mondou2 312 604 1623 pang 361 460 2666 pilot4i 410 1000 5145 qual 323 464 1714 reactor 318 637 2995 refinery 323 464 1694 vol1 323 464 1714 woodinfe 35 89 209 Δ) Συλλογή Mittelmann Name Equations Variables Nonzeros Solution fome10 6071 12230 41873 0,00 fome11 12142 24460 83746 0,00 fome12 24284 48920 167492 0,00 fome13 48568 97840 334984 0,00 fome20 33874 105728 304153 23821660000,00 fome21 67748 211456 608306 47346320000,00 nug20 15240 72600 358380 nug30 52260 379350 1822710 pds-100 156243 505360 1390539 pds-2 2953 7535 21252 28857860000,00 pds-30 49944 154998 442876 21385450000,00 pds-40 66844 212859 605678 18855200000,00 pds-50 83060 270095 764161 16603530000,00 pds-60 99431 329643 928368 14265900000,00 pds-70 114944 382311 1071390 12241160000,00 pds-80 129181 426278 1187165 11469080000,00 pds-90 142823 466671 1291579 rail2586 2586 920683 8929459 rail4284 4284 1092610 12372358 rail507 507 63009 472358 172,15 rail516 516 47311 362207 182,00 rail582 582 55515 457223 209,71 sgpf5y6 131228 112517 639540 stormg2_1000 528185 1259121 4228817 watson_1 155469 295650 880828 Ε) προβληματικά: σετ ΓΠ από την Ακαδημία Επιστημών της Ουγγαρίας Name Equations Variables Nonzeros Solution de063155 852 1488 5405 9883094500,00 de063157 936 1488 5551 21528501,00 de080285 936 1488 5514 13,92 gen1 769 2560 64621 0,00 gen2 1121 3264 84095 3,29 gen4 1537 4297 110174 0,00 iprob 3001 3001 12000 l30 2701 15380 64790 0,95 83
Στ) στοχαστικά: σετ ΓΠ από την Ακαδημία Επιστημών της Ουγγαρίας Name Equations Variables Nonzeros Solution cep1 1521 3248 9956 355160,09 deter0 1923 5468 11191-2,05 deter1 5527 15737 32239-2,56 deter2 6095 17313 35811-1,83 deter3 7647 21777 44619-2,11 deter4 3235 9133 19301-1,43 deter5 5103 14529 29763-2,26 deter6 4255 12113 24811-2,31 deter7 6375 18153 37191-2,23 deter8 3831 10905 22335-2,79 fxm2-16 3900 4012 21542 fxm2-6 1520 1642 8082 fxm3_16 41340 59692 343382 fxm3_6 6200 8602 48312 fxm4_6 22400 27682 234612 pgp2 4034 9220 25924 447,32 pltexpa2-16 1726 4540 7312 pltexpa2-6 686 1820 2912 pltexpa3_16 28350 74172 119952 pltexpa3_6 4430 11612 18752 pltexpa4_6 26894 70364 113792 sc205-2r-100 2213 2214 6031-10,07 sc205-2r-16 365 366 991-55,39 sc205-2r-1600 35213 35214 96031 0,00 sc205-2r-200 4413 4414 12031-10,07 sc205-2r-27 607 608 1651-15,11 sc205-2r-32 717 718 1951-55,39 sc205-2r-4 35 36 0 0,00 sc205-2r-400 8813 8814 24031-10,07 sc205-2r-50 1113 1114 3031-30,76 sc205-2r-64 1421 1422 3871-55,39 sc205-2r-8 189 190 511-60,42 sc205-2r-800 17613 17614 48031-10,07 scagr7-2b-16 623 660 2685-832902,15 scagr7-2b-4 167 180 717-832941,33 scagr7-2b-64 9743 10260 42045-832901,55 scagr7-2c-16 623 660 2685-832260,03 scagr7-2c-4 167 180 717-832260,03 scagr7-2c-64 2447 2580 10557-818719,61 scagr7-2r-108 4119 4340 17665-834038,85 scagr7-2r-16 623 660 2685-832902,15 scagr7-2r-216 8223 8660 35269-834038,85 scagr7-2r-27 1041 1100 4489-833543,82 scagr7-2r-32 1231 1300 5309-832902,09 scagr7-2r-4 167 180 717-832902,15 scagr7-2r-432 16431 17300 70477-834029,77 scagr7-2r-54 2067 2180 8917-833834,10 scagr7-2r-64 2447 2580 10557-832902,04 scagr7-2r-8 319 340 1373-832902,15 scagr7-2r-864 32847 34580 140893-834376,10 scfxm1-2b-16 2460 3714 14052 2877,56 scfxm1-2b-4 684 1014 4032 2875,98 scfxm1-2b-64 19036 28914 107572 2877,56 scfxm1-2c-4 684 1014 4032 2875,98 scfxm1-2r-128 19036 28914 107572 2891,71 scfxm1-2r-16 2460 3714 14052 2877,56 scfxm1-2r-256 37980 57714 214452 2891,71 scfxm1-2r-27 4088 6189 23237 2886,96 scfxm1-2r-32 4828 7314 27412 2877,56 scfxm1-2r-4 684 1014 4032 2877,56 scfxm1-2r-64 9564 14514 54132 2877,56 scfxm1-2r-8 1276 1914 7372 2877,56 scfxm1-2r-96 14300 21714 80852 2891,71 scrs8-2b-16 476 645 1955 112,10 84
scrs8-2b-4 140 189 551 112,10 scrs8-2b-64 1820 2469 7571 1121,45 scrs8-2c-16 476 645 1955 112,43 scrs8-2c-32 924 1253 3827 112,16 scrs8-2c-4 140 189 551 112,10 scrs8-2c-64 1820 2469 7571 111,88 scrs8-2c-8 252 341 1019 112,42 scrs8-2r-128 3612 4901 15059 1177,35 scrs8-2r-16 476 645 1955 123,18 scrs8-2r-256 7196 9765 30035 1144,16 scrs8-2r-27 784 1063 3242 587,17 scrs8-2r-32 924 1253 3827 123,18 scrs8-2r-4 140 189 551 123,18 scrs8-2r-512 14364 19493 59987 1074,10 scrs8-2r-64 1820 2469 7571 123,18 scrs8-2r-64b 1820 2469 7571 1346,10 scrs8-2r-8 252 341 1019 1122,97 scsd8-2b-16 330 2310 9480 27,50 scsd8-2b-4 90 630 2520 15,25 scsd8-2b-64 5130 35910 148680 16,00 scsd8-2c-16 330 2310 9480 15,00 scsd8-2c-4 90 630 2520 15,00 scsd8-2c-64 5130 35910 148680 15,00 scsd8-2r-108 2170 15190 62840 23,70 scsd8-2r-16 330 2310 9480 16,00 scsd8-2r-216 4330 30310 125480 23,40 scsd8-2r-27 550 3850 15860 24,00 scsd8-2r-32 650 4550 18760 16,00 scsd8-2r-4 90 630 2520 15,50 scsd8-2r-432 8650 60550 250760 25,80 scsd8-2r-54 1090 7630 31520 23,85 scsd8-2r-64 1290 9030 37320 15,84 scsd8-2r-8 170 1190 4840 16,00 scsd8-2r-8b 170 1190 4840 16,00 sctap1-2b-16 990 1584 6928 280,80 sctap1-2b-4 270 432 1840 239,25 sctap1-2b-64 15390 24624 108688 484,56 sctap1-2c-16 990 1584 6928 326,40 sctap1-2c-4 270 432 1840 236,25 sctap1-2c-64 3390 5424 23888 200,39 sctap1-2r-108 6510 10416 45936 248,00 sctap1-2r-16 990 1584 6928 359,00 sctap1-2r-216 12990 20784 91728 249,00 sctap1-2r-27 1650 2640 11592 247,50 sctap1-2r-32 1950 3120 13712 354,00 sctap1-2r-4 270 432 1840 280,50 sctap1-2r-480 28830 46128 203664 248,50 sctap1-2r-54 3270 5232 23040 249,25 sctap1-2r-64 3870 6192 27280 344,00 sctap1-2r-8 510 816 3536 360,50 sctap1-2r-8b 510 816 3536 250,00 stormg2-125 66185 157496 529317 stormg2-27 14441 34114 114973 stormg2-8 4409 10193 34641 Z) διάφορα: από την Ακαδημία επιστημών της Ουγγαρίας Name Equations Variables Nonzeros Solution aa01 823 8904 81869 55535,44 aa03 825 8627 79433 49616,36 aa3 0 1 0 49616,36 aa4 0 1 0 25877,61 aa5 0 1 0 53735,93 aa6 0 1 0 26977,19 air02 50 6774 68329 7640,00 air06 825 8627 79433 49616,36 aircraft 3754 7517 24034 1567,04 bas1lp 5411 4461 582429 363,00 85
baxter 27441 15128 109823 56007256,00 car4 16384 33052 96492 35,46 cari 400 1200 153600 581,89 ch 3700 5062 24760 925756,37 co5 5774 7993 58739 714469,55 co9 10789 14851 111158 946920,43 complex 1023 1408 46783-99,67 cq5 5048 7530 51879 400133,81 cq9 9278 13778 97283 505541,71 cr42 905 1513 7527 28,02 crew1 135 6469 53419 20,56 dbic1 43200 183235 1217046 dbir1 18804 27355 1067815-8106707,00 dbir2 18906 27355 1148847-6116917,00 delf000 3128 5464 15534 3,08 delf001 3098 5462 16142 2358,61 delf002 3135 5460 16215 2,83 delf003 3065 5460 16197 9115,55 delf004 3142 5464 16474 158,69 delf005 3103 5464 16422 2287,30 delf006 3147 5469 16532 228,43 delf007 3137 5471 16686 379,96 delf008 3148 5472 16749 241,24 delf009 3135 5472 16678 484,12 delf010 3147 5472 16730 229,11 delf011 3134 5471 16705 473,49 delf012 3151 5471 16721 178,68 delf013 3116 5472 16737 2616,68 delf014 3170 5472 16794 153,50 delf015 3161 5471 16721 737,04 delf017 3176 5471 16660 461,52 delf018 3196 5471 16702 142,13 delf019 3185 5471 16690 2342,13 delf020 3213 5472 16998 351,68 delf021 3208 5471 16996 394,70 delf022 3214 5472 16988 364,99 delf023 3214 5472 17026 354,12 delf024 3207 5466 17384 351,42 delf025 3197 5464 17375 350,30 delf026 3190 5462 17148 351,61 delf027 3187 5457 17128 319,46 delf028 3177 5452 17330 297,25 delf029 3179 5454 17330 275,23 delf030 3199 5469 17190 253,84 delf031 3176 5455 17133 234,30 delf032 3196 5467 17179 216,04 delf033 3173 5456 17133 200,27 delf034 3175 5455 17136 189,44 delf035 3193 5468 17212 176,95 delf036 3170 5459 17130 164,46 df2177 630 9728 31434 90,00 disp3 2182 1856 8221 183887,52 ex3sta1 17443 8156 59420-63,08 farm 7 12 48 17500,00 gams10a 114 61 298 1,00 gams10am 114 61 298 gams30a 354 181 938 1,00 gams30am 354 181 938 gams60am 714 361 1897 gas11 459 862 2731 22636722,00 greenbei 2393 5405 31105 iiasa 669 2970 9258 263486120,00 jendrec1 2109 4228 93836 7028,46 kent 21302 6622 56914 kl02 71 36699 249235 215,25 kleemin3 3 3 9-10000,00 kleemin4 4 4 14-1000000,00 kleemin5 5 5 20-100000000,00 kleemin6 6 6 27-10000000000,00 86
kleemin7 7 7 35-1000000000000,00 kleemin8 8 8 44-100000000000000,00 l9 244 1401 5829 1,00 large000 4239 6833 20233 72,61 large001 4162 6834 20885 33181,42 large002 4249 6835 21990 2,88 large003 4200 6835 21676 24595,49 large004 4250 6836 21399 174,71 large005 4237 6837 21235 411,85 large006 4249 6837 21547 247,45 large007 4236 6836 21516 502,61 large008 4248 6837 21558 268,11 large009 4237 6837 21538 502,82 large010 4247 6837 21547 256,25 large011 4236 6837 21538 493,58 large012 4253 6838 21579 199,70 large013 4248 6838 21601 571,01 large014 4271 6838 21639 171,58 large015 4265 6838 21617 672,53 large016 4287 6838 21689 163,49 large017 4277 6837 21643 625,68 large018 4297 6837 21451 214,62 large019 4300 6836 21446 525,53 large020 4315 6837 21796 377,52 large021 4311 6838 21817 422,13 large022 4312 6834 21764 377,49 large023 4302 6835 21783 362,45 large024 4292 6831 22259 356,03 large025 4297 6832 22403 355,45 large026 4284 6824 22291 356,38 large027 4275 6821 22222 333,71 large028 4302 6833 22546 311,37 large029 4301 6832 22612 287,48 large030 4285 6823 22503 265,13 large031 4294 6826 22527 245,03 large032 4292 6827 22510 226,15 large033 4273 6817 22451 209,84 large034 4294 6831 22515 198,77 large035 4293 6829 22541 185,61 large036 4282 6822 22500 171,07 lp22 2958 13434 78994 458,94 lpl1 39951 125000 462127 lpl2 3294 10755 42861 4465,00 lpl3 10828 33538 133915 27318,00 mod2 30895 28194 174441 27737371,00 model1 362 798 3028 0,00 model10 4400 15447 152025-154599,62 model11 7056 18288 65523 0,00 model2 379 1212 7716-7400,49 model3 1609 3840 24724 17489,06 model4 1337 4549 46055 1112702,45 model5 1888 11360 90235-858440,73 model6 2096 5001 28203 117507,69 model7 3358 8007 52721 49380,09 model8 2896 6464 25293 0,00 model9 2879 10257 60162-141123,09 multi 61 102 1063 43904,91 nemsafm 334 2252 4982-6792,37 nemscem 651 1570 5228 89772,33 nemsemm1 3945 71413 1120871 512959,60 nemsemm2 6943 42133 212793 581079,57 nemspmm1 2372 8622 57961-327415,84 nemspmm2 2301 8413 69838-291794,84 nemswrld 7138 27174 193284 260,31 nl 7039 9718 49250 1229264,01 nsct1 22901 14981 667499-38922440,00 nsct2 23003 14981 686396-37175080,00 nsic1 451 463 3063-9168554,00 nsic2 465 463 3225-8203512,00 87
nsir1 4407 5717 141102-28909030,00 nsir2 4453 5717 152746-27175590,00 nug05 210 225 1190 50,00 nug06 372 486 2532 86,00 nug07 602 931 4886 148,00 nug12 3192 8856 44244 nug15 6330 22275 110700 nw14 73 123409 1028319 61844,00 orna1 882 882 3990 orna2 882 882 3990 orna3 882 882 3990 orna4 882 882 3990 orna7 882 882 3990 orswq2 80 80 344-0,18 p0040 23 40 150 61796,55 p010 10090 19000 136910 1115047,92 p0291 252 291 2321 1705,13 p05 5090 9500 68455 556000,28 p19 284 586 5891 249976,18 p6000 2095 5872 23603-2351871,00 pcb1000 1565 2428 22499 56809,46 pcb3000 3960 6810 63367 137416,42 pf2177 9728 900 22606 90,00 pldd000b 3069 3267 10762 2,74 pldd001b 3069 3267 10763 3,81 pldd002b 3069 3267 10764 4,07 pldd003b 3069 3267 10765 4,03 pldd004b 3069 3267 10766 4,18 pldd005b 3069 3267 10767 4,15 pldd006b 3069 3267 10768 4,18 pldd007b 3069 3267 10769 4,04 pldd008b 3069 3267 10829 4,17 pldd009b 3069 3267 10832 4,54 pldd010b 3069 3267 10835 4,83 pldd011b 3069 3267 10837 4,97 pldd012b 3069 3267 10839 4,61 primagaz 1554 10836 32487 1071902600,00 problem 12 46 120 0,00 progas 1650 1425 8722 760773,22 qiulp 1192 840 3744-931,64 r05 5190 9500 113455 557831,86 rat1 3136 9408 94539 1999531,66 rat5 3136 9408 143685 3083707,01 rat7a 3136 9408 275180 2074371,42 refine 29 33 155-392691,80 rlfddd 4050 57471 310044-13,00 rlfdual 8052 66918 328891-1,00 rlfprim 58866 8052 265975 1,00 rosen1 520 1024 24231-27612,74 rosen10 2056 4096 65988-174215,46 rosen2 1032 2048 48432-54417,51 rosen7 264 512 8247-20329,70 rosen8 520 1024 16498-42122,68 route 20894 23923 210025 5941,65 self 960 7364 1148865 seymourl 4944 1372 34921 403,85 slptsk 2861 3347 73062 29,90 small000 709 1140 3359 21,28 small001 687 1140 3481 2007,63 small002 713 1140 3556 37,66 small003 711 1140 3555 185,44 small004 717 1140 3593 54,68 small005 717 1140 3627 34,17 small006 710 1138 3634 24,43 small007 711 1137 3689 13,88 small008 712 1134 3652 8,05 small009 710 1135 3640 4,91 small010 711 1138 3637 2,26 small011 705 1133 3615 0,89 88
small012 706 1134 3624 0,62 small013 701 1131 3599 0,96 small014 687 1130 3537 1,23 small015 683 1130 3577 1,68 small016 677 1130 3547 2,20 south31 18425 35421 146919 1818940200,00 sws 11429 2467 11921 t0331-4l 664 46915 477897 29730,03 testbig 17613 31223 61640-60,42 ulevimin 6590 44605 162207-5191102000,00 us04 163 28016 325554 17731,67 world 30736 29218 174016 40364873,00 Η) διάφορα: μοντέλα από τον Housam Binous Name Type Equations Variables Nonzeros Solution cracker1 LP 7 8 43 cracker2 LP 7 8 43 power LP 22 17 57 89
Παράρτημα C - Απεικόνιση αραιής μορφής αρχείων MPS 90
91
92
93
94