'returns the boundary violation penalty for `x` ,where `x` is a
single solution or a list or array of solutions.
If `bounds` is not `None`, the values in `bounds` are used, see `__init__`'

def __call__(self, x, archive, gp):

    if (x in (None, (), [])):
        return x
    if (gp.bounds in (None, [None, None], (None, None))):
        return (0.0 if np.isscalar(x[0]) else ([0.0] * len(x)))
    x_is_single_vector = np.isscalar(x[0])
    x = ([x] if x_is_single_vector else x)
    pen = []
    for xi in x:
        xpheno = gp.pheno(archive[xi]['geno'])
        xinbounds = gp.into_bounds(xpheno)
        fac = 1
        pen.append((sum((self.gamma * (((xinbounds - xpheno) / fac) ** 2))) / len(xi)))
    return (pen[0] if x_is_single_vector else pen)
