Kısmi bir çözüm sunacağım, ancak başlamanıza neden olabilecek olanı. Bu sorun için doğal mutabilite gibi göründüğünden, değişebilir ağaç veri yapısını this gönderiminden kullanacağım. Burada kolaylık için tekrarlanması:
Clear[makeExpressionTreeAux];
makeExpressionTreeAux[expr_?AtomQ] :=
With[{nd = new[node[]], val = Hold[Evaluate[Unique[]]]},
nd.setValue[val];
Evaluate[val[[1]]] = expr;
nd];
makeExpressionTreeAux[expr_] :=
With[{nd = new[node[]], val = Hold[Evaluate[Unique[]]]},
nd.setValue[val];
Evaluate[val[[1]]] = Head[expr];
Do[nd.addChild[makeExpressionTreeAux[expr[[i]]], i], {i, Length[expr]}];
nd];
Clear[expressionFromTree];
expressionFromTree[nd_node] /; nd.getChildren[] == {} := (nd.getValue[])[[-1, 1]];
expressionFromTree[nd_node] :=
Apply[(nd.getValue[])[[-1, 1]], Map[expressionFromTree, nd.getChildren[]]];
Clear[traverse];
traverse[root_node, f_] :=
Module[{},
f[root];
Scan[traverse[#, f] &, root.getChildren[]]];
Clear[indexNodes];
indexNodes[root_node] :=
Module[{i = 0},
traverse[root, #.setValue[{i++, #.getValue[]}] &]];
Clear[makeExpressionTree];
makeExpressionTree[expr_] :=
With[{root = makeExpressionTreeAux[expr]},
indexNodes[root];
root];
Sen gibi basit ifadeleriyle ilgili test edebilirsiniz: İşte
Module[{parent, children, value},
children[_] := {};
value[_] := Null;
node /: new[node[]] := node[Unique[]];
node /: node[tag_].getChildren[] := children[tag];
node /: node[tag_].addChild[child_node, index_] :=
children[tag] = Insert[children[tag], child, index];
node /: node[tag_].removeChild[child_node, index_] :=
children[tag] = Delete[children[tag], index];
node /: node[tag_].getChild[index_] := children[tag][[index]];
node /: node[tag_].getValue[] := value[tag];
node /: node[tag_].setValue[val_] := value[tag] = val;
];
geri ağacından ifadesini herhangi Mathematica ifadeden bir değişken ağacı oluşturmak ve okumak için kod edilir
a+b
. Bunun nasıl çalıştığına dair birkaç yorum: bir ifadeden bir değişken ifade ağacı oluşturmak için (
node
-s)
makeExpressionTree
işlevini çağırırız; ilk önce ağacı oluşturur (
makeExpressionTreeAux
çağrısı) ve sonra düğümleri dizinler.
indexNodes
).
makeExpressionTree
işlevi, yinelemeli olup, yapısını sonuçta ortaya çıkan değişebilir ağacın yapısına kopyalarken, ifade ağacını yinelemeli olarak çaprazlar. Burada bir ince nokta, sadece
nd.setValue[expr]
yerine
val = Hold[Evaluate[Unique[]]]
,
nd.setValue[val];
,
Evaluate[val[[1]]] = expr;
gibi şeylere ihtiyacımızın nedeni. Bu akılda
InputField[Dynamic[some-var]]
ile yapılır - bunun için, değeri saklamak için bir değişkene ihtiyacımız var (belki de bir tane daha hoşlanırsa bu sorunu önlemek için daha özel bir
Dynamic
yazabiliriz). Bu nedenle, ağaç oluşturulduktan sonra, her düğüm
Hold[someSymbol]
,
someSymbol
ise atom olmayan alt bölüm için bir atomun veya bir başlığın değerini içerir. Endeksleme prosedürü, her bir düğümün değerini
Hold[sym]
'dan
{index,Hold[symbol]}
'a değiştirir. Genel derinlik-ilk değişken ağaç geçişini uygulayan
traverse
işlevini kullandığını unutmayın (
Map[f,expr, Infinity]
'a benzer, ancak değiştirilebilir ağaçlar için). Bu nedenle, indeksler derinlik-birinci sırada artırılır. Son olarak,
expressionFromTree
işlevi, ağacı çaprazlar ve ağacın depoladığı ifadeyi oluşturur.
Burada değişken ağaç işlemek için kodudur:
Clear[getGraphRules];
getGraphRules[root_node] :=
Flatten[
Map[Thread,
Rule @@@
Reap[traverse[root,
Sow[{First[#.getValue[]],
Map[First[#.getValue[]] &, #.getChildren[]]}] &]][[2, 1]]]]
Clear[getNodeIndexRules];
getNodeIndexRules[root_node] :=
[email protected] Reap[traverse[root, Sow[First[#.getValue[]] -> #] &]][[2, 1]];
Clear[makeSymbolRule];
makeSymbolRule[nd_node] :=
With[{val = nd.getValue[]},
RuleDelayed @@ Prepend[Last[val], First[val]]];
Clear[renderTree];
renderTree[root_node] :=
With[{grules = getGraphRules[root],
ndrules = getNodeIndexRules[root]},
TreePlot[grules, VertexRenderingFunction ->
(Inset[
InputField[Dynamic[#2], FieldSize -> 10] /.
makeSymbolRule[#2 /. ndrules], #] &)]];
şöyle bu bölümü çalışır: getGraphRules
fonksiyon ağaç boyunca ilerleyen ve (kurallar şeklinde) ebeveyn-çocuk düğüm endekslerinin pares toplar, Ortaya çıkan kurallar, ilk argüman olarak GraphPlot
'un ne beklediğidir. getNodeIndexRules
işlevi, ağacı geçirir ve anahtarlar düğümü ve değerlerin düğümlerin kendileri olduğu karma tabloyu oluşturur. makeSymbolRule
işlevi, düğümü alır ve index:>node-var-symbol
formunun gecikmeli kuralını döndürür. Kuralın ertelenmesi önemlidir, böylece semboller değerlendirilmez. Bu, düğümü ağaçtan InputField[Dynamic[]]
'a eklemek için kullanılır. İlk ağacı oluşturmak:
root = makeExpressionTree[(b + c)*d];
Sonra işlemek: Burada
kullanmadan nasıl
renderTree[root]
Tek gereken karşın, her giriş alanına verileri değiştirmek gerekir İmlecin orada görünmesi için birkaç tıklama. Örneğin, c1
ve b
olmak üzere c
'u b1
olarak düzenledim. Daha sonra, değiştirilmiş ifade almak:
In[102]:= expressionFromTree[root]
Out[102]= (b1 + c1) d
Bu çözelti Bununla birlikte, bir başlangıç noktası olabilir, ve aynı zamanda bu kapsayacak şekilde genişletilebilir tek değişiklik, ancak düğüm vb kaldırılmasını ele alır.
DÜZENLEME İşte
aynı fikirleri ancak değişken ağaç veri yapısını kullanmayan tabanlı çok daha kısa bir fonksiyonudur. İşte
Clear[renderTreeAlt];
renderTreeAlt[expr_] :=
Module[{newExpr, indRules, grules, assignments, i = 0, set},
getExpression[] := newExpr;
newExpr = expr /. x_Symbol :> set[i++, Unique[], x];
grules =
Flatten[ Thread /@ Rule @@@
Cases[newExpr, set[i_, __][args___] :>
{i, Map[If[MatchQ[#, _set], First[#], First[#[[0]]]] &, {args}]},
{0, Infinity}]];
indRules = [email protected]
Cases[newExpr, set[ind_, sym_, _] :> (ind :> sym), {0, Infinity}, Heads -> True];
assignments =
Cases[newExpr, set[_, sym_, val_] :> set[sym , val], {0, Infinity},Heads -> True];
newExpr = newExpr /. set[_, sym_, val_] :> sym;
assignments /. set -> Set;
TreePlot[grules, VertexRenderingFunction -> (Inset[
InputField[Dynamic[#2], FieldSize -> 10] /. indRules, #] &)]
]
Kullanmaya nasıl:
renderTreeAlt[(a + b) c + d]
Sen ifadenin geçerli değerini görmek veya herhangi bir değişkene atamak için herhangi bir zamanda getExpression[]
arayabilir, ya da kullanabileceğiniz
Dynamic[getExpression[]]
Bu yöntem, Mathematica yerel ağaç yapısı ağaç için bir iskelet olarak yeniden kullanıldığından, tüm bilgilendirici parçaların (başlıklar ve atomlar) sembollerle yer değiştirdiği için çok daha kısa kodlar sağlar. Bu, orijinal sembollere ve sadece onların değerlerine erişemediğimiz sürece hala değişmez bir ağaçtır, ancak ağaç için yapı taşlarını düşünmemize gerek yoktur - bunun için ifade yapısını kullanırız. Bu, önceki daha uzun çözümü azaltmak değil, kavramsal olarak daha net olduğunu düşünüyorum ve muhtemelen daha karmaşık görevler için daha iyi.
Doğal yolun XXX/Link'i ve bunun gibi bir şeyi kullanması olduğunu düşünüyorum. Http://orange.biolab.si/doc/catalog10/Classify/InteractiveTreeBuilder.htm (Yani, sadece arabirim değil, sınıflandırma kısmı) –
Bize bu özel amaçları aydınlatır mısınız? Bunun nasıl faydalı olabileceğini hayal etmekte zorlanıyorum. –
@Sjoerd, özür dilerim, size şimdiden cevap vermeyi unuttum. Hiç büyük planım yok, sadece zaman zaman yararlı olabilecek bir alternatif. MathCAD, SPICE ve (diğerlerini hatırlayamıyorum), görsel blok montaj paradigması kullanan başka problemler var. Genel programlama için sıkıcı olurdu, ama yeri var. –