Plánujeme nové API pro (nový) Treex. Mělo by jít implementovat ve více jazycích, sami bychom chtěli implementovat asi Perl, Python, Java, C++. Implementační poznámky jsou zde [[treex:api-implementation]] ref attributes: scalar: a/lex.rf, src/tnode list: a/aux.rf, , coref/*, align/* ===== Node ===== === Primary methods === get_attr set_attr get_bundle -> bundle remove get_referencing_nodes create_child get_parent -> parent set_parent (defaultně kontroluje, aby nevznikl cyklus) get_children === Word-order methods === precedes($another_node) get_next_node -> next_node() get_prev_node -> prev_node() shift_after_node($reference_node, {without_children=>1}) shift_after_subtree($reference_node, {without_children=>1}) shift_before_node($reference_node, {without_children=>1}) shift_before_subtree($reference_node, {without_children=>1}) is_nonprojective($reference_node, {without_children=>1}) === New methods === sentence -- vrátí string věty, smí se volat pouze na technickém kořenu set_sentence === Derived methods === language selector get_document get_root is_root is_leaf get_descendants -> descendants get_siblings -> siblings get_left_neighbor -> prev_sibling get_right_neighbor -> next_sibling is_descendant_of get_depth -> depth get_address -> address === NEzachovat === [sg]et_deref_attr -- budeme ukládat rovnou reference na uzel, nikoli ID get_zone -- zony zrusime remove_reference -- interní pro mazání uzlů fix_pml_type get_pml_type_name get_layer dominates generate_new_id following get_attrs add_to_listattr -- nepoužívá se === Questionable === to_string equals get_aligned_nodes get_aligned_nodes_by_tree get_aligned_nodes_of_type is_aligned_to delete_aligned_node add_aligned_node update_aligned_nodes ===== Mají children/descendants/siblings vracet pole, či iterable? ===== * Současné ''get_children()'' i ''get_descendants()'' vrací pole, které se ale musí vždy znovu alokovat (je tedy mutable, ale změny tohoto pole neovlivní původní strom). To je z hlediska rychlosti neoptimální, lepší by bylo vracet iterable objekt, jak je Javě (collection) a Pythonu zvykem. * Pokud někdo bude to pole potřebovat (třeba proto, že chce strom měnit, ale toto pole má zůstat neměnné), tak to lze vždy snadno zařídit (v Pythonu ''list(node.children())''). Výhodou Javy a Pythonu (oproti Perlu) je, že jde iterovat for cyklem i přes collection/iterátor (a v Pythonu je ještě efektivnější list comprehension, protože to jede celé rychlostí céčkového kódu). * Další výhodou iterátorů je, že někdy nepotřebuji ani projít všechny prvky toho pole, ale hledám první prvek, který splní nějakou podmínku (short circuit). * Pokud by implementace měla ke každému uzlu v paměti alokované pole dětí a potomků (a sourozenců), tak by samozřejmě šlo vrátit přímo toto pole (a nebylo by to pomalejší než iterátory). Ale buď by se to pole mělo udělat immutable, nebo by se muselo zajistit, že se naopak správně upraví celý strom (v případě přidání uzlu do ''children'' či ''siblings'' si to lze představit, v případě ''descendants'' ne, protože není jasné, kam ten nový uzel zavěsit). * Na druhou stranu v některých implementacích bude potřeba při každém zavolání ''descendants()'' vytvořit nové pole (aby se setřídilo perlsortem/timsortem inplace, kvůli neprojektivitám, viz dále). To pole sice je taky iterable (a lze z něj snadno vyrobit iterátor), ale když uživatel zavolá ''potomci = list(node.descendants())'', tak naopak vytvoří zbytečnou kopii (protože v této implementaci už ''node.descendants()'' vrací nové pole). ===== Mají children/descendants/siblings být metoda, či property? ===== * Tohle je trochu Python-specific. Pokud by to bylo předpočítané, tak by to mohlo být property, tedy by se "ušetřilo" psaní prázdných závorek: ''potomci = node.descendants''. * Jenže asi budeme chtít přidávat parametry, a to u properties nejde. Takže z hlediska API jsem pro metody: ''potomci = node.descendants()''. ===== Mají children/descendants/siblings vracet setříděné uzly? ===== * Současné řešení vrací uzly v nedefinovaném pořadí (u descendant průchodem do hloubky, děti pak v pořadí vložení), takže když chci pořadí dle (povrchového) slovosledu, musím zavolat ''get_children({ordered=>1})''. To je dost nešikovné, protože na to člověk často zapomene, na většině vět to funguje (pořadí dle vložení se většinou shoduje se slovosledným), ale pak ne a těžko se to debugguje. * V současných zdrojácích bloků Treexu je 909 volání ''get_descendants'' a 405 z nich je ''ordered'' (jak často se které volání používá teď neberu v potaz). Navíc 455 bloků používá ''process_[at]node'', která vyžaduje ''get_descendants({ordered=>1})''. U ''get_children'' je to ordered/vše=95/598 a u ''get_siblings'' 2/46. Závěr: setřídění uzlů je potřeba velmi často (byť někde mohlo být to ordered přidáno preventivně a vlastně to potřeba není, viz předchozí bod). * Ve zdrojácích je 241 volání metod ''shift_(before|after)_(node|subtree)''. Část z toho je volání hned po přidání nového uzlu. Změna slovosledu je tedy častá. Mám ale pocit, že v typickém scénáři (t-analýza, překlad) se mění slovosled mnohem méně často, než jak často se přistupuje k setříděným dětem/potomkům (chtělo by to profiling pro přesná čísla). * U ''children'' a ''siblings'' by rozumná implementace měla udržovat seznam pořád setříděný (teď se pokaždé volá ''sort''), takže by parametr ''ordered'' mohl z API zmizet. * U ''descendants'' je situace složitější, protože u neprojektivních stromů nejde správné pořadí potomků získat průchodem do hloubky. Viz [[treex:api-implementation#setrideni-dle-ord|poznámky k implementaci setřídění]].