Sean, Thanks for the reply. I have used the type system in a way similar to what you suggest below, using set types, to indirectly enforce the kinds of constraints I described. I am indeed in a couple of spots using the approach of simply discarding candidate nodes that are invalid and repeating until a valid node it returned, but as you said this is really slowing my program down. Sean Luke wrote: > On Feb 1, 2006, at 4:19 PM, George Coles wrote: > >> I am pretty sure that this is not to be found in ECJ, but I wanted >> to run it by the list. Is there any way to constraint nodes so that >> you can prevent Node A from ever appearing within the "scope" of >> Node B, i.e. anywhere below it in the tree? I don't think a >> constraint based on return type is sufficient. > > > It's sufficient in some cases. Let's say you have nodes A(x,y), B > (x,y), C(x,y) and D(). A can't be in any tree rooted by a B. You > could set up types (I'll indicate atomic types with numbers, set > types with braces) like this: > > 1 <- A(1,1) > 1 <- B(2,2) > 1 <- C(1,1) > 1 <- D() > > 2 <- Ba(2,2) > 2 <- Ca(2,2) > 2 <- Da() > > Or in compacter form > > 1 <- A(1,1) > {1,2} <- B(2,2) > 1 <- C(1,1) > 2 <- Ca(2,2) > {1,2} <- D() > > That is, the children to B are of a different type, and you just > repeat all legal nodes that are allowed to be under B to be of that > type and to require kids of that type and so on. > > If you need more sophisticated checking, you have to check the > constraints manually and make sure your particular operators are > valid. A quick and dirty but computationally costly way to do this > is to create a BreedingPipeline which repeatedly pulses its > subsidiary pipeline until it gets a valid individual, and then > returns that individual. Then you can use that pipeline as your > pipeline root with almost anything hung off of it. > > Sean > > >