Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Friday, 11 March 2011

Non Turing complete γλώσσες προγραμματισμού

Σκεφτόμουν αυτές τις μέρες γιατί οι γλώσσες προγραμματισμού, ενώ όλες ειναι Turing complete, δεν έχουν την ίδια εκφραστικότητα. Γιατί δηλαδή κάποιες είναι πιο εύκολες στη χρήση από κάποιες άλλες; Και τότε μου γεννήθηκε η απορία αν υπάρχουν non Turing complete γλώσσες προγραμματισμού. Μια σύντομη έρευνα έδειξε ότι υπάρχουν: η BlooP. Η BlooP μαζί με τη FlooP σχεδιάστηκαν από το Douglas R. Hofstadter για το βιβλίο του Gödel, Escher, Bach.

Sunday, 17 October 2010

TeX code generation with perl

A couple of months ago I started to learn some basic perl, because perl is one of the programming languages that one should know. It can be used from text processing and web applications to system administration and many other applications. So I came with the idea to write something simple in order to automate some TeX code generation done by some other part of my program. So I wrote some basic perl functions that can be found here:

#!/usr/bin/env perl

sub initialize{
$text = '\documentclass{article}'."\n";
$text .= '% Created by '."\n";
$text .= '\begin{document}'."\n";
}

sub usepackage{
$text = '\usepackage{'.$_[0]."}\n";
}

sub finalize{
$text = '\end{document}'."\n";
}

sub itemize{
$text = '\begin{itemize}'."\n";
$text .= "\t\item"."\n";
$text .= '\end{itemize}'."\n";
}

sub enumerate{
$text = '\begin{enumerate}'."\n";
$text .= "\t\item"."\n";
$text .= '\end{enumerate}'."\n";
}

sub figure{
$text = '\begin{figure}'."\n";
$text .= "\t".'\includegraphics{}'."\n";
$text .= '\end{figure}'."\n";
}

sub table{
$text = '\begin{tabular}'."\n";
#$text = 'table';
$text .= '\end{tabular}'."\n";
}

sub tabbing{
$a = '\begin{tabbing}'."\n";
$a .= '\end{tabbing}'."\n";
}

sub section{
$a = '\section{'.$_[0]."}\n";
}

sub subsection{
$a = '\subsection{'.$_[0]."}\n";
}

sub equation{
$a = '\begin{equation}'."\n";
$a .= $_[0];
$a .= '\end{equation}'."\n";
}

And a simple example is given below:

print &initialize;
print &usepackage("graphicx");

print &itemize;
print &enumerate;
print &figure;
print &table;

print &finalize;

Wednesday, 6 October 2010

xcf2pdf

xcf2pdf is a simple python script, that uses convert from ImageMagick to batch convert every xcf image inside a folder to a pdf


#!/usr/bin/python


from subprocess import *

import re


def convert(file):

p = Popen(['convert', file, file[:-3]+'pdf'], stdout=PIPE, stderr=PIPE)


p = Popen('ls', stdout=PIPE, stderr=PIPE)

ls, error = p.communicate()

files = re.split('\n', ls)

for i in files:

if i[-3:]=='xcf':

convert(i)


There are a few features missing and known bugs, e.g. it will convert every layer of the xcf file to a different page in the same pdf. (Beware of the python code formatting)

Thursday, 11 March 2010

FORTRAN ξανά

FORTRAN ξανά
Ή "η νέα γλώσσα προγραμματισμού"

Ακούω γέλια; Ναι η FORTRAN είναι μια σύγχρονη γλώσσα προγραμματισμού που μαθαίνεται από πολλούς νέες και νέους στο forum μας, αλλά δυστυχώς δε διδάσκεται (τουλάχιστον σωστά). Και επειδή αυτοί που τη διδάσκουν δε ξέρουν από ελεύθερο λογισμικό, οπότε δε μπορούν να γράψουν έναν οδηγό και να τον διαθέσουν ελεύθερο, αποφάσισα να κάνω εγώ αυτή τη δουλειά. (Όχι ότι δε μου κάνει κέφι)

Πολλές από τις πληροφορίες που αναφέρω εδώ βρίσκονται ήδη στους οδηγούς της υπογραφής μου, αλλά τις επαναλαμβάνω για τους τεμπέληδες. Καταρχήν (επειδή έχω κουραστεί να ακούω το logari81 να τονίζει τη διαφορά μεταξύ compiler, IDE, κλπ κλπ) υπάρχει το IDE, Integrated Development Environment, με το οποίο δεν πρόκειται να ασχοληθώ καθόλου. Όπως λέει η λέξη είναι ένα ολοκληρωμένο περιβάλλον ανάπτυξης, τίποτε λιγότερο τίποτε παραπάνω. Δεν είναι compiler, δεν είναι linker. Παράδειγμα: geany.

Compiler: Είναι το πρόγραμμα εκείνο (γραμμής εντολών) που παίρνει τον πηγαίο κώδικα και το μετατρέπει σε δυαδικό εκτελέσιμο. Πάλι τίποτε λιγότερο τίποτε παραπάνω. Στον compiler ΔΕ γράφουμε κώδικα. Παραδείγμα: gfortran. Εγκατάσταση:
sudo apt-get install gfortran

Linker: Είναι το πρόγραμμα εκείνο (γραμμής εντολών) που "συνδέει" όλα τα δυαδικά αρχεία σε ένα εκτελέσιμο. Πάλι τίποτε λιγότερο τίποτε παραπάνω. Πολλές φορές ο compiler καλεί, ξανατονίζω καλεί, τον linker. Ο compiler ΔΕΝ κάνει linking. Kαλεί απλώς το linker. Παράδειγμα: ld. 

Τώρα που ξεκαθαρίσαμε τις βασικές έννοιες μπορούμε να προχωρήσουμε με τη FORTRAN. Όπως είπαμε FORTRAN είναι μια γλώσσα προγραμματισμού. Άλλα έχει πολλά πρότυπα, standards, όπως fortran 66, fortran 77, fortran 90/95, fortran 2003.Όταν γράφεις ένα πρόγραμμα αποφασίζεις σε ποιο πρότυπο θα το γράψεις, ή άλλοι το έχουν αποφασίσει πριν από σένα. Σε γενικές γραμμές είναι backwards compatible. Δε θα μπω σε λεπτομέρειες. Το fortran 66 είναι απαρχαιωμένο, μην το χρησιμοποιείτε. Το fortran 77 είναι μεν παλιό αλλά υπάρχει πολύ "legacy" κώδικας εκεί έξω που είναι γραμμένο σε αυτό. Αν ξεκινάτε κάτι καινούριο, τότε fortran 90/95. To fortran 2003 είναι ακόμη καινούριο, μη δοκιμασμένο και είναι πολύ πιθανό ο compiler gfortran να μην έχει όλες τις δυνατότητες που προδιαγράφονται από το πρότυπο. Ο gfortran υποστηρίζει τα πρότυπα 77 και 90/95 (για τα άλλα δεν είμαι σίγουρος). Ο g77 μόνο το 77 (όπως μαντεύετε και από το όνομα)

Αυτά και με τα πρότυπα. Μία άλλη σημαντική παρατήρηση είναι το format. Στο fortran 77 επειδή είχαν ακόμη κάρτες διάτριτες (τώρα μπορείτε να δείτε σε μουσεία τέτοιες) το πρότυπο προέβλεπε οι πρώτες 6 στήλες να είναι κενές και επιτρέπεται να γράφεις μέχρι την εβδομικοστή κάτι στήλη. Αυτό ονομάζεται fixed format, ενώ το ελεύθερο ονομάζεται free format. O compiler gfortran υποστηρίζει και τα δύο ανάλογα με την κατάληξη του αρχείου ή το command line argument: -ffree-form -ffixed-form και άλλα που μπορούν να βρεθούν εδώ http://linux.die.net/man/1/gfortran

Για να σκεφτούμε, τι άλλο χρειάζεται; Α ναι, ένα παράδειγμα. Γράφουμε στο αρχείο foo.f: 
print*, "hello world"
end

Ανοίγουμε το τερματικό και προσπαθούμε να το κάνουμε compile με:
gfortran foo.f
σφάλμα

ξαναπροσπαθούμε:
gfortran -ffree-form foo.f
οκ

το μετονομάζουμε το αρχείο σε foo.f90 και ξαναπροσπαθούμε:
gfortran foo.f90
οκ

Τώρα στο αρχείο foo.f προσθέτουμε 6 κενά σε κάθε γραμμή:
  print *, "hello, world"
  end
και ξαναπροσπαθούμε
gfortran foo.f
οκ

You got the point? Ωραία αλλάζουμε κεφάλαιο. (Με προσοχή τις σελίδες γιατί είναι παλιές και ευαίσθητες) 

Πριν αλλάξουμε κεφάλαιο (με προσοχή τις σελίδες είπαμε) ας δούμε τη διαφορά compiling και linking. Mέχρι στιγμής λέγαμε στον compiler να κάνει τη όλη δουλειά μόνος του, δηλαδή και το compile και να καλέσει το linker (αν έχετε ανοιχτό το top σε άλλο τερματικό θα δείτε που τρέχει στιγμιαίο η εντολή ld). Aν όμως εκτελέσουμε την εντολή
gfortran -c foo.f 
Εδώ γίνεται μόνο compile, δημιουργείται το *.ο αρχείο του πηγαίου κώδικα.

Τώρα με
gfortran -o a.out foo.o
λέμε στον compiler να συνδέσει το εκτελέσιμο a.out με το δυαδικό foo.o.

Αυτά. Happy crunching!

Friday, 26 June 2009

Maxima

To Maxima είναι ένα σύστημα υπολογιστικής άλγεβρας (computer algebra system) για την επεξεργασία συμβολικών και αριθμητικών εκφράσεων. Συμπεριλαμβάνει παραγώγιση, ολοκλήρωση, σειρές Taylor, μετασχηματισμοί Laplace, κανονικές διαφορικές εξισώσεις, συστήματα γραμμικών εξισώσεων, πολυώνυμα καθώς και σύνολα, διανύσματα, πίνακες και τανυστές.Το Maxima προσφέρει υψηλής ακρίβειας αριθμητικά αποτελέσματα χρησιμοποιώντας ακριβή κλάσματα, μεταβλητής ακρίβειας ακεραίους και μεταβλητής ακρίβειας πραγματικούς αριθμούς. Έχει τη δυνατότητα σχεδιασμού συναρτήσεων και δεδομένων σε δύο και τρεις διαστάσεις.

Το πρόγραμμα Maxima είναι τώρα πλέον ελεύθερο λογισμικό υπό την άδεια GNU GPL ενώ κατάγεται από το Macsyma, το θρυλικό σύστημα υπολογιστικής άλγεβρας που αναπτύχθηκε στα τέλη του 1960 στο πανεπιστήμιο της Μassachussetts.

Οι δυνατότητες του Maxima είναι απεριόριστες και εδώ θα περιοριστούμε στην παρουσίαση μερικών μόνο. Η γραμμή εντολών του χωρίζεται σε inputs και outputs, οπότε γράφοντας 9+7; θα πάρουμε ως αποτέλεσμα 16 (τo ; στο τέλος είναι απαραίτητο κατάλοιπο από τη C). Τίποτε το συνταρακτικό. Αν όμως δώσουμε 2/6; θα μας επιστρέψει 1/3, θα απλοποιήσει δηλαδή το κλάσμα χωρίς να υπολογίσει την προσέγγισή του. Αν θέλουμε ένα ρητό αριθμό ως προσέγγιση τότε θα πρέπει να γράψουμε float(1/3); για να πάρουμε το αποτέλεσμα 0.333333333333. Αλλά ας περάσουμε σε κάτι πιο θεαματικό. Ας υποθέσουμε ότι χρειαζόμαστε να αναπτύξουμε τον αριθμό 30! (30 παραγοντικό είναι 1*2*3*...*28*29*30) σε γινόμενο πρώτων παραγόντων, τότε γράφοντας factor(30!); παίρνουμε ως αποτέλεσμα 2^26*3^14*5^7*7^4*11^2*13^2*17*19*23*29. Φυσικά με τον ίδιο τρόπο μπορούμε να παραγοντοποιήσουμε πολυώνυμα factor(x^2 + x -6); για να δούμε (x-2)(x+3).

H επίλυση εξισώσεων γίνεται το ίδιο εύκολα solve(x^2-4,x); Το δεύτερο όρισμα, x, δηλώνει ως προς ποια μεταβλητή θα πρέπει να λυθεί η εξίσωση. Η παραγώγιση πραγματοποιείται με τη συνάρτηση diff(sin(x), x); Πάλι το δεύτερο όρισμα δηλώνει ως προς ποιά μεταβλητή πρέπει να παραγωγηθεί η δεδομένη συνάρτηση. Παρόμοια λειτουργεί και η αόριστη ολοκλήρωση integrate(1/x,x); και η ορισμένη ολοκλήρωση integrate(x+2/(x-3), x, 0, 1); H ανάπτυξη μιας συνάρτησης σε σειρά Taylor γίνεται με δύο τρόπους: niceindices(powerseries(%e^x, x, 0)); ή taylor(%e^x, x, 0, 5); Το όρισμα 0 δηλώνει σε ποιο σημείο να υπολογισθεί η σειρά ενώ στο δεύτερο τρόπο το όρισμα 5 δηλώνει πόσους όρους να δείξει στο αποτέλεσμα.

Φυσικά ένα τέτοιο πρόγραμμα θα ήταν ελλειπές αν δεν είχε δυνατότητες σχεδιασμού. Χρησιμοποιεί το πρόγραμμα gnuplot για το σχεδιασμό. Οι συναρτήσεις plot2d και plot3d δίνουν αυτή τη δυνατότητα. Tα αποτελέσματα των εντολών plot2d([x^2, x^3, x^4-x+1], [x,-10,10]);


και f(x,y):= sin(x) + cos(y); plot3d(f(x,y), [x,-5,5], [y,-5,5]); δίνουν τα αντίστοιχα διδιάστατα και τριδιάστατα γραφήματα. Στη δεύτερη περίπτωση ορίσαμε προηγουμένως μια νέα συνάρτηση χρησιμοποιώντας τον τελεστή := για να αποφύγουμε μια μακροσκελή εντολή.



To πρόγραμμα είναι γραμμένο σε Common Lisp και περιλαμβάνει μια πλήρη γλώσσα προγραμματισμού και σύνταξη παρόμοια με την ALGOL. Mπορεί να προσπελαστεί προγραμματιστικά και να επεκταθεί καθώς η υποκείμενη Lisp μπορεί να κληθεί μέσα από το Maxima. Μία άλλη πολύ ενδιαφέρουσα δυνατότητα του Maxima είναι η δημιουργία κώδικα για compiled γλώσσες προγραμματισμού όπως η FORTRAN.

Εγκαθίσταται πολύ απλά από τη γραμμή εντολών με sudo apt-get install maxima ή από το μενού Εφαρμογές > Προσθαφαίρεση Προγραμμάτων. Πρόσθετα πακέτα που μπορούν να φανούν χρήσιμα είναι τα maxima-doc, maxima-emacs, kayali (ένα GUI γραμμένο σε Qt), xmaxima (ένα GUI γραμμένο σε tcl/tk). Περισσότερες λεπτομέρειες μπορούν να βρεθούν στην ιστοσελίδα http://maxima.sourceforge.net/

Thursday, 25 June 2009

Η τέχνη του προγραμματισμού

Σε καμιά περίπτωση δεν κατέχω την υψηλή αυτή τέχνη, απλώς προσπαθώ να μοιραστώ λίγη από τη γεύση της και θα χαρώ να διαβάσω τις δικές σας εμπειρίες.

Γιατί τέχνη και γιατί προγραμματισμός; Προγραμματισμός γιατί όλες οι εφαρμογές στον υπολογιστή απαιτούν προγραμματισμό στη μία ή στην άλλη γλώσσα. Τέχνη γιατί δεν αρκεί να μάθει κανείς πως αναμιγνύονται τα χρώματα για να γίνει ζωγράφος, ούτε να μάθει να διαβάζει το πεντάγραμμο για να γίνει μουσικός. Φυσικά είναι απαραίτητες προϋποθέσεις αλλά δεν είναι οι μοναδικές. Έτσι και στον προγραμματισμό δε αρκεί να μάθει κανείς τη σύνταξη μιας γλώσσας για να πει ότι είναι προγραμματιστής.

Η τέχνες δε μαθαίνονται στα πανεπιστήμια (μεγάλη κουβέντα αυτή, αλλά από προσωπική εμπειρία και βλέποντας φίλους αυτό συμπεράνω). Η τέχνη είναι κάτι που το ασκείς και εξασκείς μόνος σου. Κανείς δε μπορεί να σε βοηθήσει να γίνεις καλύτερος αν δεν προσπαθήσεις μόνος σου.

Τα απαραίτητα χαρακτηριστικά ενός προγραμματιστή είναι να μπορεί να προγραμματίσει οτιδήποτε σε οποιαδήποτε γλώσσα. Αυτό δε σημαίνει ότι ξέρει όλες τις γλώσσες αλλά στην ανάγκη μπορεί να μάθει τη σύνταξη. Αυτό που απαιτείται είναι να μπορεί να χρησιμοποιεί χαρακτηριστικά της μιας γλώσσας σε άλλη. Αυτό που θέλω να πω είναι ότι η σύνταξη δεν πρέπει να είναι περιορισμός για την ανάγνωση ή τη συγγραφή ενός προγράμματος.

H τέχνη του προγραμματισμού δεν περιλαμβάνει μόνο το γράψιμο κώδικα, αλλά κυρίως την αποσφαλμάτωσή του (debugging). Το πρώτο βήμα είναι η ορθή ανάγνωση του σφάλματος, το οποίο περιέχει αρκετές πληροφορίες για να βρούμε τη λύση του προβλήματος. Στην περίπτωση που το σφάλμα είναι bus error ή segmentation fault τότε αρχίζει η πραγματική τέχνη. Στη διαδικασία της αποσφαλμάτωσης ενά απλό printf διάσπαρτο σε διάφορα σημεία του κώδικα μπορεί να αντικαταστήσει και τον καλύτερο εργαλείο αποσφαλμάτωσης.

Η τέχνη του προγραμματισμού περιλαμβάνει την κατανόηση του πως λειτουργεί, στοιχειωδώς τουλάχιστον, ο μεταγλωττιστής (compiler) ή ο ερμηνευτής (interpreter) της γλώσσας που χρησιμοποιούμε. Μόνο έτσι θα μπορεί να βελτιστοποιήσει κανείς ένα πρόγραμμα ή να βρει ένα δύσκολο λάθος σε άλλο. Tαυτόχρονα να κατανοεί πως λειτουργεί ο υπολογιστής και το λειτουργικό σύστημα, για να κατανοήσει τι σημαίνει θέση μνήμης και δείκτης.

Η τέχνη του προγραμματισμού περιλαμβάνει τη γνώση των απαραίτητων εργαλείων που κάνουν τη ζωή του προγραμματιστή πιο εύκολη, αλλά ίσως και όχι. Τι θέλω να πω; Ο προγραμματιστής οφείλει να μπορεί να διαβάσει το Makefile ή το configure script ενός προγράμματος, να μπορεί να χρησιμοποιήσει debuggers και ταυτόχρονα όλα αυτά από τη γραμμή εντολών. Παρόλ'αυτά αν βρεθεί σε ένα καινούριο περιβάλλον να μπορεί να εξοικειωθεί γρήγορα με τα νέα εργαλεία του.

Ο προγραμματιστής οφείλει, αν δεν έχει στη διάθεσή του τα απαραίτητα εργαλεία, να μπορεί να τα κατασκευάσει μόνος του. Δικαιολογίες όπως "δε βρίσκω αυτό το πρόγραμμα για να κάνω τη δουλειά μου" δε γίνονται δεκτές.

Προγραμματισμός σημαίνει να βρίσκεται η βέλτιστη λύση σε κάθε πρόβλημα. Το κριτήριο όμως της βελτιστότητας κάθε φορά διαφέρει. Άλλες φορές είναι η ταχύτητα εκτέλεσης και άλλες φορές η ταχύτητα συγγραφής. Πολλές φορές η μέθοδος "brute force" είναι αποδεκτή όταν ένας πολύπλοκος αλγόριθμος θα χαλάσει την απλότητα του προγράμματος, χωρίς αυτό να σημαίνει ότι απλότητα είναι πάντα και ωραία.

Η τέχνη του προγραμματισμού έγγειται στο να αφήνουμε τον υπολογιστή να κάνει επαναλαμβανόμενες και άρα ανιαρές εργασίες. Αυτό σημαίνει όταν έχουμε να γράψουμε κώδικα είναι καλύτερο να γράφουμε προγράμματα που γράφουνε κώδικα. Έτσι μειώνονται οι πιθανότητες για ανθρώπινο λάθος.

Ο καλύτερος τρόπος να αποκτήσει κανείς εμπειρία με τον προγραμματισμό είναι να αρχίσει να προγραμματίζει. Στον κόσμο του ελεύθερου λογισμικού όπου ο κώδικας είναι ελεύθερος οι δυνατότητες για μάθηση είναι απεριόριστες. Η μελέτη κώδικα που έχουν γράψει άλλοι προγραμματιστές και η βήμα-βήμα επέκτασή του είναι ενδεδειγμένη τεχνική στην απόκτηση εμπειρίας και γνώσεων. Είναι αλήθεια ότι στην αρχή όλα φαίνονται δυσνόητα και απρόσιτα αλλά με την πάροδο του χρόνου ο κώδικας αρχίζει και γίνεται κατανοητός.

Ο προγραμματισμός πρέπει να είναι στάση ζωής. Αυτό σημαίνει να βρίσκουμε αλγόριθμους για επίλυση προβλημάτων στην καθημερινή μας ζωή, όπως ποιός είναι ο συντομότερος δρόμος για τη δουλειά ή ποια είναι η βέλτιστη τακτική στο risk.

Τέλος, σημασία έχει να διασκεδάζουμε με αυτό κάνουμε, διαφορετικά όλα είναι μάταια (όχι ότι δεν είναι ούτως ή άλλως, αλλά ας πούμε ότι δεν είναι).

Sunday, 22 March 2009

FORTRAN

10 IF (.NOT.(ΕΧΩ ΔΙΑΒΑΣΕΙ ΑΥΤΟ)) ΤΗΕΝ
READ IT
ELSE
GOTO 10
END IF

Κάπως έτσι φαίνεται ο κώδικας στην τυποποίηση της FORTRAN 77. Όλα κεφαλαία, καθόλου identation, πολλά goto και άλλα πολλά που κάνουν τον κώδικα δυσανάγνωστο. Αλλά η αρχαιότερη γλώσσα υψηλού επιπέδου έχει εξελιχθεί αρκετά. Υποστηρίζει πολλά χαρακτηριστικά του αντικειμενοστραφή προγραμματισμού με τα modules, έχει δικούς της δείκτες (pointers), αλλά και συμβατούς με τη C δείκτες (Cray pointers οι οποίοι όμως δεν περιλαμβάνονται στην τυποποίηση). Το πλεονέκτημά της είναι η ταχύτητα εκτέλεσης και ότι υπάρχει μια απειρία από προγράμματα που μπορεί να βρει κανείς σχετικά με επιστημονικούς υπολογισμούς. Για παράδειγμα το scipy της python περιλαμβάνει πολλούς wrapper σε προγράμματα FORTRAN (από εδώ www.netlib.org) για διαφορικές εξισώσεις, μετασχηματισμούς Fourier κ.α.. Φυσικά η FORTRAN υποστηρίζει και τις δύο μορφές παραλληλοποίησης, openmp και mpi.

Σίγουρα στα γραφικά υστερεί. Aλλά για αυτό υπάρχει η C ή η python. H επικοινωνία με τη C είναι απλή (αν ξέρεις πως γίνεται δηλαδή), με παρόμοιο τρόπο γίνεται και με τη C++, αν και χρειάζεται και δεύτερο wrapper από C σε C++ για να μη χαθεί η αντικειμενοστρέφεια του κώδικα, με την python μπορεί να χρησιμοποιηθεί το πρόγραμμα f2py που γράφει ένα wrapper από τον FORTRAN κώδικα.

Θα μου πείτε ποιος χρησιμοποιεί ακόμη FORTRAN όταν υπάρχει η python, η java, η C++ και τόσες άλλες γλώσσες προγραμματισμού; Πολλοί. Η πλειονότητα των προγραμμάτων στους υπερυπολογιστές (high performance computing) και σμήνη υπολογιστών (clusters) είναι προγράμματα FORTRAN. Δεν πρόκειται να δείτε κανένα πρόγραμμα java.

Προγραμματίζοντας στη FORTRAN, όπως και στη C, μαθαίνει κανείς διαχείριση μνήμης. Το σίγουρο είναι ότι θα ψάχνεται με τις ώρες ένα bug που θα βγάζει segmentation fault ή bus error. Τα άλλα είναι σχετικά εύκολα, μιας και τα βρίσκει και o compiler.

Μετά θα μου πείτε, μα αφού υπάρχει το octave ή το scilab ή τα αντίστοιχα εμπορικά; Ναι, και πάλι το octave χρησιμοποιει συναρτήσεις FORTRAN για την επίλυση εξισώσεων. Φυσικά είναι πολύ πιο εύκολο να προγραμματίσεις κάτι στο octave, αλλά αν ένας πίνακας είναι μεγάλος, της τάξης των 1.000.000 στοιχείων, τότε θα πρέπει να περιμένετε μέρες.

Η FORTRAN υποστηρίζει και system call, δηλαδή μπορείτε να καλέσετε άλλα προγράμματα μέσω FORTRAN. Καθόλου καλή προγραμματιστική τεχνική αλλά γίνεται.

Tuesday, 24 February 2009

Γραφικά με GTK+

Γενικά
Θέμα του οδηγού αυτού είναι τα γραφικά με τη χρήση της βιβλιοθήκης GTK+. Ο επίσημος οδηγός στα αγγλικά βρίσκεται εδώ: http://library.gnome.org/devel/gtk-tutorial/stable/ Τα παραδείγματα που χρησιμοποιώ βρίσκονται και στον αρχικό οδηγό. Παρ'όλ' αυτά δεν πρόκειται για μετάφραση μιας και ο μεταφραστής είναι προδότης (traduttore traditore :D ) αλλά για έναν καινουριο οδηγό.
Η GTK+ είναι μια βιβλιοθήκη που ξεκίνησε από το πρόγραμμα GIMP και εξελίχθηκε σε αυτόνομη βιβλιοθήκη. Παρέχει τις βασικές λειτουργίες για γραφικά, GUI, συμβάντα, κ.α.

Προαπαιτούμενα
Για τη χρήση της βιβλιοθήκης θα χρειαστεί να εγκαταστήσουμε μερικά πακέτα, τα build-essential, gtk+-2.0, pkg-config. To build-essential μας δίνει το GNU C μεταγλωττιστή, τo εργαλείo make κ.α., το gtk+-2.0 είναι η βιβλιοθήκη, και το pkg-config είναι ένα βοηθητικό πρόγραμμα που διαχειρίζεται τις παραμέτρους για το gcc. Aνοίγουμε το τερματικό και πληκτρολογούμε:

sudo apt-get install build-essential gtk+-2.0 pkg-config

Το πρώτο πρόγραμμα
Στον παρών οδηγό θα ασχοληθούμε με c, αλλά υπάρχουν και διεπιφάνειες και για άλλες γλώσσες προγραμματισμού. Ανοίγουμε ένα αρχείο bla.c και γράφουμε μέσα τον παρακάτω κώδικα:

#include <gtk/gtk.h>

int main( int argc,
char *argv[] )
{
GtkWidget *window;

gtk_init (&argc, &argv);

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_show (window);

gtk_main ();

return 0;
}

Το αποθηκεύουμε και έπειτα το μεταγλωττίζουμε με την εντολή:

gcc bla.c -o bla `pkg-config --cflags --libs gtk+-2.0`

Προσοχή παραπάνω είναι ` και όχι ', αυτό σημαίνει αντικατάσταση του αποτελέσματος της εντολής pkg-config --cflags --libs gtk+-2.0, την οποία αν εκτελέσουμε μόνη της θα δούμε μια λίστα από διαδρομές, αρχεία, βιβλιοθήκες τα οποία είναι παράμετροι για το gcc. Φυσικά αν ξέρουμε τι κάνουμε αυτές τις παραμέτρους μπορούμε να τις τροποποιήσουμε με το χέρι.
Τρέχοντας το πρόγραμμα:

./bla

θα δούμε ένα παράθυρο που δεν έχει τη δυνατότητα τερματισμού εκτός από το ctrl+c.

H πρώτη γραμμή λέει στο πρόγραμμά μας ποια αρχεία να συμπεριλάβει. Η διαδρομή των αρχείων καθορίζεται από την εντολή pkg-config --cflags --libs gtk+-2.0. Μετά από τον απαραίτητο ορισμό του κυρίως προγράμματος main χρειαζόμαστε την κλήση της συνάρτησης gtk_init. Σε όλα τα προγράμματα αυτή η κλήση είναι απαραίτητη εκτός κι αν ξέρουμε τι κάνουμε. Όλες τις παραμέτρους από τη γραμμή εντολών που έχουν να κάνουν με τη gtk τις αφαιρεί από τη λίστα των παραμέτρων και τις υπόλοιπες μπορεί ο χρήστης να τις χρησιμοποιήσει όπως θέλει.

Στην gtk σχεδόν όλα είναι GtkWidgets. Έτσι και το παράθυρό μας είναι ένας δείκτης τύπου GtkWidget (GtkWidget *window). Αυτός είναι ο ορισμός του αλλά το παράθυρο δημιουργείται για πρώτη φορά στη γραμμή:

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

Δημιουργείται όμως στη μνήμη, τίποτε δε φαίνεται ακόμη στην οθόνη. Η εντολή που το προβάλλει είναι η:

gtk_widget_show (window);

Αλλά πάλι δε συμβαίνει τίποτε. Αρχίζουμε και βλέπουμε πράματα όταν ο κώδικάς μας μπει στο βρόγχο gtk_main (), ο οποίος είναι και ο κύριος βρόγχος του προγράμματός μας. Μετά από αυτή την εντολή τίποτε δε συμβαίνει.


Pygtk
Και ύστερα από την παραπάνω προτροπή ακολουθεί σε python. Η python είναι μια γλώσσα προγραμματισμού που δε χρειάζεται να μεταγλωττιστεί (interpreted και όχι compiled, ας με βοηθήσει κάποιος με την ελληνική ορολογία) Σε αυτή την περίπτωση θα χρειαστούμε επιπλέον το πακέτο pygtk.

Ανοίγουμε το τερματικό και πληκτρολογούμε python και μας περιμένει το γνωστό
>>>
Εδώ πληκτρολογούμε

>>>import pygtk
>>>import gtk

κι έτσι έχουμε εισάγει τις βιβλιοθήκες που χρειαζόμαστε. Μιας και στην python δε χρειάζεται να δηλώσουμε μεταβλητές απλώς δημιουργουμε το παράθυρό μας με

>>>window = gtk.Window(gtk.WINDOW_TOPLEVEL)

και το προβάλουμε με

>>> window.show()

Προφανώς ακόμη δεν εμφανίστηκε τίποτε στην οθόνη γιατί δε φτάσουμε στο κυρίως βρόγχο. Αυτό γίνεται με

>>>gtk.main_level()

Και πάλι το πρόγραμμά μας δεν έχει δυνατότητα τερματισμού εκτός από ctrl+c. Η δυνατότητα τερματισμού πραγματοποιείται με σύνδεση του συμβάντος με την αντίστοιχη εντολή.

Thursday, 14 August 2008

Εισαγωγή σε parallel computing

Όλο και πιο συχνά ακούγεται στις μέρες μας ο όρος parallel computing, παράλληλοι υπολογισμοί, και έχει γίνει πλέον και στους προσωπικούς υπολογιστές πραγματικότητα με επεξεργαστές διπλών και τρίδιπλων (όπως το λαϊκό) επεξεργαστών. Αλλά ποιος ο λόγος και υπάρχει πράγματι κέρδος από τους επεξεργαστές με δύο πυρήνες ή είναι απλώς ένα εμπορικό παιχνίδι των εταιριών για να αυξήσουν τα κέρδη τους; Αυτή την ερώτηση δυστυχώς αδυνατώ να απαντήσω αλλά θα σας δώσω μια απλή γεύση του πως μπορούμε να εκμεταλλευτούμε αυτή τη δυνατότητα.

Oι παράλληλοι υπολογιστές χωρίζονται σε δύο βασικές κατηγορίες (επιτρέψτε μου την αγγλική ορολογία): shared και distributed μνήμης υπολογιστές. Οι πρώτοι, shared memory, είναι αυτοί που έχουμε στους υπολογιστές μας, όπου ο κάθε επεξεργαστής (στο σημείο αυτό δε θα τους ξεχωρήσω από τους πυρήνες) μοιράζεται την ίδια μνήμη με όλους τους υπόλοιπους. Οι distributed memory υπολογιστές έχουν ο καθένας δική του μνήμη και επικοινωνούν μέσω δικτύου. Προφανώς αν έχουμε 100 επεξεργαστές είναι λίγο δύσκολο να τους καλωδιώσουμε ώστε να μοιράζονται την ίδια μνήμη, ίσως στο μέλλον. Η δημιουργια, ο προγραμματισμός και η χρήση distributed memory είναι αρκετά προχωρημένη και δε θα ασχοληθω εδώ καθόλου.

Ας συνεχίσουμε λοιπόν με shared memory υπολογιστές. Για τα παρακάτω θα χρειαστούν:

sudo apt-get install build-essential libgomp

build-essential περιέχει όλα τα απαραίτητα πακέτα για προγραμματισμό και αναπτυξη κώδικα
libgomp περιέχει τη βιβλιοθήκη για shared memory parallel programming

Aναλυτικές οδηγίες για την gnu openMP μπορούν να βρεθούν http://gcc.gnu.org/onlinedocs/libgomp/

Θα ξεκινήσω με ένα απλό hello world πρόγραμμα σε C. Δημιοργούμε καταρχήν ένα φάκελο

mkdir ~/testgomp
cd ~/testgomp

Ανοίγουμε μέσα στο φάκελο testgomp με το gedit το αρχείο hello.c

gedit hello.c &


Kαι εισάγουμε τα παρακάτω:

int main()
{
printf("Hello world\n");
}

To μεταγλωττίζουμε και δημιουργούμε το εκτελέσιμο με:

gcc -c hello.c
gcc -o serialtest hello.o

Eκτελούμε το πρόγραμμα που δημιουργήθηκε με

./serialtest


και βλέπουμε ότι εκτυπώνεται στην οθόνη Hello world μόνο μία φορά.

Tώρα προσθέτουμε τη γραμμή #pragma omp parallel δηλαδή το αρχείο θα πρέπει να φαίνεται:

int main()
{
#pragma omp parallel
printf("Hello world\n");
}

To μεταγλωττίζουμε (τώρα χρειάζεται να συνδέσουμε επίσης την αντίστοιχη βιβλιοθήκη) και δημιουργούμε το εκτελέσιμο με:

gcc -c -fopenmp hello.c
gcc -o paralleltest hello.o

Εκτελούμε τώρα το παράλληλο πρόγραμμα με

./paralleltest


και βλέπουμε να τυπώνεται δύο φορές ενώ υπάρχει μόνο μία φορά στον κώδικά μας και δεν υπάρχει φυσικά κανένας βρόγχος. (Φυσικά αν έχουμε επεξεργαστή με ένα μόνο πυρήνα δε θα δούμε διαφορά)
Η γραμμή #pragma omp parallel αντιλαμβάνεται από το μεταγλωττιστή gcc σαν σχόλιο αν δεν υπάρχει η επιλογή -fopenmp κατά τη μεταγλώττιση, πράμα που επιτρέπει ένα πρόγραμμα που γράφουμε να είναι αρκετά portable.

Φυσικά αυτό δεν είναι και πολύ χρήσιμο γιατί επαναλαμβάνει την ίδια δουλειά δύο φορές. Εμείς χρειαζόμαστε κάτι που να μοιράζει το φόρτιο εργασίας στους δύο επεξεργαστές.
Aς δημιουργήσουμε τώρα ένα άλλο αρχείο hello2.c που θα περιέχει τα εξης:

#define N 100000
int main()
{
int i, a[N];
#pragma omp parallel for
for (i=0;i< style="font-weight: bold;"> a[i]= 2*i;
return 0;
}

Και μεταγλώττιση όπως πάντα με

gcc -c -fopenmp hello2.c
gcc -o paralleltest2 hello2.o

Το συγκεκριμένο παράδειγμα μοιράζει αυτόματα το array a[N] στα δύο threads που δημιουργούνται. Τα αποτελέσματα είναι σωστά γιατί το δεξί μέλος της ισότητας δεν εξαρτώνται από το αριστερό.

Aν είχαμε όμως κάτι όπως αυτό:


#define N 100000

int main()
{
int i, a[N];
a[0]=0;
#pragma omp parallel for
for (i=1; i<> a[i]= a[i-1]+1;
return 0;
}

δε θα λειτουργούσε γιατι κάθε επόμενο στοιχείο του a θα εξαρτάται από το προηγούμενο, αρα για να υπολογισει το στοιχειο 50000 στο δεύτερο thread θα χρειάζεται το 49999 από το πρώτο thread το οποίο δεν έχει υπολογιστεί ακομη.

Σε distributed memory υπολογιστές όπου τα δεδομένα, το a στο παράδειγμά μας, δεν είναι σε κοινή μνήμη θα πρέπει να μεταφέρονται από επεξεργαστή σε επεξεργαστή (για περισσότερες πληροφοριές δες http://en.wikipedia.org/wiki/Message_Passing_Interface) Yπάρχουν διάφορα εργαλεία για να στηθεί ένα [/url=http://en.wikipedia.org/wiki/Computer_cluster]cluster[/url] (distributed memory υπολογιστής) φυσικά και σε linux.

Βιβλιογραφία
1. http://openmp.org/wp/
2. http://gcc.gnu.org/onlinedocs/libgomp/
3. http://en.wikipedia.org/wiki/OpenMP
4. http://en.wikipedia.org/wiki/Parallel_computing