From 94cdff971eab0fad24cdaa9dc7337217a1f54e47 Mon Sep 17 00:00:00 2001 From: Alnusjaponica <50256998+Alnusjaponica@users.noreply.github.com> Date: Fri, 10 Feb 2023 18:13:56 +0900 Subject: [PATCH 1/5] Add FAQ on combinatorial search space --- docs/source/faq.rst | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/docs/source/faq.rst b/docs/source/faq.rst index e2271b0ed5..bdd5acd7b9 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -617,3 +617,54 @@ will retry failed trials when a new trial starts to evaluate. ) study = optuna.create_study(storage=storage) + + +How can deal with permutation as a parameter? +-------------------------------------------- +Sometimes you may want to use combinatorial search space such as permutation. +However, it is difficult to suggest combinatorial parameters as they are and it is not straightforward to suggest them using existing API. + +For permutation set out of :math:`n` items, +there exists a convenient technique is to re-parametrize permutation search space as independent :math:`n` dimension int search space since with `Lehmer code `_ +as explained `here `_. +The :math:`i`-th entry of Lehmer code keeps how many inversions the :math:`i`-th entry of the permutation has after itself +and the sum of the Lehmer code entries corresponds to the minimum necessary adjacent transpositions to transform the permutation into the identity permutation. +Therefore, Lehmer code not only encodes permutations into independent int space, but also represents "positions" in the permutation set. +Optuna implementation is as follows: + +.. code-block:: python + import optuna + import numpy as np + + points = np.array( + [ + [0., 0.], + [1., 0.], + [0., 1.], + [1., 1.], + [2., 2.] + ] + ) + n = len(points) + + def decode(lehmer_code): + all_indices = list(range(n)) + output = [] + for k in lehmer_code: + value = all_indices[k] + output.append(value) + all_indices.remove(value) + return output + + def objective(trial): + lehmer_code = [trial.suggest_int(f"x{i}", 0, n-i-1) for i in range(n)] + permutation = decode(lehmer_code) + total_distance = 0 + for i in range(n): + total_distance += np.linalg.norm(points[permutation[i%n]]- points[permutation[(i+1)%n]]) + return total_distance + + study = optuna.create_study() + study.optimize(objective, n_trials=10) + lehmer_code = study.best_params.values() + print(decode(lehmer_code)) From bdb266638497d6932c167dad28d26a8dc87126b9 Mon Sep 17 00:00:00 2001 From: Alnusjaponica <50256998+Alnusjaponica@users.noreply.github.com> Date: Thu, 16 Feb 2023 14:35:16 +0900 Subject: [PATCH 2/5] Modify objective() in toy problem --- docs/source/faq.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/source/faq.rst b/docs/source/faq.rst index bdd5acd7b9..b1844c77dd 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -642,10 +642,11 @@ Optuna implementation is as follows: [1., 0.], [0., 1.], [1., 1.], - [2., 2.] + [2., 2.], + [-1., -1.] ] ) - n = len(points) + n = len(points) - 1 def decode(lehmer_code): all_indices = list(range(n)) @@ -659,12 +660,15 @@ Optuna implementation is as follows: def objective(trial): lehmer_code = [trial.suggest_int(f"x{i}", 0, n-i-1) for i in range(n)] permutation = decode(lehmer_code) + permutation.append(n) total_distance = 0 - for i in range(n): + for i in range(n+1): total_distance += np.linalg.norm(points[permutation[i%n]]- points[permutation[(i+1)%n]]) return total_distance study = optuna.create_study() study.optimize(objective, n_trials=10) + permutation = decode(lehmer_code) + permutation.append(n) lehmer_code = study.best_params.values() print(decode(lehmer_code)) From a23c1632d13391d871d3ef8092700339c96b8e46 Mon Sep 17 00:00:00 2001 From: Alnusjaponica <50256998+Alnusjaponica@users.noreply.github.com> Date: Thu, 16 Feb 2023 15:06:13 +0900 Subject: [PATCH 3/5] Fix Sphinx error --- docs/source/faq.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/faq.rst b/docs/source/faq.rst index b1844c77dd..57557f65df 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -620,7 +620,7 @@ will retry failed trials when a new trial starts to evaluate. How can deal with permutation as a parameter? --------------------------------------------- +--------------------------------------------- Sometimes you may want to use combinatorial search space such as permutation. However, it is difficult to suggest combinatorial parameters as they are and it is not straightforward to suggest them using existing API. @@ -633,6 +633,7 @@ Therefore, Lehmer code not only encodes permutations into independent int space, Optuna implementation is as follows: .. code-block:: python + import optuna import numpy as np From a0f2238fb31728861c866888635bf15571061850 Mon Sep 17 00:00:00 2001 From: Shinichi Hemmi <50256998+Alnusjaponica@users.noreply.github.com> Date: Thu, 1 Jun 2023 14:34:26 +0900 Subject: [PATCH 4/5] Update explanation --- docs/source/faq.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/source/faq.rst b/docs/source/faq.rst index 57557f65df..f239b7f765 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -621,15 +621,16 @@ will retry failed trials when a new trial starts to evaluate. How can deal with permutation as a parameter? --------------------------------------------- -Sometimes you may want to use combinatorial search space such as permutation. -However, it is difficult to suggest combinatorial parameters as they are and it is not straightforward to suggest them using existing API. +Sometimes, you may want to use a combinatorial search space, such as permutations. +However, suggesting combinatorial parameters in their original form is challenging, and it is not straightforward to accomplish this task using existing APIs. -For permutation set out of :math:`n` items, -there exists a convenient technique is to re-parametrize permutation search space as independent :math:`n` dimension int search space since with `Lehmer code `_ -as explained `here `_. -The :math:`i`-th entry of Lehmer code keeps how many inversions the :math:`i`-th entry of the permutation has after itself +To address this, a convenient technique exists for permutation sets of :math:n items. +It involves re-parametrization of permutation search space as an independent :math:n-dimensional integer search space. +This technique is based on the concept of `Lehmer code `_, which is also explained `here `_. + +In Lehmer code, the :math:`i`-th entry keeps how many inversions the :math:`i`-th entry of the permutation has after itself and the sum of the Lehmer code entries corresponds to the minimum necessary adjacent transpositions to transform the permutation into the identity permutation. -Therefore, Lehmer code not only encodes permutations into independent int space, but also represents "positions" in the permutation set. +Therefore, Lehmer code not only encodes permutations into independent int space, but also provides a representation of the "positions" within the permutation set. Optuna implementation is as follows: .. code-block:: python From c1d53b66cf402aa51a29e81aa3babbf881edd5fc Mon Sep 17 00:00:00 2001 From: Shinichi Hemmi <50256998+Alnusjaponica@users.noreply.github.com> Date: Thu, 1 Jun 2023 16:52:06 +0900 Subject: [PATCH 5/5] Update docs --- docs/source/faq.rst | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/source/faq.rst b/docs/source/faq.rst index f239b7f765..210f310cde 100644 --- a/docs/source/faq.rst +++ b/docs/source/faq.rst @@ -621,16 +621,19 @@ will retry failed trials when a new trial starts to evaluate. How can deal with permutation as a parameter? --------------------------------------------- -Sometimes, you may want to use a combinatorial search space, such as permutations. -However, suggesting combinatorial parameters in their original form is challenging, and it is not straightforward to accomplish this task using existing APIs. -To address this, a convenient technique exists for permutation sets of :math:n items. -It involves re-parametrization of permutation search space as an independent :math:n-dimensional integer search space. -This technique is based on the concept of `Lehmer code `_, which is also explained `here `_. +Although it is not straightforward to deal with combinatorial search spaces like permutations with existing API, there exists a convenient technique for handling them. +It involves re-parametrization of permutation search space of :math:`n` items as an independent :math:`n`-dimensional integer search space. +This technique is based on the concept of `Lehmer code `_, which is also explained in: `Vizier document `_. -In Lehmer code, the :math:`i`-th entry keeps how many inversions the :math:`i`-th entry of the permutation has after itself -and the sum of the Lehmer code entries corresponds to the minimum necessary adjacent transpositions to transform the permutation into the identity permutation. -Therefore, Lehmer code not only encodes permutations into independent int space, but also provides a representation of the "positions" within the permutation set. +A Lehmer code of a sequence is the sequence of integers in the same size, whose :math:`i`-th entry denotes how many inversions the :math:`i`-th entry of the permutation has after itself. +In other words, the :math:`i`-th entry of the Lehmer code represents the number of entries that are located after and are smaller than the :math:`i`-th entry of the original sequence. +For instance, the Lehmer code of the permutation :math:`(3, 1, 4, 2, 0)` is :math:`(3, 1, 2, 1, 0)`. + +Not only does the Lehmer code provide a unique encoding of permutations into an integer space, but it also has some desirable properties. +For example, the sum of a Lehmer code entries is equal to the minimum number of adjacent transpositions necessary to transform the corresponding permutation into the identity permutation. +Additionally, the lexicographical order of the encodings of two permutations is the same as that of the original sequence. +Therefore, Lehmer code preserves "closeness" among permutations in some sense, which is important for the optimization algorithm. Optuna implementation is as follows: .. code-block:: python