Combines multiple operators and makes operator-configuration parameters self-adaptive.
The OperatorCombination
operators combine operators for different subspaces of individuals by wraping other MiesOperator
s given during construction.
Different MiesOperator
s are assigned to different components or sets of components and operate on them independently of the rest of the components
or the other operators. An operator can be assigned to a single component by giving it in operators
with the name of the component, or to multiple components by
giving it in operators
with the name of a group. Groups are created by the groups
argument, but several default groups that catch components by type
exist.
Operators can be made self-adaptive by coupling their configuration parameter values to values in individuals. This is done by giving functions in adaptions
; these
functions are executed for each individual before an operator is applied, and the result given to a named operator configuration parameter.
OperatorCombination
is the base class from which MutatorCombination
and RecombinatorCombination
inherit. The latter two are to be used for Mutator
and
Recombinator
objects, respectively.
Besides groups created with the groups
construction argument, there are special groups that all unnamed operators fall into based on their Param
class: "ParamInt"
, "ParamDbl"
, "ParamFct"
, and "ParamLgl"
. A component of an individual that is not named directly in operators
or made part of a group
in groups
is automatically in one of these special groups. There is furthermore a special catch-all group "ParamAny"
, which catches all components that are
are not operated directly, not in a group, and not in another special group that is itself named directly or in a group. I.e., all components that would otherwise
have no assigned operation.
RecombinatorCombination
can only combine operators where $n_indivs_in
and $n_indivs_out
can be combined. This is
currently supported either when $n_indivs_in
and $n_indivs_out
for each operator are the same (but $n_indivs_in
may be unequal $n_indivs_out
in
eacho of them); or when $n_indivs_in
is equal to $n_indivs_out
for each operator and the set of all $n_indivs_in
that occur contains 1
and one more integer.
$n_indivs_in
and $n_indivs_out
for the resulting RecombinatorCombination
operator will be set the maximum of occuring $n_indivs_in
and $n_indivs_out
,
respectively.
Supported Param
classes are calculated based on the supported classes of the wrapped operators.
They are frequently just the set union of supported classes, unless inference can be drawn from type-specific groups that an operator is assigned to.
If e.g. an operator that supports ParamDbl
and ParamInt
is assigned to group "ParamInt"
, and
an operator that supports ParamLgl
is assigned to component "a"
, then the result will support ParamLgl
and
ParamInt
only.
The OperatorCombination
has the configuration parameters of all encapsulated MiesOperator
s, minus the configuration parameters that are named in the adaptions
.
Configuration parameter names are prefixed with the name of the MiesOperator
in the operators
list.
This Mutator
can be created with the short access form mut()
(muts()
to get a list), or through the the dictionary
dict_mutators
in the following way:
# preferred:
mut("combine", <operators>, ...)
muts("combine", <operators>, ...) # takes vector IDs, returns list of Mutators
# long form:
dict_mutators$get("combine", <operators>, ...)
This Recombinator
can be created with the short access form rec()
(recs()
to get a list), or through the the dictionary
dict_recombinators
in the following way:
Other base classes:
Filtor
,
FiltorSurrogate
,
MiesOperator
,
Mutator
,
MutatorDiscrete
,
MutatorNumeric
,
Recombinator
,
RecombinatorPair
,
Scalor
,
Selector
,
SelectorScalar
Other mutators:
Mutator
,
MutatorDiscrete
,
MutatorNumeric
,
dict_mutators_cmpmaybe
,
dict_mutators_erase
,
dict_mutators_gauss
,
dict_mutators_maybe
,
dict_mutators_null
,
dict_mutators_proxy
,
dict_mutators_sequential
,
dict_mutators_unif
Other mutator wrappers:
dict_mutators_cmpmaybe
,
dict_mutators_maybe
,
dict_mutators_proxy
,
dict_mutators_sequential
Other recombinators:
Recombinator
,
RecombinatorPair
,
dict_recombinators_cmpmaybe
,
dict_recombinators_convex
,
dict_recombinators_cvxpair
,
dict_recombinators_maybe
,
dict_recombinators_null
,
dict_recombinators_proxy
,
dict_recombinators_sbx
,
dict_recombinators_sequential
,
dict_recombinators_swap
,
dict_recombinators_xonary
,
dict_recombinators_xounif
Other recombinator wrappers:
dict_recombinators_cmpmaybe
,
dict_recombinators_maybe
,
dict_recombinators_proxy
,
dict_recombinators_sequential
miesmuschel::MiesOperator
-> OperatorCombination
operators
(named list
of MiesOperator
)
List of operators to apply to components of individuals, as set during construction. Read-only.
groups
(named list
of character
)
List of groups that operators can act on, as set during construction. Read-only.
adaptions
(named list
of function
)
List of functions used for self-adaption of operators, as set during construction. Read-only.
binary_fct_as_logical
(logical(1)
)
Whether to treat binary ParamFct
components of ParamSet
s as ParamLgl
with respect
to the special groups "ParamLgl"
and "ParamFct"
, as set during construction. Read-only.
on_type_not_present
(character(1)
)
Action to perform during $prime()
when an operator is assigned to a type special group but there is no component available that falls in this group.
See the construction argument. Can be changed during the object's lifetime.
on_name_not_present
(character(1)
)
Action to perform during $prime()
when an operator is assigned to a specifically named component, but the component is not present.
See the construction argument. Can be changed during the object's lifetime.
new()
Initialize the OperatorCombination
object.
OperatorCombination$new(
operators,
groups = list(),
adaptions = list(),
binary_fct_as_logical = FALSE,
on_type_not_present = "warn",
on_name_not_present = "stop",
granularity = 1,
dict_entry = NULL,
dict_shortaccess = NULL
)
operators
(named list
of MiesOperator
)
List of operators to apply to components of individuals. Names are either names of individual components, or group names which are either as defined
through groups
or special groups. Individual components can only be member of either a (non-special) group or named in operators
, so a name
that occurs in operators
may not be a member of a group as defined in groups
.
The $operators
field will reflect this value.
groups
(named list
of character
)
List of groups that operators can act on. Names of this list define new groups. The content of each list element contains the names of
components or special groups (a Param
subclass name or "ParamAny"
) to subsume under the group.
Individual components can only be member of either a (non-special) group or named in operators
, so a name
that occurs in operators
may not be a member of a group as defined in groups
. The default is the empty list.
The $groups
field will reflect this value.
adaptions
(named list
of function
)
List of functions used for self-adaption of operators. The names of the list must be names of configuration parameters of wrapped operators, prefixed
with the corresponding name in the operators
list. This is the same name as the configuration parameter would otherwise have if exposed by the
OperatorCombination
object. The values in the list must be functions that receive a single input, the individual or individuals being operated on,
as a data.table
. It must return a value that is then assigned to the configuration parameter of the operator to which it pertains.
Note that MutatorCombination
adaption functions are always called with a data.table
containing a single row, while
RecombinatorCombination
adaption functions are called with data.table
s with multiple rows according to $n_indivs_in
.
In both cases, the return value must be a scalar. The default is the empty list.
The $adaption
field will reflect this value.
binary_fct_as_logical
(logical(1)
)
Whether to treat binary ParamFct
components of ParamSet
s as ParamLgl
with respect
to the special groups "ParamLgl"
and "ParamFct"
. This does not perform any conversion, so a MiesOperator
assigned to the "ParamLgl"
special
group when binary_fct_as_logical
is TRUE
and there are binary ParamFct
s present will receive
a factorial value and must also support ParamFct
in this case. This is checked during $prime()
, but not during construction.
Default is FALSE
.
The $binary_fct_as_logical
field will reflect this value.
on_type_not_present
(character(1)
)
Action to perform during $prime()
when an operator is assigned to a type special group but there is no component available that falls in this group, either
because no components of the respective type are present, or because all these components are also directly named in operators
or in groups
.
One of "quiet"
(do nothing), "warn"
(give warning, default), or "stop"
(generate an error).
The writable $on_type_not_present
field will reflect this value.
on_name_not_present
(character(1)
)
Action to perform during $prime()
when an operator is assigned to a specifically named component, but the component is not present.
One of "quiet"
(do nothing), "warn"
(give warning), or "stop"
(generate an error, default).
The writable $on_name_not_present
field will reflect this value.
granularity
(integer(1)
)
At what granularity to query adaptions
for sets of individuals. Functions in adaptions
are always called once per granularity
individuals
in input values
, and the function argument in these calls will then have granularity
number of rows. This is used internally, it is set to
1 for MutatorCombination
, and to $n_indivs_in
for RecombinatorCombination
.
dict_entry
(character(1)
| NULL
)
Key of the class inside the Dictionary
(usually one of
dict_mutators
, dict_recombinators
, dict_selectors
), where it can
be retrieved using a short access function. May be NULL
if the operator
is not entered in a dictionary.
The $dict_entry
field will reflect this value.
dict_shortaccess
(character(1)
| NULL
)
Name of the Dictionary
short access function in which the operator is registered.
This is used to inform the user about how to construct a given object. Should ordinarily be one of
"mut"
, "rec"
, "sel"
.
The $dict_shortaccess
field will reflect this value.
prime()
See MiesOperator
method. Primes both this operator, as well as the wrapped operators
given to operators
during construction. Priming of wrapped operators happens according
to component assignments to wrapped operators.
param_set
(ParamSet
)
Passed to MiesOperator
$prime()
.
invisible self
.
miesmuschel::MiesOperator
-> miesmuschel::OperatorCombination
-> MutatorCombination
new()
Initialize the MutatorCombination
object.
MutatorCombination$new(
operators = list(),
groups = list(),
adaptions = list(),
binary_fct_as_logical = FALSE,
on_type_not_present = "warn",
on_name_not_present = "stop"
)
miesmuschel::MiesOperator
-> miesmuschel::OperatorCombination
-> RecombinatorCombination
n_indivs_in
(integer(1)
)
Number of individuals to consider at the same time. When operating, the number of input individuals must be divisible by this number.
n_indivs_out
(integer(1)
)
Number of individuals produced for each group of $n_indivs_in
individuals.
new()
Initialize the RecombinatorCombination
object.
RecombinatorCombination$new(
operators = list(),
groups = list(),
adaptions = list(),
binary_fct_as_logical = FALSE,
on_type_not_present = "warn",
on_name_not_present = "stop"
)
set.seed(1)
data = data.frame(x = 0, y = 0, a = TRUE, b = "a",
stringsAsFactors = FALSE) # necessary for R <= 3.6
p = ps(x = p_dbl(-1, 1), y = p_dbl(-1, 1), a = p_lgl(), b = p_fct(c("a", "b")))
# Demo operators:
m0 = mut("null") # no mutation
msmall = mut("gauss", sdev = 0.1) # mutates to small value around 0
mbig = mut("gauss", sdev = 100) # likely mutates to +1 or -1
mflip = mut("unif", can_mutate_to_same = FALSE) # flips TRUE/"a" to FALSE/"b"
# original:
data
#> x y a b
#> 1 0 0 TRUE a
# operators by name
op = mut("combine", operators = list(x = msmall, y = mbig, a = m0, b = mflip))
op$prime(p)
op$operate(data)
#> x y a b
#> 1 -0.1252908 1 TRUE b
# operators by type
op = mut("combine",
operators = list(ParamDbl = msmall, ParamLgl = m0, ParamFct = mflip)
)
op$prime(p)
op$operate(data)
#> x y a b
#> 1 0.2544859 0.08292829 TRUE b
# the binary ParamFct 'b' counts as 'ParamLgl' when
# 'binary_fct_as_logical' is set to 'TRUE'.
op = mut("combine",
operators = list(ParamDbl = msmall, ParamLgl = m0),
binary_fct_as_logical = TRUE
)
op$prime(p)
op$operate(data)
#> x y a b
#> 1 -0.1640937 0.09748581 TRUE a
# operators by type; groups can be mixed types
op = mut("combine",
operators = list(group1 = m0, group2 = msmall, group3 = mflip),
groups = list(group1 = c("a", "x"), group2 = "y", group3 = "b")
)
op$prime(p)
op$operate(data)
#> a x y b
#> 1 TRUE 0 0.1476649 b
# Special type-groups can be used inside groups.
op = mut("combine",
operators = list(group1 = m0, b = mflip),
groups = list(group1 = c("ParamDbl", "a"))
)
op$prime(p)
op$operate(data)
#> a x y b
#> 1 TRUE 0 0 b
# Type-groups only capture all parameters that were not caught by name.
# The special 'ParamAny' group captures all that is left.
op = mut("combine",
operators = list(ParamAny = m0, ParamDbl = msmall, x = mbig)
)
op$prime(p)
op$operate(data)
#> a b y x
#> 1 TRUE a -0.06107768 1
# Configuration parameters are named by names in the 'operators' list.
op$param_set
#> <ParamSetShadow>
#> id class lower upper nlevels
#> <char> <char> <num> <num> <num>
#> 1: ParamDbl.sdev ParamUty NA NA Inf
#> 2: ParamDbl.sdev_is_relative ParamLgl NA NA 2
#> 3: ParamDbl.truncated_normal ParamLgl NA NA 2
#> 4: x.sdev ParamUty NA NA Inf
#> 5: x.sdev_is_relative ParamLgl NA NA 2
#> 6: x.truncated_normal ParamLgl NA NA 2
#> default
#> <list>
#> 1: <NoDefault>\n Public:\n clone: function (deep = FALSE) \n initialize: function ()
#> 2: <NoDefault>\n Public:\n clone: function (deep = FALSE) \n initialize: function ()
#> 3: <NoDefault>\n Public:\n clone: function (deep = FALSE) \n initialize: function ()
#> 4: <NoDefault>\n Public:\n clone: function (deep = FALSE) \n initialize: function ()
#> 5: <NoDefault>\n Public:\n clone: function (deep = FALSE) \n initialize: function ()
#> 6: <NoDefault>\n Public:\n clone: function (deep = FALSE) \n initialize: function ()
#> value
#> <list>
#> 1: 0.1
#> 2: TRUE
#> 3: FALSE
#> 4: 100
#> 5: TRUE
#> 6: FALSE
###
# Self-adaption:
# In this example, the 'ParamDbl''s operation is changed depending on the
# value of 'b'.
op = mut("combine",
operators = list(ParamAny = m0, ParamLgl = mflip, ParamDbl = msmall),
adaptions = list(ParamDbl.sdev = function(x) if (x$a) 100 else 0.1)
)
op$prime(p)
data2 = data[c(1, 1, 1, 1), ]
data2$a = c(TRUE, TRUE, FALSE, FALSE)
data2
#> x y a b
#> 1 0 0 TRUE a
#> 1.1 0 0 TRUE a
#> 1.2 0 0 FALSE a
#> 1.3 0 0 FALSE a
# Note the value of x$a gets used line-wise, and that it is used *before*
# being flipped here. So the first two lines get large mutations, even though
# they have 'a' 'FALSE' after the operation.
op$operate(data2)
#> b a x y
#> 1 a FALSE -1.0000000 -1.00000000
#> 2 a FALSE 1.0000000 -1.00000000
#> 3 a TRUE -0.1783842 0.08713666
#> 4 a TRUE 0.1187803 0.18379547