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

how to get all solutions not just the pareto optimal solutions? #187

Closed
Siyuan-hub opened this issue Jul 8, 2021 · 12 comments
Closed

how to get all solutions not just the pareto optimal solutions? #187

Siyuan-hub opened this issue Jul 8, 2021 · 12 comments

Comments

@Siyuan-hub
Copy link

I applied this method to solve muti_objective problem.

res = bboptimize(Pro; Method=:borg_moea,
FitnessScheme=ParetoFitnessScheme{2}(is_minimizing=true),
SearchRange=[(-2.5,2.5),(1.0,5.0),(0.1,0.7),(0.001,0.3),
(1.5,5.0),(300.0,500.0),(0.9,5.0),(0.0,1.0),(0.1,4.0),(0.3,5.0),
(0.1,1.5),(100.0,300.0),(0.9,5.0),(0.1,4.0),(0.3,5.0),
(50.0,100.0),(0.9,5.0),(0.1,4.0),(0.3,5.0)],
PopulationSize =100,NumDimensions=19,ϵ=0.01,MaxFuncEvals=1000,TraceInterval=1.0,TraceMode=:compact)

After running it, I can see the running process. in each eval, there is a fitness result. I thought I can get 1000 soutions when I set
MaxFuncEvals=1000. But I use "pf = pareto_frontier(res)",then I just get one pareto optimal solution.
...
...
pop.size=100 arch.size=1 n.restarts=0
1071.49 secs, 990 evals, 735 steps, fitness=(0.52232, 0.34539) agg=0.86771
pop.size=100 arch.size=1 n.restarts=0
1073.56 secs, 992 evals, 736 steps, fitness=(0.52225, 0.34514) agg=0.86738
pop.size=100 arch.size=1 n.restarts=0
1074.64 secs, 993 evals, 737 steps, fitness=(0.52225, 0.34514) agg=0.86738
pop.size=100 arch.size=1 n.restarts=0
1075.69 secs, 994 evals, 738 steps, fitness=(0.52225, 0.34514) agg=0.86738
pop.size=100 arch.size=1 n.restarts=0
1077.79 secs, 996 evals, 739 steps, fitness=(0.52225, 0.34514) agg=0.86738
pop.size=100 arch.size=1 n.restarts=0
1078.84 secs, 997 evals, 740 steps, fitness=(0.52225, 0.34514) agg=0.86738
pop.size=100 arch.size=1 n.restarts=0
1079.88 secs, 998 evals, 741 steps, fitness=(0.52225, 0.34514) agg=0.86738
pop.size=100 arch.size=1 n.restarts=0
1082.04 secs, 1000 evals, 742 steps, fitness=(0.52225, 0.34512) agg=0.86737
pop.size=100 arch.size=1 n.restarts=0

I want to get all the solutions in the process. But I don't know how to do it. Could you please help me?

@robertfeldt
Copy link
Owner

robertfeldt commented Jul 8, 2021

Depends what you mean with "all". If you mean all the solutions in the Pareto frontier here is example code that you can probably tweak for your purposes:

julia> using BlackBoxOptim

julia> fitness_schaffer1(x) = (sum(abs2, x), sum(abs2, x .- 2.0))
fitness_schaffer1 (generic function with 1 method)

julia> res = bboptimize(fitness_schaffer1; Method=:borg_moea,
                   FitnessScheme=ParetoFitnessScheme{2}(is_minimizing=true),
                   SearchRange=(-10.0, 10.0), NumDimensions=3, ϵ=0.05,
                   MaxSteps=50000, TraceInterval=1.0, TraceMode=:silent);

julia> allpf_solutions = map(params, pareto_frontier(res));

julia> length(allpf_solutions)
120

julia> allpf_fitnesses = map(fitness, pareto_frontier(res));

julia> length(allpf_fitnesses)
120

julia> typeof(allpf_solutions)
Vector{Vector{Float64}} (alias for Array{Array{Float64, 1}, 1})

julia> typeof(allpf_fitnesses)
Vector{Tuple{Float64, Float64}} (alias for Array{Tuple{Float64, Float64}, 1})

Note that the number of solutions on the frontier depends on the specific problem and the specific optimization run. It can never be higher than MaxFuncEvals but will typically be much smaller since not all evaluated solutions are good enough to be on the frontier. If you really want to access all solutions that have been evaluated you can just save them in your fitness function. But this is quite rare and not clear what the benefits are (unless you are doing some kind of research on the optimization methods or similar).

@robertfeldt
Copy link
Owner

robertfeldt commented Jul 8, 2021

To clarify the example above we found 120 solutions that are on the Pareto frontier, i.e. none of them Pareto dominates any of the others. Let's look at three of them to make sure:

julia> allpf_fitnesses[17]
(1.9856426463662804, 4.223005212769594)

julia> allpf_fitnesses[18]
(1.9465173029354108, 4.280634320756287)

julia> allpf_fitnesses[49]
(7.069529667506938, 0.6484321993051512)

We can see that 17 dominates 18 on fitness value 2, since 4.22 < 4.28, and 17 dominates 49 on fitness value 1, since 1.99<7.07.

We can see that 18 dominates 17 on fitness value 1 and 18 dominates 49 on fitness value 1.

We can see that 49 dominates 17 and 18 on fitness value 2.

So none of them can be deleted from the Pareto frontier (based on comparing these 3 but of course this should hold for the whole frontier).

I hope this clarifies.

@Siyuan-hub
Copy link
Author

Depends what you mean with "all". If you mean all the solutions in the Pareto frontier here is example code that you can probably tweak for your purposes:

julia> using BlackBoxOptim

julia> fitness_schaffer1(x) = (sum(abs2, x), sum(abs2, x .- 2.0))
fitness_schaffer1 (generic function with 1 method)

julia> res = bboptimize(fitness_schaffer1; Method=:borg_moea,
                   FitnessScheme=ParetoFitnessScheme{2}(is_minimizing=true),
                   SearchRange=(-10.0, 10.0), NumDimensions=3, ϵ=0.05,
                   MaxSteps=50000, TraceInterval=1.0, TraceMode=:silent);

julia> allpf_solutions = map(params, pareto_frontier(res));

julia> length(allpf_solutions)
120

julia> allpf_fitnesses = map(fitness, pareto_frontier(res));

julia> length(allpf_fitnesses)
120

julia> typeof(allpf_solutions)
Vector{Vector{Float64}} (alias for Array{Array{Float64, 1}, 1})

julia> typeof(allpf_fitnesses)
Vector{Tuple{Float64, Float64}} (alias for Array{Tuple{Float64, Float64}, 1})

Note that the number of solutions on the frontier depends on the specific problem and the specific optimization run. It can never be higher than MaxFuncEvals but will typically be much smaller since not all evaluated solutions are good enough to be on the frontier. If you really want to access all solutions that have been evaluated you can just save them in your fitness function. But this is quite rare and not clear what the benefits are (unless you are doing some kind of research on the optimization methods or similar).

Thanks for your reply!
I mean if I can get the solution in each eval.

@Siyuan-hub
Copy link
Author

If you really want to access all solutions that have been evaluated you can just save them in your fitness function
Yeah! I want to access all solutions that have been evaluated, How to save them?

@robertfeldt
Copy link
Owner

robertfeldt commented Jul 8, 2021

Well, your fitness function will be called for each evaluation so you can just save them yourself. Basic idea:

const AllSolutions = Vector{Float64}[]
function my_saving_fitness(x)
    push!(AllSolutions, x)
    return my_fitness(x)
end

@robertfeldt
Copy link
Owner

This is a single-objective example but should be same for multi-objective:

julia> using BlackBoxOptim

julia> function rosenbrock2d(x)
         return (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2
       end
rosenbrock2d (generic function with 1 method)

julia> const AllSolutions = Vector{Float64}[]
Vector{Float64}[]

julia> function my_saving_fitness(x)
           push!(AllSolutions, x)
           return rosenbrock2d(x)
       end
my_saving_fitness (generic function with 1 method)

julia> res = bboptimize(my_saving_fitness; SearchRange = (-5.0, 5.0), NumDimensions = 2, TraceMode=:silent, MaxFuncEvals=1000);

julia> length(AllSolutions)
1002

The exact number of evaluations is not exactly that of the MaxFuncEvals value since different optimization algorithms might need some number of evals before starting the main loop etc. But it should be fairly limited how many "extra" evals are used.

@Siyuan-hub
Copy link
Author

This is a single-objective example but should be same for multi-objective:

julia> using BlackBoxOptim

julia> function rosenbrock2d(x)
         return (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2
       end
rosenbrock2d (generic function with 1 method)

julia> const AllSolutions = Vector{Float64}[]
Vector{Float64}[]

julia> function my_saving_fitness(x)
           push!(AllSolutions, x)
           return rosenbrock2d(x)
       end
my_saving_fitness (generic function with 1 method)

julia> res = bboptimize(my_saving_fitness; SearchRange = (-5.0, 5.0), NumDimensions = 2, TraceMode=:silent, MaxFuncEvals=1000);

julia> length(AllSolutions)
1002

The exact number of evaluations is not exactly that of the MaxFuncEvals value since different optimization algorithms might need some number of evals before starting the main loop etc. But it should be fairly limited how many "extra" evals are used.

Thank you for your help! I have tried it, this is very useful to me. But In the AllSolutions, there are just all sets of parameters' values, How can I also get all corresponding fitness values?

@robertfeldt
Copy link
Owner

Before you return the fitness to BBO just save it in a similar manner.

const AllSolutions = Vector{Float64}[]
const AllFitnesses = Float64[]
function my_saving_fitness(x)
    push!(AllSolutions, x)
    f = my_fitness(x)
    push!(AllFitnesses, f)
    return f
end

@Siyuan-hub
Copy link
Author

Before you return the fitness to BBO just save it in a similar manner.

const AllSolutions = Vector{Float64}[]
const AllFitnesses = Float64[]
function my_saving_fitness(x)
    push!(AllSolutions, x)
    f = my_fitness(x)
    push!(AllFitnesses, f)
    return f
end

I really appreciate it! Thanks a lot!

@Siyuan-hub
Copy link
Author

I have tried the method you told me about. I can get all fitness values and they are different and correct. But when I look at all solutions' values, most of them are the same. So they are not the corresponding solutions to each fitness. And the Best candidates are not in them. I am confused. Could you please tell me why?

-1.48973 | 2.080654 | 0.131677 | 0.07129 | 1.85131 | 449.1027 | 4.377311 | 0.750455 | 3.589066 | 4.519954
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
0.57839 | 3.623444 | 0.211428 | 0.01738 | 4.519063 | 412.6885 | 1.594383 | 0.000269 | 0.104832 | 4.01752
...
...

@robertfeldt
Copy link
Owner

Ah, for some optimization methods they might update the candidate array as they go along. So if you want to be sure to save the candidate at a certain point in time you can deepcopy them. Of course, they might still evaluate the same (or close to the same) candidate when getting close to the optimum when it is hard to make any real progress.

using BlackBoxOptim

function rosenbrock(x)
    return( sum( 100*( x[2:end] .- x[1:end-1].^2 ).^2 .+ ( x[1:end-1] .- 1 ).^2 ) )
end

AllSolutions = Vector{Float64}[]

function my_saving_fitness(x)
    global AllSolutions
    push!(AllSolutions, deepcopy(x))
    return rosenbrock(x)
end

res = bboptimize(my_saving_fitness; SearchRange = (-5.0, 5.0), NumDimensions = 2, TraceMode=:silent, 
            MaxFuncEvals=1000);

length(AllSolutions) # I get 1002 here
length(unique(AllSolutions)) # I get about 940 here

@Siyuan-hub
Copy link
Author

Ah, for some optimization methods they might update the candidate array as they go along. So if you want to be sure to save the candidate at a certain point in time you can deepcopy them. Of course, they might still evaluate the same (or close to the same) candidate when getting close to the optimum when it is hard to make any real progress.

using BlackBoxOptim

function rosenbrock(x)
    return( sum( 100*( x[2:end] .- x[1:end-1].^2 ).^2 .+ ( x[1:end-1] .- 1 ).^2 ) )
end

AllSolutions = Vector{Float64}[]

function my_saving_fitness(x)
    global AllSolutions
    push!(AllSolutions, deepcopy(x))
    return rosenbrock(x)
end

res = bboptimize(my_saving_fitness; SearchRange = (-5.0, 5.0), NumDimensions = 2, TraceMode=:silent, 
            MaxFuncEvals=1000);

length(AllSolutions) # I get 1002 here
length(unique(AllSolutions)) # I get about 940 here

Okay! Thanks for your reply and help!

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

No branches or pull requests

2 participants