Today is my 74th birthday. This Engineering Notebook post is my birthday present to myself.
For the last week, I have been trying to make paste-retaining-clones work. Unit tests show this command improperly computes v.parents arrays in the pasted outline.
This morning I saw the way forward:
Aha! paste-retaining-clones must recompute all v.parents arrays in the entire outline!
I won't attempt a formal proof, but I am sure this Aha is correct. Note that the paste-node command does not require the complications described next.
Recomputing v.parents
But how to recompute v.parents?
Aha! Define a c.all_vnode_positions generator. This hybrid generator will yield VNodes in the same order as p.all_positions using neither v.parents nor Positions.
Is it possible to write this generator? Yes, it is. The generator will maintain an explicit stack just like Position.stack. Note: c.all_vnode_positions must yield the hidden root VNode.
Recomputing all v.parents
Supposing the new generator exists, recomputing all v.parents arrays is straightforward. Something like this (untested):
for v in c.all_vnode_positions():
v.parents = []
for v in c.all_vnode_positions():
for child in v.children:
child.parents.append(v)
Yes, a one-pass solution is possible. It might be faster.
Summary
Aha! The paste-retaining-clones command must recompute all v.parents ivars. This recomputation is sound. The link correction in c.checkVnodeLinks is not.
Leo can use neither Position nor VNode generators to do the recomputation.
Aha! A new generator, c.all_vnode_positions, will yield all VNodes in outline order using neither v.parents nor Positions.
Given this generator, updating all v.parents ivars will be straightforward.
Edward
P.S. Let us define a hybrid generator as a generator yielding VNodes in the same order as some Position generator without using Positions.
Could Leo replace Position generators with hybrids? I think not. For example, please take a look qtree.full_redraw. It would not be fun to eliminate Positions there.
In any event, Leo's Position class is never going away :-)
EKR
Well, Happy Birthday Edward! ;-)
> Is it possible to write [c.all_vnode_positions]?
You bet:
def all_vnode_positions(self) -> Generator:
c = self
to_be_visited: list[VNode] = [c.hiddenRootNode]
while to_be_visited:
v = to_be_visited.pop()
yield v
for child in reversed(v.children):
to_be_visited.append(child)
This generator passes the following consistency test:
vnodes1 = [c.hiddenRootNode] + [z.v for z in c.all_positions()]
vnodes2 = list(c.all_vnode_positions())
assert vnodes1 == vnodes2
Edward
Today is my 74th birthday. This Engineering Notebook post is my birthday present to myself.
>> Is it possible to write [c.all_vnode_positions]?
> You bet: [snip]
> This generator passes the following consistency test:
vnodes1 = [c.hiddenRootNode] + [z.v for z in c.all_positions()]
vnodes2 = list(c.all_vnode_positions())
assert vnodes1 == vnodes2
The elegance of this VNode-based stand-in for c.all_positions raises some follow-on questions.
Does c.all_positions use v.parents?
Apparently not, which means that c.all_vnode_positions isn't strictly necessary. Leo could define it like this:
def all_vnode_positions(self):
c = self
yield c.hiddenRootNode
for p in c.all_positions():
yield p.v
But this definition would be much worse than a VNode-based definition.
c.alt_all_positions
Could Leo define a generator, say c.alt_all_positions, using c.all_vnode_positions as a template? Yes it could.
In my original post, I said, "[c.all_vnode_positions] will maintain an explicit stack just like Position.stack." In fact, the generator uses only a stack of VNodes. But c.alt_all_positions must indeed use a stack just like Position.stack.
c.all_positions calls p.moveToThreadNext to advance through the outline. In turn, p.moveToThreadNext calls p.moveToParent, p.moveToFirstChild and p.moveToNext.
c.alt_all_positions will use none of these helpers. Instead, the new generator will operate directly on its explicit stack, yielding new positions with (copies of) the explicit stack. There will be no need for a "copy" kwarg.
Summary
c.alt_all_positions is feasible. Similarly, Leo could define other "alt" generators.
Alt generators should be faster (and use less memory) than the corresponding legacy generators.
Nevertheless, Positions themselves and all Position methods must remain, whatever their internal form.
Edward
Best wishes on your birthday from this quarter, too!
Edward, I also want to join my voice to the group in wishing you a happy birthday! :DSo Happy Birthday, Edward!
Another year older, but your programming prowess keeps getting younger!
Cheers to you and the adventures your code will take us on! 🚀
Edward, I also want to join my voice to the group in wishing you a happy birthday! :D
Another one joining late - but - still in time ;-)
Enjoy your birthday exactly the way you prefer to !
I'm a person who is not good at expression, but I hired GPT4 to express my meaning.
With a soul for scripting and heart born for nodes,Another one:
In the realm of the Leonine World, among the stellar nodes,I like them both :D
Today is my 74th birthday. This Engineering Notebook post is my birthday present to myself.
- We can't use VNode generators because they don't yield VNodes in outline order.
> I really don't know where did you get this idea from?
> I'm a person who is not good at expression, but I hired GPT4 to express my meaning.