3D array minimization (optimization)

Viewed 158

Suppose I have the following 5x5x5 3D array, consisting of binary values:

space = [
[[0,1,0,0,1], [1,0,0,1,0], [0,1,0,1,1], [0,0,0,1,1], [0,1,1,0,1]],
[[1,1,1,0,1], [0,0,0,1,0], [0,0,1,1,1], [0,0,0,1,1], [0,1,0,0,0]],
[[0,1,0,1,0], [1,1,0,0,0], [1,0,0,1,0], [0,1,1,1,0], [0,1,1,1,1]],
[[0,1,0,1,0], [0,1,0,1,1], [1,1,0,1,0], [1,0,0,1,0], [0,0,0,0,0]],
[[1,0,0,1,1], [0,1,1,0,1], [0,1,0,1,1], [0,1,1,0,1], [1,0,1,0,0]],
]

and a function measure(space) which takes this 3D array as the input, and returns a real value. My goal is to find the best space configuration that returns the minimum measure() output.

How may I use scipy.optimize.minimize which takes a 1D-array as input (or any other function/library you might think is more appropriate for this problem) to solve this optimization problem?


EDIT: To clarify, the measure() function converts the 3D array into a CAD model (where 1: solid; 0: void), and passes the 3D geometry into an electromagnetic solver (antenna simulator) to get a result describing the "efficiency" of the antenna (sort of what the metric describes, except the lower the value is, the better the performance of the antenna).

1 Answers

Don't use a 1d optimization function, there are at least three (surely more) approaches you can take:

  • Brute force, in your case that would be trying 2**125, which seems a bit too much.

  • Using MonteCarlo, i.e generating random solutions till finding the best, or at least one that is good enough

  • Using genetic algorithms, which will be probably the best you can get for this problem. You can use PyGAD for instance, and it won't take much time to get a good solution if not the best.

Here I put an example working where you only need to specify your fitness_function, in this case it will likely find the best solution.

import pygad
import numpy as np

space = [
[[0,1,0,0,1], [1,0,0,1,0], [0,1,0,1,1], [0,0,0,1,1], [0,1,1,0,1]],
[[1,1,1,0,1], [0,0,0,1,0], [0,0,1,1,1], [0,0,0,1,1], [0,1,0,0,0]],
[[0,1,0,1,0], [1,1,0,0,0], [1,0,0,1,0], [0,1,1,1,0], [0,1,1,1,1]],
[[0,1,0,1,0], [0,1,0,1,1], [1,1,0,1,0], [1,0,0,1,0], [0,0,0,0,0]],
[[1,0,0,1,1], [0,1,1,0,1], [0,1,0,1,1], [0,1,1,0,1], [1,0,1,0,0]],
]
space = np.array(space)

# I create a reference binary matrix to create a objective solution
i = np.identity(5)
ref = np.dstack([i]*5)

# flat your array to do it gen-like
space= space.flatten()
ref = ref.flatten()

def fitness_func(solution, solution_idx):
    # write here your fitness function, in my case i just compare how different two matrix are.
    fitness = np.sum(ref == solution)
    return fitness
    
fitness_function = fitness_func

num_generations = 400
num_parents_mating = 10

sol_per_pop = 14
num_genes = len(space)
init_range_low = 0
init_range_high = 1
gene_space=[0,1] # only binary solutions
parent_selection_type = "sss"
keep_parents = 8

crossover_type = "single_point" #"scattered" #
mutation_type = "random"
mutation_percent_genes = 1

ga_instance = pygad.GA(num_generations=num_generations,
                       num_parents_mating=num_parents_mating,
                       fitness_func=fitness_function,
                       sol_per_pop=sol_per_pop,
                       num_genes=num_genes,
                       init_range_low=init_range_low,
                       init_range_high=init_range_high,
                       gene_space=gene_space,
                       parent_selection_type=parent_selection_type,
                       keep_parents=keep_parents,
                       crossover_type=crossover_type,
                       mutation_type=mutation_type,
                       mutation_percent_genes=mutation_percent_genes)
                       
ga_instance.run()

solution, solution_fitness, solution_idx = ga_instance.best_solution()
print(f"Parameters of the best solution : {solution}")
print(f"Fitness value of the best solution = {solution_fitness}")

# reshape the solution 
solution = solution.reshape([5,5,5])
print(solution)

In general without knowing how "measure" the only approach that guarantee the best solution is brute force. If you know how "measure" looks like, using "maths" could be a fourth approach. But for most cases the genetic algorithm is a good enough solution for this optimization problem.

Related