Table of Contents
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 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()
iget_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
čisiblings
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 jeordered
(jak často se které volání používá teď neberu v potaz). Navíc 455 bloků používáprocess_[at]node
, která vyžadujeget_descendants({ordered⇒1})
. Uget_children
je to ordered/vše=95/598 a uget_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
asiblings
by rozumná implementace měla udržovat seznam pořád setříděný (teď se pokaždé volásort
), takže by parametrordered
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 poznámky k implementaci setřídění.