Bonjour à tous,
dans le cadre de mon cours d'informatique théorique, je me suis codé un petit simulateur de machines de Turing en OCaml. Le code est très simple et petit (55 lignes de code). Pour mon plaisir personnel, j'ai codé un simulateur identique en Java. Pour une machine de Turing qui nous a été donnée en devoir, mon simulateur OCaml termine en 5.1s et celui en Java termine en 2.0s sur ma machine x64; sur ma machine 32 bits, le simulateur en OCaml prend 9 secondes et celui en Java en prend que 3.
Je sais que OCaml fait très peu d'optimisations du code objet et que Java en fait beaucoup, mais je me demandais si quelqu'un avait des petites améliorations à proposer pour mon code OCaml.
Pour compiler le code, utiliser la commande ocamlopt str.cmxa tm.ml -o tm et pour l'exécuter utiliser la commande ./tm <fichier de machine de Turing> <chaîne initiale> <état initial>.
Je note au passage que j'avais une version qui utilisait un Hashtbl et que sa performance était inférieure à l'utilisation d'un Map.
Si vous avez besoin d'informations supplémentaires, n'hésitez pas à me les demander.
Merci de votre aide.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 module TupleMap = Map.Make( struct type t = char * string let compare (c1, s1) (c2, s2) = let cmp1 = Char.compare c1 c2 in if cmp1 <> 0 then cmp1 else String.compare s1 s2 end ) (* in_ch : Canal de lecture rules : Map contenant les règles. Les clés sont des 2-tuples contenant un caractère et un état, et les valeurs sont des 3-tuples contenant un caractère, un état et une direction. Chaque ligne est lu et est séparée aux virgules; s'il y a 5 éléments, on ajoute la règle, sinon on passe à la ligne suivante. À la fin du fichier, on retourne le Map. *) let rec read_rules in_ch rules = let splitter = Str.regexp "[ ]*,[ ]*" in let rec loop rules = try let line = input_line in_ch in match (Str.split splitter line) with | [old_st; old_ch; new_st; new_ch; dir] -> loop (TupleMap.add (old_ch.[0], old_st) (new_ch.[0], new_st, dir.[0]) rules) | _ -> loop rules with End_of_file -> rules in loop rules let move_head head dir = match dir with | 'G' -> head - 1 | 'D' -> head + 1 | _ -> head (* tape: un tableau de caractères représentant le ruban head: un entier représentant la position dans le ruban state: une chaîne représentant l'état actuel rules: un map contenant les règles de transition steps: un entier contenant le nombre d'étapes exécutées Tant que `state` n'est pas l'état ACCEPTE ou REJETTE, on trouve la règle correspondante à l'état et au caractère actuel, on les remplace et on se déplace vers la gauche ou vers la droite. *) let rec execute tape head state rules steps = match state with | "ACCEPTE" -> ("ACCEPTE", steps) | "REJETTE" -> ("REJETTE", steps) | _ -> let (new_ch, new_st, dir) = TupleMap.find (tape.(head), state) rules in tape.(head) <- new_ch; execute tape (move_head head dir) new_st rules (steps+1) (* Créer le ruban en créant un tableau de caractères _ et en remplaçant le centre par la chaîne d'entrée. *) let make_tape length input = let tape = Array.make length '_' in for i = 0 to (String.length input) - 1 do tape.(length / 2 + i) <- input.[i] done; tape let _ = let in_ch = open_in Sys.argv.(1) in let rules = read_rules in_ch TupleMap.empty in close_in in_ch; let init_st = Sys.argv.(3) in let tape_length = 1 lsl 20 - 1 in (* ~1M *) let head = tape_length / 2 in let tape = make_tape tape_length Sys.argv.(2) in let (final_st, steps) = execute tape head init_st rules 0 in Printf.printf "%s (%d)\n" final_st steps
Code pour la machine de Turing (à exécuter avec ./tm fichier.tm "" 1):
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 1,_,2,1,G 1,1,3,1,D 2,_,3,1,G 2,1,2,1,G 3,_,4,1,G 3,1,5,_,D 4,_,1,1,D 4,1,4,1,D 5,_,ACCEPTE,1,G 5,1,1,_,D
Partager