def _do(self, problem, pop, **kwargs): X = pop.get("X").astype(np.double) Y = np.full(X.shape, np.inf) if self.prob is None: self.prob = 1.0 / problem.n_var do_mutation = random.random(X.shape) < self.prob Y[:, :] = X xl = np.repeat(problem.xl[None, :], X.shape[0], axis=0)[do_mutation] xu = np.repeat(problem.xu[None, :], X.shape[0], axis=0)[do_mutation] if self.var_type == np.int: xl -= 0.5 xu += (0.5 - 1e-16) X = X[do_mutation] delta1 = (X - xl) / (xu - xl) delta2 = (xu - X) / (xu - xl) mut_pow = 1.0 / (self.eta + 1.0) rand = random.random(X.shape) mask = rand <= 0.5 mask_not = np.logical_not(mask) deltaq = np.zeros(X.shape) xy = 1.0 - delta1 val = 2.0 * rand + (1.0 - 2.0 * rand) * (np.power( xy, (self.eta + 1.0))) d = np.power(val, mut_pow) - 1.0 deltaq[mask] = d[mask] xy = 1.0 - delta2 val = 2.0 * (1.0 - rand) + 2.0 * (rand - 0.5) * (np.power( xy, (self.eta + 1.0))) d = 1.0 - (np.power(val, mut_pow)) deltaq[mask_not] = d[mask_not] # mutated values _Y = X + deltaq * (xu - xl) # back in bounds if necessary (floating point issues) _Y[_Y < xl] = xl[_Y < xl] _Y[_Y > xu] = xu[_Y > xu] # set the values for output Y[do_mutation] = _Y if self.var_type == np.int: Y = np.rint(Y).astype(np.int) off = OutOfBoundsRepair().do(problem, pop.new("X", Y)) return off
def _sample(self, n_samples, n_var): X = random.random(size=(n_samples, n_var)) val = X.argsort(axis=0) + 1 if self.smooth: val = val - random.random(val.shape) else: val = val - 0.5 val /= n_samples return val
def _do(self, p, parents, children, **kwargs): n_var = parents.shape[2] n_offsprings = parents.shape[0] # do the crossover if self.type == "binomial": # uniformly for each individual and each entry r = random.random(size=(n_offsprings, n_var)) < self.prob elif self.type == "exponential": r = np.full((n_offsprings, n_var), False) # start point of crossover n = random.randint(0, n_var, size=n_var) # length of chromosome to do the crossover L = np.argmax((random.random(n_offsprings) > self.prob), axis=1) # create for each individual the crossover range for i in range(n_offsprings): for l in range(L[i] + 1): r[i, (n[i] + l) % n_var] = True else: raise Exception( "Unknown crossover type. Either binomial or exponential.") # the so called donor vector children[:, :] = parents[:, 0] if self.variant == "DE/rand/1": trial = parents[:, 3] + self.weight * (parents[:, 1] - parents[:, 2]) else: raise Exception("DE variant %s not known." % self.variant) # set only if larger than F_CR children[r] = trial[r] # bounce back into bounds if self.bounce_back_in_bounds: smaller_than_min, larger_than_max = p.xl > children, p.xu < children children[smaller_than_min] = (p.xl + (p.xl - children))[smaller_than_min] children[larger_than_max] = (p.xu - (children - p.xu))[larger_than_max]
def _next(self, pop): # iterate for each member of the population in random order for i in random.perm(len(pop)): # all neighbors of this individual and corresponding weights N = self.neighbors[i, :] if random.random() < self.prob_neighbor_mating: parents = N[random.perm(self.n_neighbors)][:self.crossover.n_parents] else: parents = random.perm(self.pop_size)[:self.crossover.n_parents] # do recombination and create an offspring off = self.crossover.do(self.problem, pop, parents[None, :]) off = self.mutation.do(self.problem, off) off = off[random.randint(0, len(off))] # evaluate the offspring self.evaluator.eval(self.problem, off) # update the ideal point self.ideal_point = np.min(np.vstack([self.ideal_point, off.F]), axis=0) # calculate the decomposed values for each neighbor FV = self._decomposition.do(pop[N].get("F"), weights=self.ref_dirs[N, :], ideal_point=self.ideal_point) off_FV = self._decomposition.do(off.F[None, :], weights=self.ref_dirs[N, :], ideal_point=self.ideal_point) # get the absolute index in F where offspring is better than the current F (decomposed space) I = np.where(off_FV < FV)[0] pop[N[I]] = off return pop
def _do(self, problem, pop, parents, **kwargs): # get the X of parents and count the matings X = pop.get("X")[parents.T] _, n_matings, n_var = X.shape # the mask do to the crossover M = np.full((n_matings, n_var), False) # start point of crossover n = random.randint(0, n_var, size=len(pop)) # the probabilities are calculated beforehand r = random.random((n_matings, n_var)) < self.prob # create for each individual the crossover range for i in range(n_matings): # the actual index where we start start = n[i] for j in range(problem.n_var): # the current position where we are pointing to current = (start + j) % problem.n_var # replace only if random value keeps being smaller than CR if r[i, current]: M[i, current] = True else: break _X = crossover_mask(X, M) return pop.new("X", _X)
def sample(self, problem, pop, n_samples, **kwargs): m = problem.n_var val = random.random(size=(n_samples, m)) if self.var_type == np.bool: val = random.random((n_samples, m)) val = (val < 0.5).astype(np.bool) elif self.var_type == np.int: val = np.rint( denormalize(val, problem.xl - 0.5, problem.xu + (0.5 - 1e-16))).astype(np.int) else: val = denormalize(val, problem.xl, problem.xu) return pop.new("X", val)
def sample(self, problem, n_samples, data=None): m = len(problem.xl) val = random.random(size=(n_samples, m)) for i in range(m): val[:, i] = val[:, i] * (problem.xu[i] - problem.xl[i]) + problem.xl[i] return val
def sample(self, problem, pop, n_samples, **kwargs): m = problem.n_var val = random.random((n_samples, m)) val = (val < 0.5).astype(np.bool) return pop.new("X", val)
def _do(self, p, X, Y, **kwargs): if self.prob_mut is None: self.prob_mut = 1.0 / p.n_var for i in range(X.shape[0]): for j in range(X.shape[1]): rnd = random.random() if rnd <= self.prob_mut: y = X[i, j] yl = p.xl[j] yu = p.xu[j] delta1 = (y - yl) / (yu - yl) delta2 = (yu - y) / (yu - yl) mut_pow = 1.0 / (self.eta_mut + 1.0) rnd = random.random() if rnd <= 0.5: xy = 1.0 - delta1 val = 2.0 * rnd + (1.0 - 2.0 * rnd) * (pow( xy, (self.eta_mut + 1.0))) deltaq = pow(val, mut_pow) - 1.0 else: xy = 1.0 - delta2 val = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * (pow( xy, (self.eta_mut + 1.0))) deltaq = 1.0 - (pow(val, mut_pow)) y = y + deltaq * (yu - yl) if y < yl: y = yl if y > yu: y = yu Y[i, j] = y else: Y[i, j] = X[i, j]
def _next(self, pop): # get the vectors from the population F, CV, feasible = pop.get("F", "CV", "feasible") F = parameter_less(F, CV) # create offsprings and add it to the data of the algorithm if self.var_selection == "rand": P = self.selection.do(pop, self.pop_size, self.crossover.n_parents) elif self.var_selection == "best": best = np.argmin(F[:, 0]) P = self.selection.do(pop, self.pop_size, self.crossover.n_parents - 1) P = np.column_stack([np.full(len(pop), best), P]) elif self.var_selection == "rand+best": best = np.argmin(F[:, 0]) P = self.selection.do(pop, self.pop_size, self.crossover.n_parents) use_best = random.random(len(pop)) < 0.3 P[use_best, 0] = best else: raise Exception("Unknown selection: %s" % self.var_selection) self.off = self.crossover.do(self.problem, pop, P) # do the mutation by using the offsprings self.off = self.mutation.do(self.problem, self.off, algorithm=self) # bring back to bounds if violated through crossover - bounce back strategy X = self.off.get("X") xl = np.repeat(self.problem.xl[None, :], X.shape[0], axis=0) xu = np.repeat(self.problem.xu[None, :], X.shape[0], axis=0) # otherwise bounds back into the feasible space X[X < xl] = (xl + (xl - X))[X < xl] X[X > xu] = (xu - (X - xu))[X > xu] self.off.set("X", X) # evaluate the results self.evaluator.eval(self.problem, self.off, algorithm=self) _F, _CV, _feasible = self.off.get("F", "CV", "feasible") _F = parameter_less(_F, _CV) # find the individuals which are indeed better is_better = np.where((_F <= F)[:, 0])[0] # truncate the replacements if desired if self.n_replace is not None and self.n_replace < len(is_better): is_better = is_better[random.perm(len(is_better))[:self.n_replace]] # replace the individuals in the population pop[is_better] = self.off[is_better] return pop
def sample(self, problem, pop, n_samples, **kwargs): m = problem.n_var val = random.random(size=(n_samples, m)) for i in range(m): val[:, i] = val[:, i] * (problem.xu[i] - problem.xl[i]) + problem.xl[i] return pop.new("X", val)
def _do(self, problem, pop, algorithm, **kwargs): X = pop.get("X") off = algorithm.off _X = off.get("X") # do the crossover if self.variant == "bin": # uniformly for each individual and each entry r = random.random(size=(len(off), problem.n_var)) < self.CR elif self.variant == "exp": # start point of crossover r = np.full((len(off), problem.n_var), False) # start point of crossover n = random.randint(0, problem.n_var, size=len(off)) # length of chromosome to do the crossover L = random.random((len(off), problem.n_var)) < self.CR # create for each individual the crossover range for i in range(len(off)): # the actual index where we start start = n[i] for j in range(problem.n_var): # the current position where we are pointing to current = (start + j) % problem.n_var # replace only if random value keeps being smaller than CR if L[i, current]: r[i, current] = True else: break else: raise Exception( "Unknown crossover type. Either binomial or exponential.") X[r] = _X[r] return pop.new("X", X)
def _do(self, problem, pop, parents, **kwargs): X = pop.get("X")[parents.T] if self.dither == "vector": weight = (self.weight + random.random(len(parents)) * (1 - self.weight))[:, None] elif self.dither == "scalar": weight = self.weight + random.random() * (1 - self.weight) else: weight = self.weight # http://www.cs.ndsu.nodak.edu/~siludwig/Publish/papers/SSCI20141.pdf if self.jitter: gamma = 0.0001 weight = (self.weight * (1 + gamma * (random.random(len(parents)) - 0.5)))[:, None] _X = X[0] + weight * (X[1] - X[2]) return pop.new("X", _X)
def _do(self, p, parents, children, data=None): for i in range(p.n_var): if random.random() < 0.5: children[0, i] = parents[0, i] children[1, i] = parents[1, i] else: children[0, i] = parents[1, i] children[1, i] = parents[0, i] return children
def _do(self, p, X, Y): if self.p_mut is None: self.p_mut = 1.0 / p.n_var for i in range(X.shape[0]): for j in range(X.shape[1]): # no mutation for this index if random.random() > self.p_mut: Y[i, j] = X[i, j] else: y = X[i, j] yl = p.xl[j] yu = p.xu[j] delta1 = (y - yl) / (yu - yl) delta2 = (yu - y) / (yu - yl) r = random.random() mut_pow = 1.0 / (self.eta_m + 1.0) if r <= 0.5: xy = 1.0 - delta1 val = 2.0 * r + (1.0 - 2.0 * r) * (pow( xy, (self.eta_m + 1.0))) deltaq = pow(val, mut_pow) - 1.0 else: xy = 1.0 - delta2 val = 2.0 * (1.0 - r) + 2.0 * (r - 0.5) * (pow( xy, (self.eta_m + 1.0))) deltaq = 1.0 - (pow(val, mut_pow)) y = y + deltaq * (yu - yl) if y < yl: y = yl if y > yu: y = yu Y[i, j] = y return Y
def _do(self, problem, pop, **kwargs): if self.prob is None: self.prob = 1.0 / problem.n_var X = pop.get("X") _X = np.full(X.shape, np.inf) M = random.random(X.shape) flip, not_flip = M < self.prob, M > self.prob _X[flip] = np.logical_not(X[flip]) _X[not_flip] = X[not_flip] return pop.new("X", _X.astype(np.bool))
def _do(self, p, X, Y, **kwargs): if self.p_mut is None: self.p_mut = 1.0 / len(X) for i in range(X.shape[0]): for j in range(X.shape[1]): if random.random() < self.p_mut: Y[i, j] = not X[i, j] else: Y[i, j] = X[i, j] return Y
def _next(self, pop): # get the vectors from the population F, CV, feasible = pop.get("F", "CV", "feasible") F = parameter_less(F, CV) # create offsprings and add it to the data of the algorithm if self.var_selection == "rand": P = self.selection.do(pop, self.pop_size, self.crossover.n_parents) elif self.var_selection == "best": best = np.argmin(F[:, 0]) P = self.selection.do(pop, self.pop_size, self.crossover.n_parents - 1) P = np.column_stack([np.full(len(pop), best), P]) elif self.var_selection == "rand+best": best = np.argmin(F[:, 0]) P = self.selection.do(pop, self.pop_size, self.crossover.n_parents) use_best = random.random(len(pop)) < 0.3 P[use_best, 0] = best else: raise Exception("Unknown selection: %s" % self.var_selection) # do the first crossover which is the actual DE operation self.off = self.crossover.do(self.problem, pop, P, algorithm=self) # then do the mutation (which is actually ) _pop = self.off.new().merge(self.pop).merge(self.off) _P = np.column_stack([np.arange(len(pop)), np.arange(len(pop)) + len(pop)]) self.off = self.mutation.do(self.problem, _pop, _P, algorithm=self)[:len(self.pop)] # bounds back if something is out of bounds self.off = BoundsBackRepair().do( self.problem, self.off) # evaluate the results self.evaluator.eval(self.problem, self.off, algorithm=self) _F, _CV, _feasible = self.off.get("F", "CV", "feasible") _F = parameter_less(_F, _CV) # find the individuals which are indeed better is_better = np.where((_F <= F)[:, 0])[0] # replace the individuals in the population pop[is_better] = self.off[is_better] return pop
def _do(self, p, parents, children, **kwargs): # number of parents n_parents = parents.shape[0] # random matrix to do the crossover M = random.random(n_parents, p.n_var) smaller, larger = M < 0.5, M > 0.5 # first possibility where first parent 0 is copied children[:n_parents][smaller] = parents[:, 0, :][smaller] children[:n_parents][larger] = parents[:, 1, :][larger] # now flip the order of parents with the same random array and write the second half of children children[n_parents:][smaller] = parents[:, 1, :][smaller] children[n_parents:][larger] = parents[:, 0, :][larger]
def stochastic_ranking(F, CV, prob): # swap two individuals in the _current population def func_swap(A, i, j): tmp = A[i] A[i] = A[j] A[j] = tmp # the number of solutions that need to be ranked n_solutions = F.shape[0] # the number of pairwise comparisons - here we fix it to the number of solutions _lambda = n_solutions # the final sorting index = np.arange(n_solutions) for i in range(n_solutions): # variable which sets the flag if a swap was performed or not swap = False for j in range(_lambda - 1): _current, _next = index[j], index[j + 1] if (CV[_current] == 0 and CV[_next] == 0) or (random.random() < prob): if F[_current] > F[_next]: func_swap(index, j, j + 1) swap = True else: if CV[_current] > CV[_next]: func_swap(index, j, j + 1) swap = True if not swap: break return index
def _do(self, problem, pop, **kwargs): if self.p_mut is None: self.p_mut = 1.0 / problem.n_var X = pop.get("X") _X = np.full(X.shape, np.inf) for k in range(X.shape[0]): for i in range(X.shape[1]): if random.random() < self.p_mut: available_choices = np.arange(problem.xl[i], problem.xu[i] + 1).tolist() available_choices.remove(X[k, i]) # removes the current value _X[k, i] = np.random.choice(available_choices) else: _X[k, i] = X[k, i] return pop.new("X", _X.astype(np.int))
def _do(self, problem, pop, parents, **kwargs): # number of parents n_matings = parents.shape[0] off = np.full((n_matings * self.n_offsprings, problem.n_var), np.inf, dtype=problem.type_var) X = pop.get("X")[parents.T] # random matrix to do the crossover M = random.random((n_matings, problem.n_var)) smaller, larger = M < 0.5, M > 0.5 # first possibility where first parent 0 is copied off[:n_matings][smaller] = X[0, :, :][smaller] off[:n_matings][larger] = X[1, :, :][larger] # now flip the order of parents with the same random array and write the second half of off off[n_matings:][smaller] = X[1, :, :][smaller] off[n_matings:][larger] = X[0, :, :][larger] return pop.new("X", off.astype(problem.type_var))
def _do(self, p, parents, children, **kwargs): n_children = 0 for k in range(parents.shape[0]): if random.random() <= self.prob_cross: for i in range(p.n_var): rnd = random.random() if rnd <= 0.5: if np.abs(parents[k, 0, i] - parents[k, 1, i]) > 1.0e-10: yl = p.xl[i] yu = p.xu[i] if parents[k, 0, i] < parents[k, 1, i]: y1 = parents[k, 0, i] y2 = parents[k, 1, i] else: y1 = parents[k, 1, i] y2 = parents[k, 0, i] if (y1 - yl) > (yu - y2): beta = 1 / (1 + (2 * (yu - y2) / (y2 - y1))) else: beta = 1 / (1 + (2 * (y1 - yl) / (y2 - y1))) alpha = (2.0 - pow(beta, self.eta_cross + 1.0)) rnd = random.random() if rnd <= 1.0 / alpha: alpha *= rnd else: alpha *= rnd alpha = 1.0 / (2.0 - alpha) betaq = pow(alpha, 1.0 / (self.eta_cross + 1.0)) c1 = 0.5 * ((y1 + y2) - betaq * (y2 - y1)) c2 = 0.5 * ((y1 + y2) + betaq * (y2 - y1)) if c1 < yl: c1 = yl if c2 < yl: c2 = yl if c1 > yu: c1 = yu if c2 > yu: c2 = yu children[n_children, i] = c1 children[n_children + 1, i] = c2 else: children[n_children, i] = parents[k, 0, i] children[n_children + 1, i] = parents[k, 1, i] else: children[n_children, i] = parents[k, 0, i] children[n_children + 1, i] = parents[k, 1, i] else: children[n_children, :] = parents[k, 0, :] children[n_children + 1, :] = parents[k, 1, :] n_children += self.n_offsprings
def _do(self, p, parents, children, data=None): n = p.n_var if random.random() <= self.p_xover: for i in range(n): if random.random() <= 0.5: if abs(parents[0, i] - parents[1, i]) > Configuration.EPS: if parents[0, i] < parents[1, i]: y1 = parents[0, i] y2 = parents[1, i] else: y1 = parents[1, i] y2 = parents[0, i] yl = p.xl[i] yu = p.xu[i] rand = random.random() beta = 1.0 + (2.0 * (y1 - yl) / (y2 - y1)) alpha = 2.0 - pow(beta, -(self.eta_c + 1.0)) if rand <= (1.0 / alpha): betaq = pow((rand * alpha), (1.0 / (self.eta_c + 1.0))) else: betaq = pow((1.0 / (2.0 - rand * alpha)), (1.0 / (self.eta_c + 1.0))) c1 = 0.5 * ((y1 + y2) - betaq * (y2 - y1)) beta = 1.0 + (2.0 * (yu - y2) / (y2 - y1)) alpha = 2.0 - pow(beta, -(self.eta_c + 1.0)) if rand <= (1.0 / alpha): betaq = pow((rand * alpha), (1.0 / (self.eta_c + 1.0))) else: betaq = pow((1.0 / (2.0 - rand * alpha)), (1.0 / (self.eta_c + 1.0))) c2 = 0.5 * ((y1 + y2) + betaq * (y2 - y1)) if c1 < yl: c1 = yl if c2 < yl: c2 = yl if c1 > yu: c1 = yu if c2 > yu: c2 = yu if random.random() <= 0.5: children[0, i] = c2 children[1, i] = c1 else: children[0, i] = c1 children[1, i] = c2 else: children[0, i] = parents[0, i] children[1, i] = parents[1, i] else: children[0, i] = parents[0, i] children[1, i] = parents[1, i] else: children[:, :] = parents return children
def _do(self, p, parents, children, **kwargs): n_var = p.n_var n_children = 0 for k in range(parents.shape[0]): if random.random() <= self.prob_cross: for i in range(n_var): if random.random() <= 0.5: if abs(parents[k, 0, i] - parents[k, 1, i]) > Configuration.EPS: if parents[k, 0, i] < parents[k, 1, i]: y1 = parents[k, 0, i] y2 = parents[k, 1, i] else: y1 = parents[k, 1, i] y2 = parents[k, 0, i] yl = p.xl[i] yu = p.xu[i] rand = random.random() beta = 1.0 + (2.0 * (y1 - yl) / (y2 - y1)) alpha = 2.0 - pow(beta, -(self.eta_cross + 1.0)) if rand <= (1.0 / alpha): betaq = pow((rand * alpha), (1.0 / (self.eta_cross + 1.0))) else: betaq = pow((1.0 / (2.0 - rand * alpha)), (1.0 / (self.eta_cross + 1.0))) c1 = 0.5 * ((y1 + y2) - betaq * (y2 - y1)) beta = 1.0 + (2.0 * (yu - y2) / (y2 - y1)) alpha = 2.0 - pow(beta, -(self.eta_cross + 1.0)) if rand <= (1.0 / alpha): betaq = pow((rand * alpha), (1.0 / (self.eta_cross + 1.0))) else: betaq = pow((1.0 / (2.0 - rand * alpha)), (1.0 / (self.eta_cross + 1.0))) c2 = 0.5 * ((y1 + y2) + betaq * (y2 - y1)) if c1 < yl: c1 = yl if c2 < yl: c2 = yl if c1 > yu: c1 = yu if c2 > yu: c2 = yu if random.random() <= 0.5: children[n_children, i] = c2 children[n_children+1, i] = c1 else: children[n_children, i] = c1 children[n_children+1, i] = c2 else: children[n_children, i] = parents[k, 0, i] children[n_children+1, i] = parents[k, 1, i] else: children[n_children, i] = parents[k, 0, i] children[n_children+1, i] = parents[k, 1, i] else: children[n_children, :] = parents[k, 0, :] children[n_children+1, :] = parents[k, 1, :] n_children += self.n_children
def _mating(self, p, parents, children, **kwargs): if random.random() <= self.prob_cross: for i in range(p.n_var): if random.random() <= 0.5: if np.abs(parents[0, i] - parents[1, i]) > 1.0e-14: if parents[0, i] < parents[1, i]: y1 = parents[0, i] y2 = parents[1, i] else: y1 = parents[1, i] y2 = parents[0, i] yl = p.xl[i] yu = p.xu[i] rand = random.random() beta = 1.0 + (2.0 * (y1 - yl) / (y2 - y1)) alpha = 2.0 - pow(beta, -(self.eta_cross + 1.0)) if rand <= (1.0 / alpha): betaq = pow((rand * alpha), (1.0 / (self.eta_cross + 1.0))) else: betaq = pow((1.0 / (2.0 - rand * alpha)), (1.0 / (self.eta_cross + 1.0))) c1 = 0.5 * ((y1 + y2) - betaq * (y2 - y1)) beta = 1.0 + (2.0 * (yu - y2) / (y2 - y1)) alpha = 2.0 - pow(beta, -(self.eta_cross + 1.0)) if rand <= (1.0 / alpha): betaq = pow((rand * alpha), (1.0 / (self.eta_cross + 1.0))) else: betaq = pow((1.0 / (2.0 - rand * alpha)), (1.0 / (self.eta_cross + 1.0))) c2 = 0.5 * ((y1 + y2) + betaq * (y2 - y1)) if c1 < yl: c1 = yl if c2 < yl: c2 = yl if c1 > yu: c1 = yu if c2 > yu: c2 = yu if random.random() <= 0.5: children[0, i] = c2 children[1, i] = c1 else: children[0, i] = c1 children[1, i] = c2 else: children[0, i] = parents[0, i] children[1, i] = parents[1, i] else: children[0, i] = parents[0, i] children[1, i] = parents[1, i] else: children[0, :] = parents[0, :] children[1, :] = parents[1, :]
def _do(self, problem, pop, parents, **kwargs): n_matings = parents.shape[0] children = np.full((n_matings * self.n_offsprings, problem.n_var), np.inf) X = pop.get("X")[parents.T].astype(np.double) xl, xu = problem.xl, problem.xu # in case of an integer problem we do the same, but change the bounds slightly and # round later on if self.var_type == np.int: xl = problem.xl - 0.5 xu = problem.xu + (0.5 - 1e-16) # crossover mask that will be used in the end do_crossover = np.full(X[0].shape, True) # simulating probability of doing a crossover with the parents at all do_crossover[random.random(n_matings) > self.prob, :] = False # per variable the probability is then 50% do_crossover[random.random(( n_matings, problem.n_var)) > self.prob_per_variable] = False # also if values are too close no mating is done do_crossover[np.abs(X[0] - X[1]) <= 1.0e-14] = False # assign y1 the smaller and y2 the larger value y1 = np.min(X, axis=0) y2 = np.max(X, axis=0) # random values for each individual rand = random.random((n_matings, problem.n_var)) def calc_betaq(beta): alpha = 2.0 - np.power(beta, -(self.eta + 1.0)) mask, mask_not = (rand <= (1.0 / alpha)), (rand > (1.0 / alpha)) betaq = np.zeros(mask.shape) betaq[mask] = np.power((rand * alpha), (1.0 / (self.eta + 1.0)))[mask] betaq[mask_not] = np.power((1.0 / (2.0 - rand * alpha)), (1.0 / (self.eta + 1.0)))[mask_not] return betaq # difference between all variables delta = (y2 - y1) # now just be sure not dividing by zero (these cases will be filtered later anyway) #delta[np.logical_or(delta < 1.0e-10, np.logical_not(do_crossover))] = 1.0e-10 delta[delta < 1.0e-10] = 1.0e-10 beta = 1.0 + (2.0 * (y1 - xl) / delta) betaq = calc_betaq(beta) c1 = 0.5 * ((y1 + y2) - betaq * delta) beta = 1.0 + (2.0 * (xu - y2) / delta) betaq = calc_betaq(beta) c2 = 0.5 * ((y1 + y2) + betaq * delta) # do randomly a swap of variables b = random.random((n_matings, problem.n_var)) <= 0.5 val = c1[b] c1[b] = c2[b] c2[b] = val # take the parents as _template c = X.astype(np.double) # copy the positions where the crossover was done c[0, do_crossover] = c1[do_crossover] c[1, do_crossover] = c2[do_crossover] # copy to the structure which is returned children[:n_matings, :] = c[0] children[n_matings:, :] = c[1] if self.var_type == np.int: children = np.rint(children).astype(np.int) # now repair all the offsprings to be in bound off = OutOfBoundsRepair().do(problem, pop.new("X", children)) return off
def _do(self, problem, pop, parents, **kwargs): n_matings = parents.shape[0] children = np.full((n_matings * self.n_offsprings, problem.n_var), np.inf) X = pop.get("X")[parents.T].astype(np.double) # crossover mask that will be used in the end do_crossover = np.full(X[0].shape, True) # simulating probability of doing a crossover with the parents at all do_crossover[random.random(n_matings) > self.prob_cross, :] = False # per variable the probability is then 50% do_crossover[random.random((n_matings, problem.n_var)) <= 0.5] = False # also if values are too close no mating is done do_crossover[np.abs(X[0] - X[1]) <= 1.0e-14] = False # assign y1 the smaller and y2 the larger value y1 = np.min(X, axis=0) y2 = np.max(X, axis=0) # random values for each individual rand = random.random((n_matings, problem.n_var)) def calc_betaq(beta): alpha = 2.0 - np.power(beta, -(self.eta_cross + 1.0)) mask, mask_not = (rand <= (1.0 / alpha)), (rand > (1.0 / alpha)) betaq = np.zeros(mask.shape) betaq[mask] = np.power((rand * alpha), (1.0 / (self.eta_cross + 1.0)))[mask] betaq[mask_not] = np.power((1.0 / (2.0 - rand * alpha)), (1.0 / (self.eta_cross + 1.0)))[mask_not] return betaq # difference between all variables delta = (y2 - y1) # now just be sure not dividing by zero (these cases will be filtered later anyway) #delta[np.logical_or(delta < 1.0e-10, np.logical_not(do_crossover))] = 1.0e-10 delta[delta < 1.0e-10] = 1.0e-10 beta = 1.0 + (2.0 * (y1 - problem.xl) / delta) betaq = calc_betaq(beta) c1 = 0.5 * ((y1 + y2) - betaq * delta) beta = 1.0 + (2.0 * (problem.xu - y2) / delta) betaq = calc_betaq(beta) c2 = 0.5 * ((y1 + y2) + betaq * delta) # do randomly a swap of variables b = random.random((n_matings, problem.n_var)) <= 0.5 val = c1[b] c1[b] = c2[b] c2[b] = val # take the parents as template c = X.astype(np.double) # copy the positions where the crossover was done c[0, do_crossover] = c1[do_crossover] c[1, do_crossover] = c2[do_crossover] # copy to the structure which is returned children[:n_matings, :] = c[0] children[n_matings:, :] = c[1] # just be sure we are not out of bounds children[children < problem.xl] = np.repeat(problem.xl[None, :], children.shape[0], axis=0)[ children < problem.xl] children[children > problem.xu] = np.repeat(problem.xu[None, :], children.shape[0], axis=0)[ children > problem.xu] children = covert_to_type(problem, children) return pop.new("X", children)