Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

typed Primitive Set Index Error #219

Open
JayDeng2837 opened this issue Jul 13, 2017 · 3 comments · May be fixed by #749
Open

typed Primitive Set Index Error #219

JayDeng2837 opened this issue Jul 13, 2017 · 3 comments · May be fixed by #749

Comments

@JayDeng2837
Copy link

JayDeng2837 commented Jul 13, 2017

Hi,

I was trying to formulate a problem two numpy arrays as terminals and undetermined number of random floats as ephemeral constants. (these random floats are the second input for function fmul that multiples an numpy array with a float).

The tree depth is limited to 10 and I added 300 constants, however i still get the following error....
is there a way to fix it? thanks.

IndexError: The gp.generate function tried to add a primitive of type '<type 'float'>', but there is none available.

`pset = gp.PrimitiveSetTyped("MAIN", [np.ndarray, np.ndarray],np.ndarray, 2)
pset.addPrimitive(numpy.add, [np.ndarray, np.ndarray],np.ndarray, name="vadd")
pset.addPrimitive(numpy.subtract, [np.ndarray, np.ndarray] ,np.ndarray, name="vsub")
pset.addPrimitive(numpy.multiply, [np.ndarray, np.ndarray] ,np.ndarray, name="vmul")
pset.addPrimitive(numpy.multiply, [np.ndarray, float] ,np.ndarray, name="fmul")
pset.addPrimitive(numpy.negative, [np.ndarray] ,np.ndarray, name="vneg")

#adding many ephemeral constants
for i in range(300):
pset.addEphemeralConstant("rand%s"%i, lambda: random.randint(-1,1), float)

pset.renameArguments(ARG0='x')
pset.renameArguments(ARG1='y')
toolbox.register("expr", gp.genHalfAndHalf, pset=pset, min_=1, max_=10)`

@snigdhasjg
Copy link

I found out this

The generation of trees is done randomly while making sure type constraints are respected. If any primitive has an input type that no primitive and terminal can provide, chances are that this primitive will be picked and placed in the tree, resulting in the impossibility to complete the tree within the limit fixed by the generator. For example, when generating a full tree of height 2, suppose "op" takes a boolean and a float, "and" takes 2 boolean and "neg" takes a float, no terminal is defined and the arguments are booleans. The following situation will occur where no terminal can be placed to complete the tree.

Image of ### ### Yaktocat

In this case, DEAP raises an IndexError with the message "The gp.generate function tried to add a terminal of type float, but there is none available."

While adding primitive

Alleast one relation should be there for each type

Input args -> return args

  1. np.ndarray -> float
  2. float -> np.ndarray

and you were missing the 1st case

While adding terminal / ephemeral

For all primitive you have used should atleast have one terminals for them

  1. one for float
  2. one for np.ndarray

and you are missing the 2nd case

@snigdhasjg
Copy link

So now you have to add a dummy primitive and terminal for each of the missing case

pset = gp.PrimitiveSetTyped("MAIN", [np.ndarray, np.ndarray],np.ndarray, 2)
pset.addPrimitive(numpy.add, [np.ndarray, np.ndarray],np.ndarray, name="vadd")
pset.addPrimitive(numpy.subtract, [np.ndarray, np.ndarray] ,np.ndarray, name="vsub")
pset.addPrimitive(numpy.multiply, [np.ndarray, np.ndarray] ,np.ndarray, name="vmul")
pset.addPrimitive(numpy.multiply, [np.ndarray, float] ,np.ndarray, name="fmul")
pset.addPrimitive(numpy.negative, [np.ndarray] ,np.ndarray, name="vneg")

def dummy_primitive_for_numpyarray_to_float(numpy_array):
    # and you have handle this return in each method
    return None

pset.addPrimitive(dummy_primitive_for_numpyarray_to_float, [np.ndarray] ,float, name="dummy_primitive")

# adding many ephemeral constants
for i in range(300):
pset.addEphemeralConstant("rand%s"%i, lambda: random.randint(-1,1), float)

# dummy terminal
pset.addTerminal("dummy_terminal",lamda: None, np.ndarray)

pset.renameArguments(ARG0='x')
pset.renameArguments(ARG1='y')
toolbox.register("expr", gp.genHalfAndHalf, pset=pset, min_=1, max_=10)

You have keep in mind that all dummy terminals and primitive shouldn't get selected.

p.s. - I'm terrible at explaining things. Sorry for that.

@GregoryMorse
Copy link

This is a bug here: https://github.com/DEAP/deap/blob/master/deap/gp.py#L634

Basically it should not check the condition if either terminals or primitives are not available. Both not being available would be a legitimate error. I can make a PR for it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants