1. Trang chủ
  2. » Giáo Dục - Đào Tạo

Construction dun platoon en CSPllB

123 10 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 123
Dung lượng 771,15 KB

Nội dung

IFI HanoÔ, Vietnam LORIA Nancy, France MÉMOIRE DE FIN D'ÉTUDES Construction d'un platoon en CSPjjB Stagiaire : Huu-Nghia Nguyen Promotion 13, option SystËmes et RÈseaux Encadrants : Jean-Pierre Jacquot Jeanine SouquiËres Lieu de stage : Équipe DEDALE - LORIA Campus Scientique, BP 239 F-54506 Vandu˜vre lËs Nancy Cedex Nancy, le 28 octobre 2009 i Remerciements Je tiens tout d'abord ‡ remercier Jeanine SouquiËres de m'avoir accueilli au sein de l'Èquipe de recherche DEDALE - LORIA Je tiens particuliËrement ‡ remercier Jean-Pierre Jacquot qui m'a aidÈ beaucoup avec les conseils utiles sur la direction et la mÈthode de recherche pendant toute la durÈe du stage Je voudrais remercier Ègalement les personnes dans l'Èquipe DEDALE pour leur sympathie et leur environnement de travail trËs chaleureux Mes plus sincËres remerciements vont ‡ tous les professeurs et les personnels de l'IFI pour m'avoir donnÈ des cours et pour leur soutien tout au long de mes Ètudes ‡ l'IFI En n, un grand merci ‡ mes amis, ‡ ma famille qui sont toujours prËs de moi et m'encourage ‡ passer la dicultÈ ii RÈsumÈ : Ce travail a ÈtÈ rÈalisÈ dans le cadre des projets TACOS et CRISTAL qui ont pour but de construire un systËme des vÈhicules autonomes en libre-service Dans ce systËme, les vÈhicules peuvent se dÈplacer en convoi Nous partons d'une modÈlisation d'un convoi en CSPjjB Elle dÈcrit les processus internes des vÈhicules membres qui maintiennent la distance entre vÈhicules, de sorte que la propriÈtÈ de dÈplacement en convoi est conservÈe Le travail de stage a eu pour premier but de modÈliser en CSPjjB les processus internes des vÈhicules pour accrocher et dÈcrocher d'un convoi Nous avons amÈliorÈ le modËle existant pour avoir un nouveau modËle qui prÈsente les processus de quatre modes de fonctionnement : dÈplacement en convoi, dÈcrochage d'un convoi, dÈplacement indÈpendant et accrochage ‡ un convoi Un second axe a ÈtÈ consacrÈ ‡ la thÈorie de l'approche CSP jjB CSPjjB, qui apparait dans les annÈes 2000, est la combinaison de la mÈthode B et de l'algËbre CSP Elle n'est pas encore totalement achevÈe Une modÈlisation en CSP jjB comporte plusieurs composants CSPjjB Chaque composant CSPjjB contient une machine B et un contrÙleur CSP Il existe des outils pour vÈrier les machines B et leur contrÙleur CSP Cependant, il n'existe pas encore d'outil qui permet de vÈrier la cohÈrence entre la machine B et son contrÙleur CSP Nous avons construit un logiciel qui permet de rÈsoudre ce problËme Mots clÈs : CSPjjB, composants logiciel, platoon, vÈrication formelle Abstract : First, we want to model in CSPjjB the behavior of a vehicle when it joins or disjoins a platoon We extend a model of platoon in which members maintain the distance between them so that the form of the platoon is preserved However, the hooking and unhooking processes of a vehicle in a convoy are more complex We have a new model, written in CSP jjB, of platoons This models de-scribes all behaviors of vehicles : autonomous movement, joining a convoy, movement as a member of a convoy, and disjoining a convoy Second, our work addressed the practical implementation of the theory of the CSP jjB approach This approach, which appeared in 2000, is driven by the desire to exploit existing tool support for verifying both CSP and B specications and by the need for compositional proof techniques However, there is no tool for verifying the con-sistency between Bmachines and their CSP controler We built a tool to solve this problem Keywords : CSPjjB, software component, platoon, formal verication Table des matiËres Introduction 1.1 Contexte 1.2 Objectifs initiaux du stage 1.3 RÈsultats 1.4 Structure du rapport Approche CSPjjB 2.1 Introduction 2.1.1 2.1.2 2.2 CSP parallËle B 2.2.1 2.2.2 2.3 2.2.3 Discussion ModËle du systËme des vÈhicules 3.1 ModËle P LAT OON existant 3.2 SystËme des vÈhicules 3.2.1 3.2.2 3.3 Structure du code CSPjjB 3.3.1 3.3.2 3.3.3 3.4 VÈrication Table des matiËres 3.5 Discussion VÈrication de la cohÈrence entre la machine B et le contrÙleur CSP 4.1 CohÈrence entre la machine B 4.1.1 4.1.2 4.2 Comment Áa marche ? 4.3 Les problËmes ‡ rÈsoudre 4.3.1 4.3.2 4.3.3 4.3.4 4.4 Programmation en Ocaml 4.5 Test 4.6 Discussion Conclusion et perspectives Bibliographie A ModËle du systËme en CSP jjB A.1 DÈnitions gÈnÈrales A.1.1 Dene.csp A.1.2 A.2 Composant V ehicle A.2.1 Le contrÙleur CSP : V A.2.2 A.3 Composant DrivingSystem A.3.1 Le contrÙleur CSP : D Table des matiËres A.3.2 La machine B : DrivingSyst A.4 Composant N et A.4.1 Le contrÙleur CSP : Net.cs A.4.2 La machine B : Net.mch B La vÈrication des machines B C La vÈrication des contrÙleurs CSP D La vÈrication de la cohÈrence des composants D.1 La machine traduite du contrÙleur D.1.1 D.1.2 D.2 La machine traduite du contrÙleur D.2.1 D.2.2 D.3 La machine traduite du contrÙleur D.3.1 D.3.2 E Le traducteur E.1 PrÈ-requis E.2 Structure du projet E.3 Mode d'emploi E.4 Les modules E.4.1 Traiter des donnÈes E.4.2 Construire la machine abstr E.4.3 Éviter des non pertinences E.4.4 Éviter des homonymes E.4.5 Table des matiËres E.4.6 E.4.7 Table des gures 1.1 VÈhicules se dÈplacent en convoi 1.2 Modes des fonctionnement du systËme 2.1 DÈveloppement en B 2.2 Exemple de copie de donnÈe 2.3 Architecture CSPjjB 2.4 Architecture CSPjjB de Robot 2.5 La modÈlisation CSPjjB du Robot 3.1 ModËle du convoi sans Net 3.2 ActivitÈ de vÈhicule dans le convoi 3.3 ModËle du convoi avec Net 3.4 3.5 Structure en CSPjjB du Cristal SystËme des vÈhicules 3.6 Changement du mode 3.7 Cristal en CSPjjB 3.8 3.9 Structure du systËme en CSPjjB Composant V ehicle 3.10 Composant DrivingSystem 3.11 Composant N et 3.12 VÈrication de la machine B 3.13 VÈrication du contrÙleur CSP 4.1 Le prototype de la machine B traduite d'un contrÙleur C 4.2 Traduction de CSP en B 4.3 Exemple d'exÈcution Table des gures 4.4 Fichiers de codage 4.5 VÈrication de la cohÈrence entre la ma Chapitre Introduction Sommaire 1.1 Contexte 1.2 Objectifs initiaux du stage 1.3 RÈsultats 1.4 Structure du rapport D.3 La machine traduite du contrÙ WHEN cb = THEN / ManageJoint / 71 72 73 74 75 76 ANY requestPermissionJoint_platoon_id WHERE requestPermissionJoint_platoon_id IDS THEN VAR getPermissionJoint_permi IN getPermissionJoint_permigetPermissionJoint(Net_ref_Id, requestPermissionJoint_platoon_id); 77 78 79 IF getPermissionJoint_permi = YES THEN / Net_ref_Id := Net_ref_Id; / 80 81 82 83 84 85 86 cb := ELSE / Net_ref_Id := Net_ref_Id; / cb := END END END 87 88 89 WHEN cb = THEN / ManageJoint_process / VAR getVehicleInfo_speed, getVehicleInfo_xpos IN getVehicleInfo_speed, getVehicleIn 90 91 92 93 BEGIN CHOICE / Net_ref_Id := Net_ref_Id; / 94 95 96 cb := OR BEGIN END 103 104 105 106 107 END END END END 108 109 110 VAR getPermissionDisjoint_permi IN WHEN cb = 111 getPermissionDisjoint_permi 112 IF getPermissionDisjoint_permi = THEN 113 114 115 116 117 / Net_ref_Id := Net_ref_Id; / cb := ELSE / Net_ref_Id := Net_ref_Id; / cb := 118 119 120 121 122 123 WHEN cb = THEN / ManageDisjoint_process / VAR getVehicleInfo_speed, getVehicleInfo_xpos IN END END D.3 124 125 126 127 BEGIN CHOICE / Net_ref_Id := Net_ref_Id; / 128 129 130 cb := OR BEGIN END 137 138 139 140 141 142 143 144 END END END END END END END La machine traduite d getVehicleInfo_speed, getVe Annexe E Le traducteur E.1 PrÈ-requis Base thÈorique : Le projet a pour but de traduire du code CSP en texte B et de chercher la forme du CLI Il faut dont conntre : • la syntaxe des langage CSP et B, • la description de chiers mly et mll qui sont utilisÈs par l'outil ocamllex et ocamlyacc pour reconnaÓtre la syntaxe de langage CSP et B, • la thÈorie de CLI : les rËgles de traduction, la forme de CLI, qui se trouve dans la section 4.1 du rapport, • et le langage Ocaml, bien entendu Environnement : Nous avons dÈveloppÈ ce projet en Ocaml version 3.11.1, en utilisant Eclipse et le mode ocaml1 Le traducteur marche bien sous Ubuntu 8.04, 8.10, 9.04, 9.10 et sous WindowsXP Nous utilisons Ègalement les deux outils ocamllex et ocamlyacc qui sont inclus dans la distribution d'Ocaml E.2 Structure du projet Le code du projet est contenu dans le rÈpertoire src qui se compose de deux paquetages b et csp : http://ocamldt.free.fr/ E.3 Mode d'emploi src |- b |- main.ml |- affix.ml |- outil.ml |- b2pred.ml |- csp |- b2string.ml |-change_name.ml |- bbop.ml |- cli.ml |- blast_mk.ml |- csp2string.ml |- blast.ml |- csplexer.mll |- blexer.mll |- cspparser.mly |- bparser.mly |- csptypes.ml |- error.ml |- redondance.ml |- id_acc.ml |- variable.ml |- modules.ml • le paquetage csp a pour but d'analyser le contrÙleur CSP (qui est dans un chier csp), Èviter des non pertinences, eectuer le typage et chercher la forme du CLI Il comporte l'essentiel du traducteur • le paquetage b a pour but d'analyser la machine B (qui est dans un chier mch) E.3 Mode d'emploi Compilation En s'aidant d'Eclipse en Ocaml-mode, la compilation est rÈalisÈe automatiquement par un click de souris Le rÈsultat est le chier exÈcutable main qui se trouve dans le rÈpertoire bin/src Utilisation Un composant CSPjjB est dÈcrit dans deux chiers : X.csp pour le contrÙleur et X.mch pour la machine Il faut que les deux chiers portent le mÍme nom, par exemple, Vehicle.csp (pour le contrÙleur) et Vehicle.mch (pour la machine) Nous utilisons le chier main pour gÈnÈrer la machine de contrÙle ‡ partir de ce composant CSPjjB : /main Vehicle AprËs l'exÈcution, nous obtenons la machine de contrÙle Cette machine se compose de • la machine abstraite qui est dÈcrite dans le chier Vehicle_abs.mch • le ranement qui est dÈcrit dans le chier Vehicle_ref.ref E.4 Les modules E.4 Les modules E.4.1 Traiter des donnÈes Il faut d'abord dÈnir la structure d'un contrÙleur CSP (chier csptypes.ml ) et d'une machine B (chier blast.ml ) Par exemple : type csp = Include of string | Process of process and denition = 6Datatype of datatype 7| Nametype of nametype 8| Constant of constant 9| Channel of channel 10 11 | GroupeChannel of string ( string list ) Un contrÙleur CSP se compose de parties : Include (contient le nom du chier inclus), Dention (contient les dÈnitions nÈcessaires comme les types de don-nÈes, les prototypes de canaux, ) et Process (pour reprÈsenter les processus du contrÙleur) On va dÈtailler ces dÈnitions, comme la partie Denition dans cet exemple Quand on a dÈnit la structure d'un contrÙleur CSP, on peut dÈclarer une variable de ce type pour contenir les donnÈes d'un contrÙleur qui est lu de chier csp Le codage de processus de lecture du chier csp et le transfert du rÈsultat dans une variable est gÈrÈ automatiquement par les outils Ocamllex et Ocamlyacc Ces outils utilisent des chiers de descriptions mll et mly comme entrÈe Le chier mll contient la description du lexique et le chier mly contient la description de la grammaire ; pour CSP ( csplexer.ml et cspparser.mly ) et pour B (blexer.mll et manual-ocaml/manual026.html bparser.mly ) Il faut se rÈfÈrer ‡ cette adresse http://caml.inria.fr/pub/docs/ pour avoir le dÈtail de l'utilisation des outils AprËs cette Ètape, nous pouvons lire un chier ( mch ou csp) et obtenir le rÈsultat dans une variable Par exemple, aprËs ce morceau de codage, nous avons la variable amn qui contient la donnÈe de la machine qui est dÈcrite par le chier Vehicle.mch : print_string ("\nLecture du chier B : [ Vehicle mch]\n"); let amn = Bparser.amn Blexer.token (Lexing.from_channel (open_in ("Vehicle.mch"))) in print_string " ==i OK\n"; ush stdout; | Denition E.4 Les modules E.4.2 Construire la machine abstraite La machine abstraite est construite facilement : let write_machine_abs le_name ((name,params), clause) cproc_lst = 3let f = open_out (le_name ^ "_abs.mch") in 5let out = (Printf fprintf ) in let len = (List length cproc_lst) let spc = (get_space 1) in in out f "MACHINE %s_abs" le_name; 9if params hi then 10 11 12 13 let str = (B2string list2string ", " B2string id2string params) in out f "(%s)\n" str; else out f "\n"; 14 15 16 let rec print_clauses cl = if cl hi then 17 18 19 20 21 22 23 24 25 26 begin begin match List.hd(cl ) with Blast Constraints c ! out f "CONSTRAINTS\n%s %s\n" spc (B2string.predicat2string c) |_!() end; print_clauses ( List tl cl ) end in print_clauses clause ; 27 28 29 30 31 32 33 34 35 36 out f "VARIABLES\n%s cb\n" spc; out f "INVARIANT\n%s cb : %d\n" spc len; out f "INITIALISATION\n%s cb := 0\n" spc; out f "OPERATIONS\n"; out f "%sControls =\n" spc; out f "%sBEGIN cb :: %d END\n" spc len; out f "END\n"; ush f ;; Dans lequel, ((name; params); clause) reprÈsente la machine B avec le nom name, les paramËtres params et des substitutions clause ; cproc_lst reprÈsente une liste de processus CSP dans le contrÙleur AprËs cette Ètape, nous avons un chier indiquÈ par la variable file_name Ce chier contient la machine abstraite E.4 Les modules E.4.3 Éviter des non pertinences Cette partie du code est contenue dans le chier redondance.ml Nous dÈtaillons les fonctions dans ce chier : • D'abord, nous avons des fonctions pour dÈterminer la nÈcessitÈ des variables Par exemple, la fonction is_necessary_in_body prend une chaÓne string et une liste de process_body, elle retourne une value logique bool, elle a pour but de dÈterminer qu'une variable est nÈcessaire dans une liste de process_body val is_necessary_in_body : string ! Csptypes.process_body list ! bool val is_necessary_in_body_list : string ! Csptypes.process_body val is_necessary_in_ope : string ! Csptypes.process_body ! boo val is_necessary_in_channel : string ! string ! Csptypes.channel val is_necessary_in_expr_list : string ! Csptypes.expr list ! bool 10 11 val is_necessary_in_expr : string ! Csptypes.expr ! bool 12 13 14 15 val is_necessary_in_if : string ! Csptypes.expr ! Csptypes.process_body list ! Csptypes.process_body list ! bool 16 17 val is_necessary_in_lambda : string ! Csptypes.expr ! Csptypes.process_body list ! bool ◦ Ensuite, nous Èvitons les non pertinences val remove_redondance_in_body : Csptypes.process_body list ! Csptypes.process_body list val remove_redondance_in_body_list : Csptypes.process_body list list ! Csptypes.process_body list list val remove_redondance_in_ope : Csptypes.process_body ! 7Csptypes.process_body list ! Csptypes.process_body list val remove_redondance_in_channel : string ! list ! 10Csptypes.channel_param 11Csptypes.process_body list ! Csptypes.process_body list 12 13 14 15 16 17 val remove_redondance_in_process : string string list Csptypes.process_body list ! string bool list Csptypes.process_body list val remove_redondance : (string string list Csptypes.process_body list ) list ! ( string string list Csptypes.process_body list ) list E.4 Les modules E.4.4 Éviter des homonymes L'Èlimination des homonymes est traitÈe dans le chier change_name.ml • D'abord, nous construisons des fonctions pour changer le nom d'une variable dans les structures tel que : le corps du processus CSP ( change_name_variable_in_body), la liste de corps (change_name_variable_in_body_list), etc val change_name_variable_in_body : string ! string ! Csptypes.process_body list ! Csptypes process_body list val change_name_variable_in_body_list : string ! string ! Csptypes.process_body list list ! Csptypes.process_body list list val change_name_variable_in_ope : string ! string ! Csptypes.process_body ! Csptypes process_body val change_name_variable_in_expr : string ! string ! Csptypes.expr ! Csptypes.expr 10 11 12 val change_name_variable_in_channel : string ! string ! string Csptypes.channel_param list ! Csptypes.process_body 13 14 val change_name_variable_in_set : string ! string ! Csptypes set ! Csptypes set ◦ Ensuite, nous Èvitons des homonymes La fonction change_name_variable change_name_parametre_channel_in_body ajoute un prÈxe (string) avant des paramËtres d'un processus CSP La fonction ajoute un prÈxe (qui est le nom du canal) avant des paramËtres de chaque canal dans un processus CSP val change_name_variable : string ! (' a (' a val change_name_parametre_channel_in_body : Csptypes.process_body list ! Csptypes.process_body list E.4.5 Typage Tout le code est contenu dans le chier variable.ml Nous avons des fonctions pour chercher le type d'une variable Par exemple, la fonction get_type_from_body cherche le type de la variable dans un corps de processus CSP val get_type_from_body : string ! Csptypes.process_body list ! string val get_type_from_body_list : string ! Csptypes.process_body list list ! string E.4 Les modules val get_type_from_ope : string ! Csptypes.process_body ! string val get_type_from_channel : string ! string ! Csptypes.channel_param list ! string val get_type_from_expr_list : string ! Csptypes.expr list ! string 10 11 val get_type_from_expr : string ! Csptypes.expr ! string 12 13 val get_type_of_expr : string ! Csptypes.expr ! string 14 15 val get_type_from_denition : string ! string 16 17 18 19 val get_type_from_if : string ! Csptypes.expr ! Csptypes.process_body list ! Csptypes.process_body list ! string 20 21 val get_type_from_lambda : string ! Csptypes.expr ! Csptypes.process_body list ! string Avec les fonctions de base, nous construisons une fonction qui a pour but de chercher le type de toutes les variables globales Cette fonction retourne trois formes des variables qui sont utilisÈes dans la substitution VARIABLES, INVARIANT et INI-TIALISATION de la machine B : val get_variable_global : (' a string string string string list Csptypes.process_body list ) list ! E.4.6 Chercher la form CLI Nous avons la fonction get_cli_in_process_list pour chercher le CLI dans la liste de processus CSP du contrÙleur La fonction cli2string convertit le CLI trouvee par la fonction prÈcÈdente en une chaÓne de caractËres qui est Ècrite dans le chier de la machine de contrÙle Le code se trouve dans le chier cli.ml du paquet csp val get_cli_in_process_list : ( string ( Retourne une list de 4index: 'a) list ! ( string int string list ) list name : string (nom de processus) int 5( variable : string ) list CLI : ((cb = index) = i string list P( variable_list )) & ((cb = index) = i P( variable_list )) ) val cli2string : (' a int string list ) list ! string & E.4 Les modules E.4.7 Construire le ranement En utilisant les fonctions ci-dessus, nous pouvons construire le ranement de la machine de contrÙle : let rec write_renement le_name ((name,params), clause) cproc_lst cdef_lst = let f = open_out (le_name ^ "_ref.ref") in let out = (Printf fprintf ) in print_string "\n eliminer des non pertinences \n"; ush stdout ; let channel_communication_lst = get_channel_communication clause cdef_lst in ( Redondance ) Redondance.channel_communication_prototype := channel_communication_lst; let cproc_lst = Redondance.remove_redondance cproc_lst in 10 11 12 print_string "\n changer le nom des variables \n"; ush stdout ; ( changer les noms des variables) let cproc_lst = Change_name.change_name_variable (le_name ^ "_ref") cproc_lst in 13 14 15 16 17 print_string "\n ( Variable ) chercher les types des variables \n"; ush stdout ; let chan_lst = List map ( fun x ! match x with Csptypes.Channel (n,p) ! [(n,p)] | _ ! cdef_lst 18 in 19 20 Variable cdef_lst := cdef_lst ; Variable cchan_lst := List fold_left 21 let (var , inv , 22 23 24 25 print_string "\n (CLI) let cli = Cli.get_cli_in_process_list cproc_lst in let cli = Cli cli2string cli in 26 27 28 if cli hi "" then begin 29 30 31 print_string "Oui, il doit ajouter une invariance \n"; out f "/ \n"; 32 33 out f " Il faut ajouter une invariance \n CLI = %s\n" cli ; out f " /\n" end 34 else 35 print_string " Non, il n'a pas besoin d' ajouter une invariance \n"; 36 37 let bope = ref ( 38 let spc = (get_space 1) in 39 40 let params_str = if params hi ^ ")"); 42 else 43 45 46 47 then let str = (B2string list2string ", " B2string id2string params) in ("(" ^ str 41 44 : string list ) in "" in print_string "\n ecriture du chier de ranement \n"; ush stdout ; ) E.4 Les modules 48 49 out f "REFINEMENT %s_ref%s\n" le_name params_str; 50 51 out f "REFINES %s\n" (le_name ^ "_abs"); 52 53 out f "INCLUDES %s%s\n" le_name params_str; 54 55 56 let rec print_clauses cl = if cl hi then 57 58 59 begin begin match List.hd(cl ) with Blast Sees s out f "SEES\n%s %s\n" spc (B2string 60 61 62 63 64 65 66 67 68 69 | Blast Operations ope_lst ! bope := List map (fun (name, i, o, b) ! (B2string id2string name) ) ope_lst |_!() end; print_clauses ( List tl cl ) end in print_clauses clause ; 70 71 72 73 74 75 76 77 78 let clen = (List len out f "VARIABLES\n%scb%s\n" spc var; out f "INVARIANT\n%scb : %d%s\n" spc clen inv; out f "INITIALISATION\n%scb := 0%s\n" spc ini; out f "OPERATIONS\n"; out f "%sControls =\n" spc; out f "%sBEGIN\n" spc; let spc2 = (get_space 2) in 79 80 let cproc_arr = Array of_list cproc_lst in 81 82 83 Csp2string csp_process_prototype := cproc_lst; Csp2string channel_communication_prototype := channel_communication_lst; 84 85 86 87 88 for i =0 to clen let (name, params, body) = cproc_arr.(i) in if i =0 then out f "%sSELECT cb = THEN / %s / \n" spc2 name 89 else 91 92 93 ; 90 let lst = Csp2string process_operation_list body in List iter (fun x ! (out f "%s%s" spc2 x)) lst ; 94 95 done; out f "\n%sWHEN cb = %d TH 96 97 98 99 out f "%sEND\n" spc2; out f "%sEND\n" spc; out f "END\n"; ush f E.4 Les modules ... industrielle et ‡ l'ensemble du cycle de dÈveloppement En 1996, J.R.ABRIAL a prÈsentÈ The B Book[1] qui est le premier ouvrage de rÈfÈrence sur B Le processus de dÈveloppement en B est prÈsentÈ dans la... ranement d'un ensemble par un tableau) Ces deux types de ranement ne sont pas exclusifs : ils peuvent appartre dans la mÍme Ètape de ranement Il est Èvident que tout ranement de donnÈes entraÓne... de la cohÈrence entre la machine B et le contrÙleur CSP 4.1 CohÈrence entre la machine B et son contrÙleur CSP 4.1 CohÈrence entre la machine B et son contrÙleur CSP La cohÈrence entre la machine

Ngày đăng: 30/10/2020, 21:20

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w