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.