Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I will provide a partial solution, but the one that could get you started. I will use the mutable tree data structure from <a href="https://stackoverflow.com/questions/6097071/tree-data-structure-in-mathematica/6097444#6097444">this</a> post, since it seems like mutability is natural for this problem. Repeating it for convenience here:</p> <pre><code>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; ]; </code></pre> <p>Here is the code to create a mutable tree from any Mathematica expression, and read the expression back from the tree:</p> <pre><code>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] &amp;, root.getChildren[]]]; Clear[indexNodes]; indexNodes[root_node] := Module[{i = 0}, traverse[root, #.setValue[{i++, #.getValue[]}] &amp;]]; Clear[makeExpressionTree]; makeExpressionTree[expr_] := With[{root = makeExpressionTreeAux[expr]}, indexNodes[root]; root]; </code></pre> <p>You can test on simple expressions like <code>a+b</code>. A few comments on how this works: to create a mutable expression tree (built of <code>node</code>-s) from an expression, we call the <code>makeExpressionTree</code> function, which first creates the tree (call to <code>makeExpressionTreeAux</code>), and then indexes the nodes (call to <code>indexNodes</code>). The <code>makeExpressionTree</code> function is recursive, it recursively traverses the expression tree while copying its structure to the structure of the resulting mutable tree. One subtle point here is why we need things like <code>val = Hold[Evaluate[Unique[]]]</code>, <code>nd.setValue[val];</code>, <code>Evaluate[val[[1]]] = expr;</code> rather than just <code>nd.setValue[expr]</code>. This is done with <code>InputField[Dynamic[some-var]]</code> in mind - for this, we need a variable to store the value (perhaps, one could write a more custom <code>Dynamic</code> to avoid this problem if one likes). So, after the tree is created, each node contains a value that is <code>Hold[someSymbol]</code>, while <code>someSymbol</code> contains the value of an atom, or of a head, for non-atomic sub-part. The indexing procedure changes the value of each node from <code>Hold[sym]</code> to <code>{index,Hold[symbol]}</code>. Note that it uses the <code>traverse</code> function which implements the generic depth-first mutable tree traversal (similar to <code>Map[f,expr, Infinity]</code>, but for mutable trees). Therefore, indexes are incremented in depth-first order. Finally, the <code>expressionFromTree</code> function traverses the tree and builds the expression that the tree stores.</p> <p>Here is the code to render the mutable tree:</p> <pre><code>Clear[getGraphRules]; getGraphRules[root_node] := Flatten[ Map[Thread, Rule @@@ Reap[traverse[root, Sow[{First[#.getValue[]], Map[First[#.getValue[]] &amp;, #.getChildren[]]}] &amp;]][[2, 1]]]] Clear[getNodeIndexRules]; getNodeIndexRules[root_node] := Dispatch@ Reap[traverse[root, Sow[First[#.getValue[]] -&gt; #] &amp;]][[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 -&gt; (Inset[ InputField[Dynamic[#2], FieldSize -&gt; 10] /. makeSymbolRule[#2 /. ndrules], #] &amp;)]]; </code></pre> <p>This part works as follows: the <code>getGraphRules</code> function traverses the tree and collects parent-child pares of node indices (in the form of rules), the resulting set of rules is what the <code>GraphPlot</code> expects as a first argument. The <code>getNodeIndexRules</code> function traverses the tree and builds the hash table where keys are node indices and values are the nodes themselves. The <code>makeSymbolRule</code> function takes the node and returns the delayed rule of the form <code>index:&gt;node-var-symbol</code>. It is important that the rule is delayed, so that the symbols do not evaluate. This is used to insert the symbol from the node tree into <code>InputField[Dynamic[]]</code>. </p> <p>Here is how you can use it: first create a tree:</p> <pre><code>root = makeExpressionTree[(b + c)*d]; </code></pre> <p>Then render it:</p> <pre><code>renderTree[root] </code></pre> <p>You must be able to modify data in each input field, although it takes a few clicks to make the cursor appear there. For example, I edited <code>c</code> to be <code>c1</code> and <code>b</code> to be <code>b1</code>. Then, you get the modified expression:</p> <pre><code>In[102]:= expressionFromTree[root] Out[102]= (b1 + c1) d </code></pre> <p>This solution handles only modifications, but not removal of nodes etc. It can however be a starting point, and be extended to cover that as well. </p> <p><strong>EDIT</strong></p> <p>Here is a much shorter function, based on the same ideas but not using the mutable tree data structure.</p> <pre><code>Clear[renderTreeAlt]; renderTreeAlt[expr_] := Module[{newExpr, indRules, grules, assignments, i = 0, set}, getExpression[] := newExpr; newExpr = expr /. x_Symbol :&gt; set[i++, Unique[], x]; grules = Flatten[ Thread /@ Rule @@@ Cases[newExpr, set[i_, __][args___] :&gt; {i, Map[If[MatchQ[#, _set], First[#], First[#[[0]]]] &amp;, {args}]}, {0, Infinity}]]; indRules = Dispatch@ Cases[newExpr, set[ind_, sym_, _] :&gt; (ind :&gt; sym), {0, Infinity}, Heads -&gt; True]; assignments = Cases[newExpr, set[_, sym_, val_] :&gt; set[sym , val], {0, Infinity},Heads -&gt; True]; newExpr = newExpr /. set[_, sym_, val_] :&gt; sym; assignments /. set -&gt; Set; TreePlot[grules, VertexRenderingFunction -&gt; (Inset[ InputField[Dynamic[#2], FieldSize -&gt; 10] /. indRules, #] &amp;)] ] </code></pre> <p>Here is how you use it:</p> <pre><code>renderTreeAlt[(a + b) c + d] </code></pre> <p>You can call <code>getExpression[]</code> at any time to see the current value of expression or assign it to any variable, or you can use </p> <pre><code>Dynamic[getExpression[]] </code></pre> <p>This method yields much shorter code since the Mathematica native tree structure is reused as a skeleton for the tree, where all informative pieces (heads and atoms) were replaces by symbols. This is still a mutable tree as long as we have access to original symbols and not just their values, but we don't need to think about building blocks for the tree - we use expression structure for that. This is not to diminish the previous longer solution, conceptually I think it is more clear, and it is probably still better for more complicated tasks.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload