Как проще всего построить дерево разложения в системе Mathematica?

Я хотел бы построить «дерево разложения» в системе Mathematica.

У меня есть функция f, которая принимает объект и возвращает все компоненты этого объекта в виде списка. Для целей этого вопроса давайте просто разложим выражения Mathematica следующим образом (мой реальный f полагается на внешнюю базу данных для декомпозиции различных типов объектов, поэтому я не могу легко опубликовать его):

f[e_?AtomQ] := {}
f[e_] := List @@ e

Я хотел бы создать древовидный график, который показывает, как объект декомпозируется по мере того, как мы рекурсивно продолжаем применять f. В конкретном примере f выше мы должны получить что-то очень похожее на результат TreeForm, за исключением того, что на каждом узле должно отображаться полное выражение (а не только заголовок). Дочерние элементы узла будут его компонентами, возвращенными f.

Обратите внимание, что элементы могут повторяться в дереве разложения, как это, но не элементы повторяются в выходных данных TreePlot, поскольку он работает с графиками. Одна из идей - создать уникальное «внутреннее имя» для каждого узла, построить график и использовать TreePlot, настроив его для отображения фактической формы узлов, а не их «внутреннего имени».


person Szabolcs    schedule 13.04.2011    source источник


Ответы (2)


Как насчет этого?

tf[x_] := f[x] /. {{} :> x, r_ :> x @@ tf /@ r}

пример использования

Если какой-либо из терминов не является инертным, этот «простой» (?) Подход не будет работать.

person WReach    schedule 13.04.2011
comment
В некотором смысле хакерское, но это простое решение, на которое я надеялся. И объекты, которые я разлагаю, хранятся в виде строк, поэтому они очень подходят (без случайной оценки). - person Szabolcs; 14.04.2011
comment
Можете ли вы предложить способ, совместимый с этим решением, для изменения шрифта узлов? (Требуется для отображения глифов, отсутствующих в шрифте по умолчанию.) - person Szabolcs; 05.05.2011
comment
@Szabolcs Вы можете использовать параметр VertexRenderingFunction в TreeForm, чтобы получить полный контроль над внешним видом узла, например VertexRenderingFunction->(Inset[Framed[Style[#2, FontFamily->"Webdings"], Background->LightYellow], #1]&). - person WReach; 05.05.2011
comment
ах, так очевидно! Я все время шел по ложному пути, пытаясь напрямую манипулировать узлами ... - person Szabolcs; 05.05.2011

Я не уверен, что он отвечает на ваш вопрос, но вот как я бы реализовал рудиментарный TreeForm:

decompose[expr_?AtomQ] := expr
decompose[expr_] := Block[{lev = Level[expr, {1}]},
  Sow[Thread[expr -> lev]]; decompose /@ lev;]

treeForm[expr_] := Reap[decompose[expr]][[-1, 1]] // Flatten

Потом:

введите описание изображения здесь

РЕДАКТИРОВАТЬ Да, вы правы, это не дерево. Чтобы сделать его деревом, каждое выражение должно иметь свою позицию. Примерно так:

ClearAll[treePlot, node, decompose2];
SetAttributes[{treePlot, node, decompose2}, HoldAll];
decompose2[expr_] /; AtomQ[Unevaluated[expr]] := node[expr];
decompose2[expr_] := Module[{pos, list},
  pos = SortBy[
    Position[Unevaluated[expr], _, {0, Infinity}, Heads -> False], 
    Length];
  list = Extract[Unevaluated[expr], pos, node];
  list = MapThread[Append, {list, pos}];
  ReplaceList[
   list, {___, node[e1_, p1_], ___, node[e2_, p2_], ___} /; 
     Length[p2] == Length[p1] + 1 && 
      Most[p2] == p1 :> (node[e1, p1] -> node[e2, p2])]
  ]

потом

treePlot2[expr_] := 
 Module[{data = decompose2[a^2 + Subscript[b, 2] + 3 c], gr, vlbls},
  gr = Graph[data];
  vlbls = Table[vl -> (HoldForm @@ {vl[[1]]}), {vl, VertexList[gr]}];
  Graph[data, VertexLabels -> vlbls, ImagePadding -> 50]
  ]

введите описание изображения здесь

person Sasha    schedule 13.04.2011
comment
ваш сюжет на самом деле не является деревом, так как оба a^2 и b_2 имеют край, указывающий на один и тот же узел с меткой 2. Это как раз и есть проблема (и почему я упомянул, что, возможно, необходимо использовать внутреннее имя for node): мне нужно ветвление на каждом шаге, и элементы могут повторяться в дереве. Здесь у нас должно быть два узла, помеченных 2, один ответвляется от a^2, другой - от b_2. - person Szabolcs; 13.04.2011
comment
Это отличное кодирование, но есть небольшая ошибка. Функция treeplot2 должна читать: Module [{data = decopose2 [expr], gr, vlbls}, gr = Graph [data]; vlbls = Таблица [vl - ›(HoldForm @@ {vl [[1]]}), {vl, VertexList [gr]}]; График [данные, VertexLabels - ›vlbls, ImagePadding -› 50]], - person mathlawguy; 20.01.2013