Meta.Problem (TP I v0.1.0) View Source

Definition of an arbitrary optimization problem to be solved using meta-heuristics.

To use a problem definition you must provide the variables list and the objective function. The objective arity must match the variables length and must be placed in a sorted order as the function must be called.

This module also acknowledges some common functions around Problem solving.

Link to this section Summary

Functions

Applies the objective function with variables and yields a Solution struct with the function result and the variables used, useful for logging or history registry.

Compares two solutions and returns if the first is better than the second, based on the problem's type (:minimization or :maximization).

Seeds a variable value field if its nil, generating a random variable value respecting its constraint definitions. If the variable already has a value, nothing is changed, hence the maybe name.

Tweak a variable value, to a maximum of a matching variable name in noise_sizes. The constraints of the variable are respected, so the maximum delta change may be lower than the noise_size found.

Flattens a solution map to a one-dimensional for serialiation purpose.

Tweak a variable value, to a maximum of a noise_size. The constraints of the variable are respected, so the maximum delta change may be lower than the noise_size found.

Link to this section Types

Specs

t() :: %Meta.Problem{
  objective: (... -> float()),
  solution: Meta.Problem.Solution.t() | nil,
  type: :minimization | :maximization,
  variables: [Meta.Problem.Variable.t()]
}

Link to this section Functions

Link to this function

fetch_solution(objective, variables)

View Source

Specs

fetch_solution((... -> float()), [Meta.Problem.Variable.t()]) ::
  Meta.Problem.Solution.t()

Applies the objective function with variables and yields a Solution struct with the function result and the variables used, useful for logging or history registry.

# Examples

iex> fetch_solution(&Meta.Functions.simple_example/1, [%Meta.Problem.Variable{name: :x, value: 3, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 100}}])
%Meta.Problem.Solution{value: 9, variables: [%Meta.Problem.Variable{name: :x, value: 3, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 100}}]}

iex> fetch_solution(&Meta.Functions.example_one/2, [%Meta.Problem.Variable{name: :x, value: 10, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 100}}, %Meta.Problem.Variable{name: :y, value: 4, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 100}}])
%Meta.Problem.Solution{value: 32.99060735569487, variables: [%Meta.Problem.Variable{name: :x, value: 10, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 100}}, %Meta.Problem.Variable{name: :y, value: 4, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 100}}]}
Link to this function

is_better?(arg1, arg2, arg3)

View Source

Specs

is_better?(
  Meta.Problem.Solution.t(),
  Meta.Problem.Solution.t(),
  :minimization | :maximization
) :: boolean()

Compares two solutions and returns if the first is better than the second, based on the problem's type (:minimization or :maximization).

# Examples

iex> is_better?(%Meta.Problem.Solution{value: 2, variables: []}, %Meta.Problem.Solution{value: 1, variables: []}, :minimization)
false

iex> is_better?(%Meta.Problem.Solution{value: 2, variables: []}, %Meta.Problem.Solution{value: 1, variables: []}, :maximization)
true
Link to this function

maybe_generate_random_variable_value(variable)

View Source

Specs

maybe_generate_random_variable_value(Meta.Problem.Variable.t()) ::
  Meta.Problem.Variable.t()

Seeds a variable value field if its nil, generating a random variable value respecting its constraint definitions. If the variable already has a value, nothing is changed, hence the maybe name.

# Examples

iex> :rand.seed(:exsplus, {101, 102, 103})
iex> maybe_generate_random_variable_value(%Meta.Problem.Variable{name: :x, value: nil, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}})
%Meta.Problem.Variable{name: :x, value: 1.489738081165117, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}

iex> maybe_generate_random_variable_value(%Meta.Problem.Variable{name: :x, value: 1, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}})
%Meta.Problem.Variable{name: :x, value: 1, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}
Link to this function

maybe_tweak_variable(variable, probability, noise_sizes)

View Source

Tweak a variable value, to a maximum of a matching variable name in noise_sizes. The constraints of the variable are respected, so the maximum delta change may be lower than the noise_size found.

The variable is only tweaked if a probability check passes (a random float between 0 and 1 is lower than the probability argument).

It raises an Error if the probability is not between 0 and 1 # Examples

iex> :rand.seed(:exsplus, {101, 102, 103})
iex> maybe_tweak_variable(%Meta.Problem.Variable{name: :x, value: 1, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}, 1, [x: 0.25])
%Meta.Problem.Variable{name: :x, value: 0.978631679333307, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}

iex> maybe_tweak_variable(%Meta.Problem.Variable{name: :x, value: 1, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}, 0, [x: 0.25])
%Meta.Problem.Variable{name: :x, value: 1, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}

iex> :rand.seed(:exsplus, {101, 102, 103})
iex> maybe_tweak_variable(%Meta.Problem.Variable{name: :x, value: 1, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}, 1, [x: 5000])
%Meta.Problem.Variable{name: :x, value: 0.9145267173332277, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}

Specs

serialize(Meta.Problem.Solution.t()) :: map()

Flattens a solution map to a one-dimensional for serialiation purpose.

The key value of solution is passed on along each variable name as key and its corresponding values as value.

Examples

iex> serialize(%Meta.Problem.Solution{value: 5, variables: [%Meta.Problem.Variable{name: :x, value: 0.25}, %Meta.Problem.Variable{name: :y, value: 0.5}]})
%{value: 5, x: 0.25, y: 0.5}
Link to this function

tweak_variable(variable, noise_size)

View Source

Specs

Tweak a variable value, to a maximum of a noise_size. The constraints of the variable are respected, so the maximum delta change may be lower than the noise_size found.

# Examples

iex> :rand.seed(:exsplus, {101, 102, 103})
iex> tweak_variable(%Meta.Problem.Variable{name: :x, value: 1, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}, 0.25)
%Meta.Problem.Variable{name: :x, value: 1.1224345202912793, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}

iex> :rand.seed(:exsplus, {101, 102, 103})
iex> tweak_variable(%Meta.Problem.Variable{name: :x, value: 1, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}, 5000)
%Meta.Problem.Variable{name: :x, value: 1.489738081165117, constraint: %Meta.Problem.Constraint{lower_boundary: 0, higher_boundary: 2}}