Closed 46bit closed 7 years ago
I've solved many of the issues I mused about above.
I'm keeping "pick terminals and nonterminals yourself." I renamed those to leaf and branch based upon Terminology_used_in_Trees on Wikipedia.
As regards custom deriving nodes, it seems possible. I'd need a separate crate for that. I'd also need to require all types named in the Tree
-implementing enums to be either Tree
or rand::Rand
. Presumably Self
would be used as Tree
and all other included types as Rand
.
For now custom deriving exceeds requirements. I don't know what I have yet, so a solid day of engineering on pure convenience would be a mistake.
The
Tree
trait is very powerful and would seem sufficiently so to build a Rust form of DEAP. However the naming is unclear or raises issues. In addition it is still improvised around the constraints to-hand.Tree::rand_terminal
Tree::rand_terminal
is an accurate name. The name matches the expectation that it returns a leaf node of some sort.But it is a bad name. Originally, when I was trying to be reminiscent of Rust Quickcheck's
Arbitrary
API, this was namedarbitrary_terminal
. That name was closer to what I desire: the chosen terminal does not need to be random; in fact I want people to be able to put logic in there.Tree::new_terminal
.Tree::rand_nonterminal
Tree:: rand_nonterminal
is an inaccurate and bad name. There is no requirement for this method to return a non-terminal. Returning a non-terminal is in keeping with howTreeGen
generates trees of certain depths but this is much more of a handy guideline than a rule.Tree::new_child
orTree::new_node
?Tree::terminal_proportion
This is lifted straight from DEAP's
genGrow
logic. I like having properties about the implementation ofTree
to hand, but this should probably be done some way other than having users calculate how many of their nodes are terminal.There's a large design space here.
This is somewhat ugly, especially in extended code. Requiring tagging of Terminals only is an option. It would be nice if the Terminals could be identified by reasoning about the Types - identifying the Terminals as those which cannot contain
Self
. Fascinatingly, reasoning about the types could allow for deriving how to generate a particular Terminal or Nonterminal.jeepers
could use a nested enum structure like thisThis works but I very much dislike this as a long-term pattern. It works around the immediate problem but doesn't do much for the wider concerns of this document.
Both these implementations add requirements to users, but the functionality may become more straightforward.
Dealing with tree roots
I think it would be best to have a
TreeRoot
struct that wraps an entireTree
. From the DEAP and GP point-of-view this is better thought of as anIndividual
. Amongst other things this struct would store the number of nodes in the tree and its maximum depth - useful for logging.Calculating number of nodes during generation would add complication.
TreeGen
isn't designed to do this and adding further method arguments is going to confuse users. The ability to visit each node is evidently called for - this would be a new section to the API.