Compare commits

...
524 Commits
Author SHA1 Message Date
Marcus Edel f974ea0945 Merge pull request #343 from zoq/release-2.19.0
Release version 2.19.0: "Eight Ball Deluxe"
2022-04-08 21:10:49 -04:00
Marcus Edel a30c1a98b3 Add new block for next release to HISTORY.md. 2022-04-06 20:55:31 -04:00
Marcus Edel a5b57ba657 Update and release version 2.19.0. 2022-04-06 20:55:31 -04:00
conradsnicta 99147a88b1 bump check for min supported version of armadillo (#342)
followup to #318
2022-04-06 05:15:58 +02:00
Marcus Edel 1fd8d34e28 Merge pull request #211 from zoq/DemonSGD
DemonSGD & DemonAdam.
2022-04-05 20:47:19 -04:00
Marcus Edel a33dc777fc Merge branch 'master' into DemonSGD 2022-04-01 23:14:06 -04:00
Marcus Edel 394926879f Merge pull request #340 from rcurtin/iteration-in-update-policy
Move `iteration` member into UpdatePolicy classes.
2022-03-27 21:10:15 -04:00
Ryan Curtin 097024c656 Fix some dead store issues. 2022-03-25 18:21:39 -04:00
Ryan Curtin ab4481a387 Add a test to ensure that resetting the update policy works. 2022-03-25 17:56:45 -04:00
Ryan Curtin dbcc51062d Fix a couple PVS-Studio issues. 2022-03-24 21:06:23 -04:00
Ryan Curtin 4d9d060d15 Update HISTORY. 2022-03-23 18:55:49 -04:00
Ryan Curtin 9f5ab09db6 Move iteration member into UpdatePolicy classes. 2022-03-23 18:52:29 -04:00
Marcus Edel 5990bac4c6 Make demon test suite more stable. 2022-03-02 21:31:50 -05:00
Marcus Edel 69abe29952 Merge pull request #234 from zoq/ada_sqrt
AdaSqrt - Second-order Information in First-order Optimization Methods.
2022-02-28 20:48:28 -05:00
Marcus Edel 063f1eb364 Adjust CNE Himmelblau optimizer settings to make the test case more robust. 2022-02-27 22:01:19 -05:00
Marcus Edel 9929e1c81e Use smaller step size for the first iteration to stabilize the test suite. 2022-02-26 21:17:46 -05:00
Marcus Edel 8d68925e11 Use smaller step size for the first iteration to stabilize the test suite. 2022-02-24 22:06:58 -05:00
Marcus Edel df69ffb564 Unify header inclusion format. 2022-02-23 20:39:32 -05:00
Marcus Edel bb31a4455a Unify header inclusion format. 2022-02-22 21:54:06 -05:00
Marcus Edel 0dfa8fb929 Remove superfluous header. 2022-02-21 18:09:45 -05:00
Marcus Edel 69d6cf178c Unify header inclusion format. 2022-02-21 18:09:45 -05:00
Marcus EdelandConrad Sanderson 7776391f21 Use armadillo function to square the gradient.
Co-authored-by: Conrad Sanderson <conradsnicta@users.noreply.github.com>
2022-02-20 20:23:36 -05:00
Marcus Edel 3d31cc03ea Use the correct optimizer for the AdaSqrt test suite. 2022-02-19 13:23:02 -05:00
Marcus Edel 3486dd16b1 Update test suits to use updated test framework. 2022-02-18 21:52:19 -05:00
Marcus Edel be570d5ff9 Merge branch 'master' into ada_sqrt 2022-02-18 21:45:11 -05:00
Marcus EdelandRyan Curtin 3fe169e453 Correct test author.
Co-authored-by: Ryan Curtin <ryan@ratml.org>
2022-02-18 21:44:27 -05:00
Marcus Edel 8afcc2e31f Merge pull request #233 from zoq/ada_belief
AdaBelief - Adapting Stepsizes by the Belief in Observed Gradients.
2022-02-18 19:42:51 -05:00
Marcus Edel 30f56ac990 Merge branch 'master' into ada_belief 2022-02-18 16:10:48 -05:00
Marcus Edel f401c9e95c Merge branch 'master' into DemonSGD 2022-02-17 22:24:45 -05:00
Marcus Edel f1b3cc6fd6 Merge pull request #232 from zoq/yogi
Yogi - Adaptive Methods for Nonconvex Optimization.
2022-02-17 21:41:42 -05:00
Marcus Edel d3686fa6a2 Merge branch 'master' into ada_sqrt 2022-02-17 20:38:56 -05:00
Marcus Edel 3bb5ea6df0 Merge branch 'master' into ada_belief 2022-02-17 20:30:48 -05:00
Marcus Edel 9176ceced3 Use armadillo function to get the square gradient. 2022-02-15 22:12:59 -05:00
Marcus Edel 3383542a4a Update test suits to use updated test framework. 2022-02-15 22:12:42 -05:00
Marcus Edel f5c25cc9aa Remove duplication from the history file. 2022-02-15 20:40:24 -05:00
Marcus Edel 1d584119d3 Merge branch 'master' into yogi 2022-02-15 20:39:11 -05:00
Marcus Edel ba981aad7a Update histroy - add Yogi optimizer. 2022-02-15 20:38:30 -05:00
Ryan Curtin a1a84c8fcb Add new block for next release to HISTORY.md. 2022-02-15 20:38:30 -05:00
Ryan Curtin 80d42cb643 Update and release version 2.18.2. 2022-02-15 20:38:30 -05:00
Marcus Edel 7bc1ee09ea Update test suits to use updated test framework. 2022-02-14 22:29:23 -05:00
Marcus Edel b9413f2bbf Add DemonSGD and DemonAdam optimizer documentation. 2022-02-14 22:27:20 -05:00
Marcus Edel 427d4b600e Merge branch 'master' into DemonSGD 2022-02-14 21:32:03 -05:00
Marcus Edel ec7d984120 Report the correct maximum number of iterations. 2022-02-14 21:30:13 -05:00
Marcus Edel c2ec446c3c Reference Demon typedefs. 2022-02-14 21:27:54 -05:00
Ryan Curtin a14b08f8d7 Add new block for next release to HISTORY.md. 2022-02-14 09:36:35 -05:00
Ryan Curtin 384912f38f Update and release version 2.18.2. 2022-02-14 09:36:35 -05:00
Marcus Edel 694bd1d049 Merge branch 'master' into yogi 2022-02-13 21:42:01 -05:00
Marcus Edel b153c95a5b Extend optimizer description. 2022-02-13 21:41:08 -05:00
Marcus Edel 6506d3a199 Remove unrelated paper from the reference section. 2022-02-13 21:36:40 -05:00
Marcus Edel f077ea57e5 Report the correct epoch time in seconds. (#337) 2022-02-12 05:27:13 +01:00
Conrad Sanderson f75b532d16 update Catch2 to 2.13.8 (#336) 2022-02-02 04:12:47 +01:00
Marcus Edel a652ca2ce5 Add new block for next release to HISTORY.md. 2021-11-20 11:32:46 -05:00
Marcus Edel bf42276c5a Update and release version 2.18.1. 2021-11-20 11:32:46 -05:00
Marcus Edel c35e78e489 SCD partial gradient test fix (#332) 2021-11-19 04:24:23 +01:00
Conrad Sanderson d811ff9738 avoid infinite loop for single-precision matrices (#331) 2021-11-17 15:01:01 +01:00
Marcus Edel 525dd6d961 Merge pull request #330 from zoq/sgd-test-break
Accelerate SGD test time by skipping additional trials.
2021-11-15 21:15:44 -05:00
Marcus Edel 025095a180 Accelerate SGD test time by skiping additional trials. 2021-11-12 23:11:41 -05:00
Marcus Edel c493c55e2e Add new block for next release to HISTORY.md. 2021-10-21 19:45:07 -04:00
Marcus Edel ac933c5dba Update and release version 2.18.0. 2021-10-21 19:45:07 -04:00
Conrad Sanderson ee3f0e1ea2 Merge pull request #327
Fix MOEAD test stability
2021-10-20 04:52:48 +02:00
Ryan CurtinandMarcus Edel 7a8c5ae685 Apply suggestions from code review
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-10-18 11:37:18 -04:00
Ryan Curtin bd285743b3 Some cleanup. 2021-10-18 10:29:23 -04:00
Ryan Curtin 23aab9f924 Factor out constant things from the loop. 2021-10-18 10:07:02 -04:00
Ryan Curtin df3a1cf347 Update HISTORY for #324 too. 2021-10-18 10:02:17 -04:00
Ryan Curtin f3b0224187 Update HISTORY. 2021-10-16 13:02:44 -04:00
Ryan Curtin d58258ff6c Fix MOEAD test stability. 2021-10-16 12:58:29 -04:00
Conrad Sanderson 99de75ce7c Merge pull request #325
Fix for C++20 constructor template argument deprecation
2021-10-14 11:19:23 +02:00
Eliane Briand 0f634056d0 Fix for C++20 constructor template argument deprecation 2021-10-13 15:03:33 +02:00
Conrad Sanderson 1db28cf195 Merge pull request #323
more approachable and impactful blurb to match description on website
2021-10-12 07:09:45 +02:00
Conrad Sanderson a04945ea8b simplify blurb to match description on website 2021-10-11 04:21:26 +02:00
Conrad Sanderson 0c1d98d11c Update Catch2 to 2.13.7 (#322) 2021-09-21 03:46:57 +02:00
Marcus Edel cf434a0ed7 Update history. 2021-09-19 12:39:10 -04:00
Marcus Edel 6ec037e7bb Update Catch2 to 2.13.7. 2021-09-19 12:35:54 -04:00
Conrad Sanderson 38e5c691e9 Revert "Add citation file"
This reverts commit 8f074a421a.
2021-09-07 03:04:21 +02:00
Marcus Edel 8f074a421a Add citation file. (#317) 2021-09-06 02:03:00 +02:00
Marcus Edel 1490193fb0 GradClipByValue callback (#315) 2021-08-31 06:53:03 +02:00
Marcus Edel 1208c62381 Bump minimum Armadillo version to 9.800. (#318)
* Bump minimum Armadillo version to 9.800.
* Update history.
* Download armadillo from the offical source (sourceforge).
2021-08-30 03:58:17 +02:00
Ryan Curtin f90ccda31d Merge pull request #316 from mlpack/conradsnicta-citation-update
update citation to JMLR paper
2021-08-15 15:08:10 -04:00
Conrad Sanderson bf77ef6bde update citation to JMLR paper 2021-08-14 05:21:14 +02:00
Conrad Sanderson 8b4cadf3ab Merge pull request #314 from zoq/travis-update
Update travis config to build the ensmallen tests
2021-08-09 04:51:48 +02:00
Conrad Sanderson c3f71b8099 Merge pull request #313 from zoq/test-build
The BUILD_TESTS option was replaced with 'make ensmallen_tests'.
2021-08-09 04:50:47 +02:00
Marcus Edel 9e8696bdb1 Do not fail the build on a warning. 2021-08-06 18:13:20 +02:00
Marcus Edel 122be35c0f Update travis config to build the ensmallen tests. 2021-08-06 02:58:39 +02:00
Marcus Edel b92e576f88 Update history. 2021-08-05 03:20:51 +02:00
Marcus Edel 7b0e36ec3b The BUILD_TESTS option was replaced with 'make ensmallen_tests'. 2021-08-04 05:09:46 +02:00
Ryan Curtin 237daa9c78 Merge pull request #310 from jonpsy/release-2.17.0
Release version 2.17.0: "Pachis Din Me Pesa Double"
2021-07-06 14:59:06 -04:00
Nanubala Gnana Sai c45abbdd9f Add new block for next release to HISTORY.md. 2021-07-06 16:09:25 +00:00
Nanubala Gnana Sai 9bd4bc2527 Update and release version 2.17.0. 2021-07-06 16:09:25 +00:00
Nanubala Gnana Sai 000d4c8488 Update HISTORY.md for release 2.17.0. 2021-07-06 16:08:50 +00:00
Conrad Sanderson b7aab43451 Merge pull request #299 from jonpsy/iterate-moead
Repair MOEAD
2021-07-05 14:43:36 +02:00
Marcus Edel ee8e1601bb Merge pull request #306 from jonpsy/nsga2-speed
Reduce LOC of NSGA-II.
2021-07-04 12:10:41 -04:00
Conrad Sanderson ec114f1904 Merge pull request #305 from mlpack/conradsnicta-init-fixes
various fixes for matrix initialisation
2021-07-02 05:34:37 +02:00
Conrad Sanderson 7582788d14 fix PR number 2021-07-02 05:32:20 +02:00
Nanubala Gnana SaiandMarcus Edel 3b78ab0d43 Update include/ensmallen_bits/nsga2/nsga2_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-07-01 22:13:17 +05:30
Nanubala Gnana Sai 3b4015c289 Update nsga2_impl.hpp
fix indent again
2021-07-01 21:57:09 +05:30
Nanubala Gnana Sai 0dd2b4c6fc Update nsga2_impl.hpp
fix indent
2021-07-01 21:56:23 +05:30
Nanubala Gnana Sai 0873d4a3b9 done changes. 2021-07-01 16:24:11 +00:00
Conrad Sanderson e5f2ca2553 update HISTORY.md 2021-07-01 13:50:39 +02:00
Nanubala Gnana Sai f4da19da12 resize => set_size 2021-07-01 04:51:57 +00:00
Conrad Sanderson 055ebfd3e9 use fill::none to avoid default zeroing 2021-07-01 05:45:17 +02:00
Conrad Sanderson 777fb6ac36 explicitly initialise to zeros 2021-07-01 05:38:54 +02:00
Conrad Sanderson d6ffdc59fa avoid zeroing twice 2021-07-01 05:31:53 +02:00
Conrad Sanderson ba167cefa0 use fill::none to avoid default zeroing 2021-07-01 05:21:18 +02:00
Nanubala Gnana Sai 6d4914ab72 remove unneccessary evaluate() call 2021-07-01 01:39:00 +00:00
Conrad Sanderson 44bb57ceb6 Merge pull request #304 from rcurtin/readd-deprecated-front
Add Front() back into the NSGA2 class.
2021-06-30 04:00:30 +02:00
Ryan Curtin 83bc231e1b Remove unused variables. 2021-06-28 13:38:49 -04:00
Ryan Curtin 9906c22d62 Use 3.x as the version number. 2021-06-28 11:51:24 -04:00
Ryan Curtin 4faea9791a Merge pull request #303 from mlpack/conradsnicta-dont-build-tests-by-default
don't build tests by default
2021-06-28 11:46:31 -04:00
Ryan Curtin 4c0accde96 Add Front() back into the NSGA2 class. 2021-06-28 11:43:15 -04:00
Conrad Sanderson 7a870142d0 update HISTORY.md 2021-06-27 07:06:24 +02:00
Conrad Sanderson a622a767de fix minor typo 2021-06-27 06:59:09 +02:00
Conrad Sanderson 735ae35521 building tests is now optional
- state that building tests is now optional
- show how to build and run the tests
2021-06-27 06:53:04 +02:00
Conrad Sanderson f51bfd71e7 don't build ensmallen_tests as part of make all 2021-06-27 06:43:53 +02:00
Nanubala Gnana Sai 9d55d24b3c Update pbi_decomposition.hpp
Use default arma::norm p value.
2021-06-26 01:35:02 +05:30
Marcus Edel 176aea6ef9 Merge pull request #298 from jonpsy/zdt_fix
ZDT4 Evaluate Fix.
2021-06-25 14:54:12 -04:00
jonpsy 9cad4a5d24 L2 norm not L1. 2021-06-25 20:09:49 +05:30
Marcus Edel 54c2de48e9 Merge branch 'master' into ada_belief 2021-06-24 20:27:34 -04:00
Marcus Edel ea7fe09913 Use updated update strategy from the latest paper release. 2021-06-25 02:26:26 +02:00
Ryan Curtin e6406a5c9a Merge pull request #300 from mlpack/README-improved-install-instructions
improved installation and compilation instructions
2021-06-24 10:35:40 -04:00
Conrad Sanderson a0137b07bb adjust line lengths to 80 chars max
this is to make editing on phones easier :)
2021-06-24 15:43:25 +02:00
Conrad Sanderson af145271ba Merge branch 'master' into README-improved-install-instructions 2021-06-24 15:34:55 +02:00
Conrad Sanderson c0b361d88a fix merge clashes 2021-06-24 15:31:51 +02:00
Ryan Curtin 14e1717b8d Merge pull request #302 from jonpsy/history
Modify HISTORY.md release history
2021-06-24 09:06:50 -04:00
jonpsy 0a53dcf7a6 Fix main Evaluate() 2021-06-24 09:49:54 +05:30
jonpsy 3921d34db0 Move up for next release. 2021-06-24 09:04:11 +05:30
Marcus Edel 9232017bd5 Merge pull request #296 from jonpsy/dirichlet
Add Dirichlet Weight Initialization.
2021-06-23 15:54:18 -04:00
Nanubala Gnana Sai 9835cd1149 Update optimizers.md 2021-06-24 00:11:03 +05:30
Nanubala Gnana Sai 96006fa6b2 Merge branch 'master' into dirichlet 2021-06-24 00:08:45 +05:30
Marcus Edel 86cf8f3edb Merge pull request #295 from jonpsy/uniform
Add Das-Dennis weight initialization method.
2021-06-23 14:23:59 -04:00
Conrad Sanderson 0678b0518a change "automatic" to "cmake based"
clarify wording, as the cmake installation isn't really automatic (still need to type commands)
2021-06-23 16:44:31 +02:00
Conrad Sanderson bb18d79413 automatic installation before manual installation
* place automatic installation instructions before manual installation instructions
* adapt text to improve flow
* fix bug in path for cmake non-root installation
2021-06-23 16:35:30 +02:00
NanuSai 7ce177996a frontIndices should be a vector. 2021-06-23 17:54:31 +05:30
jonpsy 8ac18870ef Add source of GFG code. 2021-06-23 14:39:27 +05:30
Conrad Sanderson 3c1bad105c update HISTORY.md 2021-06-23 04:47:20 +02:00
Conrad Sanderson 30bf5d2a67 improved installation and compilation instructions
Improved installation and compilation instructions:
* show how to install manually (in addition to cmake)
* show how to install with and without root access
* added example compilation commands, using standard and non-standard installation directories
2021-06-23 04:06:59 +02:00
jonpsy 5b8fcdf2f9 Set iterate after optimization ends. 2021-06-22 22:41:49 +05:30
jonpsy c585d2e377 HISTORY change isn't required. 2021-06-22 22:21:06 +05:30
jonpsy f108cc51ca history added. 2021-06-22 22:14:12 +05:30
jonpsy edb7e15229 truncatedCoords should be MatType. 2021-06-22 22:11:00 +05:30
Nanubala Gnana SaiandMarcus Edel bb893f683c Update include/ensmallen_bits/moead/weight_init_policies/uniform_init.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-22 00:33:48 +05:30
NanuSai b9b011ea01 Test against ZDT3
Add DirichletMOEAD
2021-06-19 01:03:30 +05:30
NanuSai 3268605bd7 Merge branch 'uniform' of https://github.com/jonpsy/ensmallen into uniform 2021-06-19 00:07:34 +05:30
NanuSai 239916188f add BBSMOEAD 2021-06-19 00:07:16 +05:30
Nanubala Gnana SaiandMarcus Edel 4f297c7abd Update include/ensmallen_bits/moead/weight_init_policies/uniform_init.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-18 23:52:22 +05:30
Nanubala Gnana SaiandMarcus Edel cb3dc29b09 Update include/ensmallen_bits/moead/weight_init_policies/uniform_init.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-18 21:13:34 +05:30
Nanubala Gnana SaiandMarcus Edel 50f1245e01 Update include/ensmallen_bits/moead/weight_init_policies/uniform_init.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-18 21:13:28 +05:30
Nanubala Gnana SaiandMarcus Edel 3c0b4673b4 Update include/ensmallen_bits/moead/weight_init_policies/uniform_init.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-18 21:13:22 +05:30
NanuSai cf38624cf5 added history 2021-06-18 19:34:35 +05:30
NanuSai fde96643fc added in optimizers.md
tests are passing
2021-06-18 19:32:14 +05:30
NanuSai ee1bb9760a Added dirichilet 2021-06-18 19:31:11 +05:30
NanuSai f9c5d7f3d6 revert to normal 2021-06-18 19:05:59 +05:30
NanuSai d98f82599b nit 2021-06-18 19:04:36 +05:30
NanuSai a8c664ece0 oldschool 2021-06-18 18:59:18 +05:30
NanuSai 7ebc527c09 minor indent fix 2021-06-18 18:42:18 +05:30
NanuSai dbfcf7e20f RDP test 2021-06-18 18:20:51 +05:30
NanuSai cf1a9e7e03 document in optimizers.md 2021-06-18 18:14:23 +05:30
NanuSai 501d486fa3 add history 2021-06-18 18:11:28 +05:30
NanuSai 275ded335d Add the braces 2021-06-18 18:09:54 +05:30
NanuSai d7be57a90b fix test params 2021-06-18 18:09:54 +05:30
NanuSai 96a1998ab6 efficient Binomial coefficient O(n) 2021-06-18 18:09:54 +05:30
NanuSai 60f92647a2 => Added uniform init
=> Use 300 instead of 150 population
=> DefaultMOEAD = MOEAD<Uniform, Tchebycheff>
2021-06-18 18:09:54 +05:30
Marcus Edel 0af8004ff9 Merge pull request #293 from jonpsy/moead+
Introduce Policy Methods for MOEA/D-DE.
2021-06-18 08:26:14 -04:00
NanuSai ff03b06848 restore cmake 2021-06-17 00:40:50 +05:30
NanuSai bd6cf8a116 Set bad threshold as of now. 2021-06-17 00:04:23 +05:30
NanuSai 18a4ca67e8 revert appveyor.yml 2021-06-16 23:59:07 +05:30
NanuSai a8b9018d83 use arma::diff 2021-06-16 23:52:31 +05:30
NanuSai 91ed336d0f remove stackoverflow link 2021-06-16 23:41:54 +05:30
NanuSai d66c3d0ca9 Merge branch 'moead+' of https://github.com/jonpsy/ensmallen into moead+ 2021-06-16 23:40:04 +05:30
NanuSai e3b865fcf0 revert moead test 2021-06-16 23:26:47 +05:30
Nanubala Gnana SaiandMarcus Edel e2b883dbda Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 23:24:16 +05:30
Nanubala Gnana SaiandMarcus Edel 955e7db555 Update include/ensmallen_bits/moead/weight_init_policies/bbs_init.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 22:35:18 +05:30
Nanubala Gnana SaiandMarcus Edel d7f2be2adb Update include/ensmallen_bits/moead/moead.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 22:35:06 +05:30
Nanubala Gnana SaiandMarcus Edel 79aa3f637a Update include/ensmallen_bits/moead/decomposition_policies/pbi_decomposition.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 22:34:56 +05:30
Nanubala Gnana SaiandMarcus Edel c1fbf16247 Update include/ensmallen_bits/moead/decomposition_policies/weighted_decomposition.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 22:34:46 +05:30
Nanubala Gnana SaiandMarcus Edel be9f8b6346 Update include/ensmallen_bits/moead/decomposition_policies/tchebycheff_decomposition.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 22:34:35 +05:30
Nanubala Gnana SaiandMarcus Edel 7d86a46a7b Update include/ensmallen_bits/moead/decomposition_policies/pbi_decomposition.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 22:34:26 +05:30
Nanubala Gnana Sai c79f593ff2 no need to build redundant tests 2021-06-16 15:39:39 +00:00
Nanubala Gnana Sai 40c9aaad7f Start RDP 2021-06-16 15:38:32 +00:00
NanuSai 23ff19074a minor fix 2021-06-16 11:53:04 +05:30
NanuSai 77bd44bed3 added template doc in optimizer.md 2021-06-16 11:16:11 +05:30
NanuSai d02d5e46aa extra doc for decomp policy 2021-06-16 10:55:02 +05:30
NanuSai 4997f550d2 add doc for bbs 2021-06-16 10:54:43 +05:30
NanuSai 8d81b422d2 indent 2021-06-16 10:47:06 +05:30
NanuSai 6e3e323654 doc decomposition policy 2021-06-16 10:42:54 +05:30
NanuSai de612d3d09 using DefaultMOEAD 2021-06-16 10:30:08 +05:30
NanuSai 9beaa5f0d4 InitPolicy, Generate const 2021-06-16 10:29:02 +05:30
Nanubala Gnana SaiandMarcus Edel 2c02c5f969 Update include/ensmallen_bits/moead/decomposition_policies/tchebycheff_decomposition.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 10:25:43 +05:30
Nanubala Gnana SaiandMarcus Edel 8952378a04 Update include/ensmallen_bits/moead/decomposition_policies/weighted_decomposition.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 10:25:37 +05:30
Nanubala Gnana SaiandMarcus Edel 4ec1f2e430 Update include/ensmallen_bits/moead/moead.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 10:25:30 +05:30
Nanubala Gnana SaiandMarcus Edel ade51c915b Update include/ensmallen_bits/moead/decomposition_policies/pbi_decomposition.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 10:25:23 +05:30
Nanubala Gnana SaiandMarcus Edel e092c4d262 Update include/ensmallen_bits/moead/moead.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 08:54:03 +05:30
Nanubala Gnana SaiandMarcus Edel 4692047af2 Update include/ensmallen_bits/moead/moead.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 08:53:44 +05:30
Nanubala Gnana SaiandMarcus Edel cfed986674 Update include/ensmallen_bits/moead/moead.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-16 08:53:26 +05:30
NanuSai 6e1164e952 remove uniform_init.hpp as of now 2021-06-16 08:43:58 +05:30
NanuSai ee41faad7d Tested against ZDT1 2021-06-16 08:24:02 +05:30
NanuSai 945e21abb5 history fix 2021-06-16 08:19:16 +05:30
NanuSai 6868e2ca94 restore all tests 2021-06-16 08:06:07 +05:30
NanuSai dbc24bbe4c moead doc fix 2021-06-16 08:06:07 +05:30
NanuSai 7505ecc6c7 fix decomposition policy docs 2021-06-16 08:06:07 +05:30
NanuSai e08c0c86c3 fix moead doc 2021-06-16 08:06:07 +05:30
NanuSai 9242279aba Re-configure tests 2021-06-16 08:06:07 +05:30
NanuSai d41c265202 Added Init policies
=> BayesianBootStrap : Working
=> Uniform : **NOT WORKING**
2021-06-16 08:06:07 +05:30
NanuSai 2749d31e7e Added decomposition policies
=> PBI
=> Tchebycheff
=> Weighted
2021-06-16 08:06:07 +05:30
NanuSai c66ee3a098 Make MOEA/D-DE policy based 2021-06-16 08:06:07 +05:30
NanuSai 9e6b3cad22 Fixed minor indent 2021-06-16 08:06:07 +05:30
Marcus Edel 3497f276f4 Merge pull request #269 from jonpsy/moead
Implement MOEA/D - DE.
2021-06-15 15:07:30 -04:00
Marcus Edel db90638fb3 Merge pull request #273 from jonpsy/ZDT
Adding ZDT Test Suite.
2021-06-14 12:30:44 -04:00
Nanubala Gnana SaiandMarcus Edel 973d4a7bcc Update include/ensmallen_bits/moead/moead.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-13 09:17:14 +05:30
Nanubala Gnana SaiandMarcus Edel da7683b770 Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-13 09:17:04 +05:30
Nanubala Gnana SaiandMarcus Edel 5cd6bc8c29 Update tests/moead_test.cpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-13 09:16:56 +05:30
Nanubala Gnana SaiandMarcus Edel 40e44d4ede Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-13 09:16:47 +05:30
Nanubala Gnana SaiandMarcus Edel 7d794cb4bc Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-13 09:16:40 +05:30
Nanubala Gnana SaiandMarcus Edel a2a7ef166b Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-13 09:16:03 +05:30
Nanubala Gnana SaiandMarcus Edel b1fa440fda Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-13 09:15:39 +05:30
NanuSai e893dfd3ee weights are fixed bruh 2021-06-12 19:27:03 +05:30
NanuSai 53cae18ff6 fix default arg in ctor
fix callback test
2021-06-12 10:42:04 +05:30
NanuSai b7178fef0e Added epsilon to docs 2021-06-12 10:28:51 +05:30
NanuSai edd089a72b 2. => 2.0 2021-06-12 10:22:03 +05:30
NanuSai 60d19c48d7 if( 2021-06-12 10:21:19 +05:30
NanuSai 287bf825fa style fix 2021-06-12 10:20:49 +05:30
Nanubala Gnana Sai 5d9e73c139 Update moead_impl.hpp
Another day, another indent
2021-06-12 10:14:42 +05:30
NanuSai aa54aade4a BaseMatType 2021-06-12 10:02:13 +05:30
NanuSai b0c4c1b7b1 reorder tests 2021-06-12 09:59:26 +05:30
NanuSai 3267c42e4d RequireDenseFloatingCheck 2021-06-12 09:58:26 +05:30
NanuSai a646f7c136 re-ordered state variables 2021-06-12 09:55:29 +05:30
NanuSai 81e07bf455 minor style + numobjectives remvoed from opt 2021-06-12 09:37:21 +05:30
NanuSai 604209a0f7 added epsilon 2021-06-12 09:00:30 +05:30
NanuSai 1dadc1bbb0 delta indent fix 2021-06-12 08:46:53 +05:30
NanuSai 80fbf6c9e8 Mate fix 2021-06-12 08:46:30 +05:30
NanuSai ad9f355503 Mating more clear 2021-06-12 08:32:22 +05:30
Nanubala Gnana Sai 27404cdaad Update moead_impl.hpp 2021-06-12 00:25:33 +05:30
Nanubala Gnana Sai cf850f50d1 Update moead_impl.hpp
pick is const
2021-06-12 00:23:33 +05:30
Nanubala Gnana Sai 9d93405f5b Update moead_impl.hpp
delta should be generated per gene.
2021-06-12 00:23:02 +05:30
Nanubala Gnana SaiandMarcus Edel 4824e72f93 Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-11 23:09:17 +05:30
Nanubala Gnana SaiandMarcus Edel 3404708708 Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-11 23:09:09 +05:30
Nanubala Gnana SaiandMarcus Edel 4e4fa69b08 Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-11 23:08:56 +05:30
Nanubala Gnana SaiandMarcus Edel 0828c7bfe4 Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-11 23:08:45 +05:30
Nanubala Gnana SaiandMarcus Edel 7505121ee6 Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-11 23:08:28 +05:30
Nanubala Gnana SaiandMarcus Edel bd2522667e Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-11 23:08:17 +05:30
NanuSai fb587225d4 fix error 2021-06-10 14:51:56 +05:30
NanuSai 6acbe14bfb minor style 2021-06-10 11:59:36 +05:30
Nanubala Gnana Sai 950e36c2d0 Update moead_impl.hpp
Indent fix
2021-06-10 11:57:40 +05:30
Nanubala Gnana Sai d2a396cde1 Update moead.hpp
Fix indent
2021-06-10 11:55:30 +05:30
NanuSai b5f49a00a2 Fix callbacks 2021-06-10 10:08:38 +05:30
NanuSai a068a6e40d Fix docs for optimizers.md 2021-06-10 09:53:25 +05:30
NanuSai 5adfba0bbd use distributionIndex again 2021-06-10 09:53:14 +05:30
NanuSai 08fa726dc1 Tests pass 2021-06-09 21:26:23 +05:30
NanuSai 0f597ddd11 initialize fitness 2021-06-09 19:23:35 +05:30
NanuSai dd4b475b8c All tests compile 2021-06-09 12:49:28 +05:30
NanuSai 7d7ad342ee => cache converted upper and lowerBound
=> PreciisonType flexible
=> Created containers to pass to evaluateobjectives
2021-06-09 12:49:12 +05:30
NanuSai 62dc59099c use MatType lowerBound 2021-06-09 12:47:53 +05:30
NanuSai 556ded8c48 Everything compiles. 2021-06-09 11:14:45 +05:30
NanuSai 34366e7237 perturbationIndex pt.2 2021-06-09 11:07:12 +05:30
NanuSai 274f9f06e9 => Use cleaner Mutate code.
=> Remove redundant for loops.
2021-06-09 11:04:41 +05:30
NanuSai 5fb082a95a distributionIndex => perturbationIndex 2021-06-09 11:03:24 +05:30
NanuSai 2822fae878 Additional docs in declare file 2021-06-09 09:17:36 +05:30
NanuSai 5c11b532bc => Indent fix.
=> Use ElemType in DecomposeObjectives.
=> paretoSet and paretoFront filled.
=> Additional docs.
2021-06-09 09:17:07 +05:30
NanuSai efa5a2efbd Additional docs
remove callback tests
2021-06-08 21:29:16 +05:30
NanuSai b4f862d73f ] => ) 2021-06-08 20:48:28 +05:30
NanuSai 80a2f851b6 g => generation: main loop 2021-06-08 20:32:17 +05:30
NanuSai 57c8d70a02 ideal point uses ElemType 2021-06-08 20:30:58 +05:30
NanuSai a44da082b2 rm StepTaken 2021-06-08 20:23:52 +05:30
NanuSai 6703d07001 Tab fix
Remove const ref for primitive
2021-06-08 20:22:22 +05:30
NanuSai 410eb50fd2 Maintain EvaluateObjectives of NSGA-II 2021-06-08 20:19:32 +05:30
NanuSai e086bf2bd0 Doc fix 2021-06-08 19:58:29 +05:30
NanuSai 391e164fb7 moead_impl.hpp
=> Use BaseMatType
=> Remove redundant checks
2021-06-08 19:47:58 +05:30
NanuSai 1149301fa5 use ParetoSet & ParetoFront in declaration file 2021-06-08 10:29:43 +05:30
NanuSai 2ce3bd3d14 tab v space pt3 2021-06-08 10:21:16 +05:30
NanuSai e515851b40 author fix impl
test comments fixed.
2021-06-08 10:21:16 +05:30
NanuSai 47c981ec3a fix indendations pt2 2021-06-08 10:21:16 +05:30
NanuSai bfde39de2f tab v space 2021-06-08 10:21:16 +05:30
Nanubala Gnana SaiandMarcus Edel 9d7eec84b9 Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-08 10:21:16 +05:30
Nanubala Gnana SaiandMarcus Edel c849873522 Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-08 10:21:16 +05:30
Nanubala Gnana SaiandMarcus Edel faa94ab15b Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-08 10:21:16 +05:30
Nanubala Gnana SaiandMarcus Edel 83e0850cc7 Update include/ensmallen_bits/moead/moead_impl.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-08 10:21:16 +05:30
NanuSai f516864104 arma::square 2021-06-08 10:21:16 +05:30
NanuSai c602dc1386 bound fix in optimizer.MD 2021-06-08 10:21:16 +05:30
NanuSai 9c888154b0 fix bounds 2021-06-08 10:21:16 +05:30
NanuSai 8a52d9ab10 add callbacktest 2021-06-08 10:21:16 +05:30
NanuSai a95c0e647a Remove shuffle from problems 2021-06-08 10:21:16 +05:30
NanuSai f38f6a1d44 modify test a bit 2021-06-08 10:21:16 +05:30
NanuSai 73ef983352 maxreplace is always positive 2021-06-08 10:21:16 +05:30
NanuSai d2615d5471 optimizer.MD update 2021-06-08 10:21:16 +05:30
NanuSai 5e27bdf1f2 minor doc changes 2021-06-08 10:21:16 +05:30
NanuSai f1488ab44e candidateFval => candidateFitness 2021-06-08 10:21:16 +05:30
NanuSai 3f30929c31 => test with def args : pass
=> rm arma::Mat<> => arma::umat
2021-06-08 10:21:16 +05:30
NanuSai be8e45b45a rm
a) mutationProb
 b) mutationStrength

add
 Sanity checks for all params

Styling fix
2021-06-08 10:21:16 +05:30
NanuSai c388bde9ea rm redundant args 2021-06-08 10:21:16 +05:30
NanuSai 33bcfca29d optimizer.md updated 2021-06-08 10:21:16 +05:30
NanuSai 288b3d710a change def args:
- numGen should be 2k
- paper says neighborProb should be less (for diversity) => 0.3
2021-06-08 10:21:16 +05:30
NanuSai b1bd1445ce numGenerations => maxGenerations 2021-06-08 10:21:16 +05:30
Nanubala Gnana SaiandMarcus Edel e73e79de9b Update include/ensmallen_bits/moead/moead.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-08 10:21:16 +05:30
Nanubala Gnana SaiandMarcus Edel eaf86e9c22 Update doc/optimizers.md
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-08 10:21:16 +05:30
Nanubala Gnana SaiandMarcus Edel cab48a009d Update doc/optimizers.md
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-08 10:21:16 +05:30
NanuSai c380dd5d7d rname MOEAD => MOEA/D-DE 2021-06-08 10:21:16 +05:30
NanuSai e04519b936 fix authors 2021-06-08 10:21:16 +05:30
NanuSai cf9ec55754 some work on optimizer.md 2021-06-08 10:21:16 +05:30
NanuSai ee92ed0f7b HISTORY.md updated 2021-06-08 10:21:16 +05:30
NanuSai c067fcc68e fonseca shuffle fix 2021-06-08 10:21:16 +05:30
NanuSai 2e8ba4d144 undo nsga2_test changes 2021-06-08 10:21:16 +05:30
NanuSai aecbe43c3b - Removed preserveDiversity for now
- ALL TESTS PASSED!!!
2021-06-08 10:20:45 +05:30
NanuSai 8b2ae1312d rm preserve diversity 2021-06-08 10:20:45 +05:30
NanuSai 57815a59b0 Shuffle func is wrong 2021-06-08 10:20:45 +05:30
NanuSai fefcaa6b1f minor style change test 2021-06-08 10:20:45 +05:30
NanuSai 08b24f1bc8 - Everything compiles
- All tests fail
-  debug shows weight 0?

Finally hit the "wall".
2021-06-08 10:20:45 +05:30
NanuSai b1ba5a2123 - n_rows
- evaluate should take const population
2021-06-08 10:20:45 +05:30
NanuSai 8b8fe49f7c use arma::datum::eps
add check for lowerBound and upperBound
2021-06-08 10:20:45 +05:30
NanuSai 41d58bc652 minor 2021-06-08 10:20:45 +05:30
NanuSai 1011370953 mutation fixed 2021-06-08 10:20:45 +05:30
NanuSai ed5ad0e53b DE done 2021-06-08 10:20:45 +05:30
NanuSai 7d50c879fc Nits on MatingSelection
-  assert neighborSize > 1
-  minors
2021-06-08 10:20:45 +05:30
NanuSai d794746062 styling fix 2021-06-08 10:20:45 +05:30
NanuSai c281336e64 fix chronology in docs 2021-06-08 10:20:45 +05:30
NanuSai d67ed85dd0 remove
- dominates
rename
- differentialWeight, changed default value
- add
weight stability
2021-06-08 10:20:45 +05:30
NanuSai 73a3b90c1c tchebycheff is max 2021-06-08 10:20:45 +05:30
NanuSai 99f6f2b630 rm:
- externalPopulation
 - externalPopulationFval
 - update neighbor of MOEA/D
 rename:
- FValue => populationFval
- Add
 - update solutions as MOEA/D-DE prefers
 -  use diversity preserve conditions
 -  idealPoint and candidateFval are arma::vec

========
REMAINING
- Fixing the final stuff
- Some additional touches
- Possible code fixes
2021-06-08 10:20:45 +05:30
NanuSai a4dcccd26a rename
-  DecomposeObjectives
2021-06-08 10:20:45 +05:30
NanuSai d69c899bfd Add params
- maxReplace
- preserveDiversity
- Add docs
2021-06-08 10:20:45 +05:30
NanuSai 89f6b8fb41 - fix compile errors
- test still fail
2021-06-08 10:20:45 +05:30
NanuSai 0ae80352d8 - add TODO
- add FIXME
- neighborIndices
2021-06-08 10:20:45 +05:30
NanuSai 09ec4a23ac Scalingfactor in impl
pFlag switch Mating
2021-06-08 10:20:45 +05:30
NanuSai ad8383ebad Add enum for P type 2021-06-08 10:20:45 +05:30
NanuSai a3b812a283 weightNeighborIndex fix 2021-06-08 10:20:45 +05:30
NanuSai f4c348a316 MatingSelection needs popIdx
weighNeighbourMatrix idx fix
2021-06-08 10:20:45 +05:30
NanuSai 5a07b38a3a evaluatedCandidate => candidateFval 2021-06-08 10:20:45 +05:30
NanuSai b01e7fab18 * scalingFactor in ctor
* paper says 0.4  -> 1 is a good for scaling factor
2021-06-08 10:20:45 +05:30
NanuSai ded4a43837 1.f / numVariables, should pass float 2021-06-08 10:20:45 +05:30
NanuSai 28be655f05 numVariables 2021-06-08 10:20:45 +05:30
NanuSai 3cd94aeb67 scalingFactor getter setter 2021-06-08 10:20:45 +05:30
NanuSai bb414e68ed convention 2021-06-08 10:20:45 +05:30
NanuSai a52f1ad5f4 cast to vector only at EvaluateObjectives 2021-06-08 10:20:45 +05:30
NanuSai 3d91ccc37f differential crossover 2021-06-08 10:20:45 +05:30
NanuSai 91df7068c5 crossover inside mainloop 2021-06-08 10:20:45 +05:30
NanuSai 19425d4d78 - wrap mating in a function
- declare DifferentialCrossover
2021-06-08 10:20:45 +05:30
NanuSai 0419469103 - Import previous work
- populationSize > neighborSize + 1
- fix initNeighborhood
- neighborHoodSize => neighborSize
2021-06-08 10:20:45 +05:30
Nanubala Gnana Sai c22c6fc420 Add docs for ZDT_ONE Test 2021-06-08 06:59:34 +05:30
NanuSai 6e9287df1a Fix re-ordering warning 2021-06-06 11:38:14 +05:30
Marcus Edel 447f8086ff Merge branch 'master' into ZDT 2021-06-05 22:25:35 -04:00
Marcus Edel abd5b036f1 Merge pull request #289 from jonpsy/moo-callback
Make Callback flexible for MultiObjective Optimizers.
2021-06-04 09:58:24 -04:00
Marcus Edel 2306acb37e Merge pull request #291 from jonpsy/frontdoc
Doc fix.
2021-06-02 09:32:23 -04:00
NanuSai 6d28ed41c6 rm query front doc in ctor 2021-06-01 22:32:12 +05:30
NanuSai 3eb05e9ddf Merge branch 'moo-callback' of https://github.com/jonpsy/ensmallen into moo-callback 2021-06-01 22:29:51 +05:30
NanuSai 72ced21bb4 history fix 2021-06-01 22:29:33 +05:30
Nanubala Gnana SaiandMarcus Edel 6d4023c855 Update include/ensmallen_bits/callbacks/query_front.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-06-01 22:14:36 +05:30
NanuSai 29b6ff1974 fix 2021-06-01 15:12:19 +05:30
NanuSai 526f1d449f init gensteptaken 2021-06-01 15:03:34 +05:30
NanuSai e6c4513df4 remov e ZDT5 2021-06-01 14:56:23 +05:30
NanuSai e7215436fe fix test for MOO 2021-06-01 14:43:56 +05:30
NanuSai b5e85c9874 Add inbuilt query front hpp 2021-06-01 14:43:48 +05:30
NanuSai 873d951e2e add docs in callbacks.md 2021-06-01 14:43:30 +05:30
NanuSai 5d05ff62ec => Rename to GenerationalStepTaken
=> Move Callback::StepTaken() at the end of for loop nsga2
=> Register GenerationStepTaken in macro
2021-06-01 10:10:03 +05:30
NanuSai 5082d82133 history 2021-05-29 12:21:51 +05:30
NanuSai 5afdcdd9e3 replace callback in nsga2 2021-05-29 11:50:31 +05:30
NanuSai 4a45156130 remove redundant docs 2021-05-29 11:47:28 +05:30
NanuSai 25c4af46bf indendation fix 2021-05-29 11:38:40 +05:30
NanuSai 5853712ba1 1. fix compile error
2. rename to ObjectivesVecType
2021-05-29 11:32:41 +05:30
Nanubala Gnana Sai eb345f1346 Initial push.
=> add MOOTypedForms in traits.hpp.
=> added a specialization for StepTaken for MOO in callbacks.hpp.
2021-05-29 03:05:36 +05:30
Nanubala Gnana Sai a6e8291c66 Document that reference front plot is in the PR. 2021-05-26 22:50:31 +05:30
Nanubala Gnana Sai 4136639d4e Add ZDT1 Test 2021-05-26 22:50:04 +05:30
Nanubala Gnana Sai 2c22ab2407 GetParetoFront => GetReferenceFront 2021-05-25 22:06:04 +05:30
NanuSai d40b12fa77 add ZDT to nsga2 (not working) 2021-05-25 19:08:30 +05:30
NanuSai 3200754617 numParetoPoints specified by user 2021-05-25 19:08:18 +05:30
Marcus Edel f66643e1c5 Merge pull request #288 from zoq/catch-main-seed
Use Catch2 seed command-line argument to set ensmallen seeds.
2021-05-17 19:37:36 -04:00
Marcus Edel b24589bacb Add AdaBelief to the function types documentation. 2021-05-16 23:44:49 +02:00
NanuSai 118bc4ebaa fix compile errors 2021-05-14 10:57:10 +05:30
NanuSai e4c3a63375 Pareto Front for ZDT-4,5,6 2021-05-14 10:43:12 +05:30
NanuSai d34aec8cf8 fix indent 2021-05-14 10:08:11 +05:30
NanuSai 4baf1072e0 fix history 2021-05-14 10:06:49 +05:30
NanuSai 1276ef366b * Pareto Front for ZDT-1,2,3
* Put inside folder
2021-05-14 10:04:53 +05:30
NanuSai f36a517358 Add Pareto Front for ZDT1, ZDT2 2021-05-14 10:04:53 +05:30
NanuSai 6a9a44f62a move to folder 2021-05-14 10:04:53 +05:30
NanuSai 1f7bb9a730 ZDT5 added 2021-05-14 10:04:53 +05:30
NanuSai e6b130bb24 ZDT history 2021-05-14 10:04:53 +05:30
Nanubala Gnana Sai e7b26115f4 Merge branch 'master' into ZDT 2021-05-04 13:05:23 +05:30
Ryan Curtin 27150fc8fd Merge pull request #287 from zoq/ci-dist-update
Switch from Ubuntu Trusty 14.04 to Ubuntu Focal 20.04
2021-05-02 22:34:08 -04:00
Marcus Edel 2751e7968f Merge pull request #285 from jonpsy/indicator
Add MOO Indicators.
2021-05-02 12:04:53 -04:00
Marcus Edel 6e3fbc278e Use Catch2 seed command-line argument to set ensmallen seeds. 2021-05-02 04:15:53 +02:00
Marcus Edel 55f2e6aac2 Use updated test suite functionality. 2021-05-02 04:11:43 +02:00
Marcus EdelandRyan Curtin 6458263f05 Spelling fix and remove duplicated description.
Co-authored-by: Ryan Curtin <ryan@ratml.org>
2021-05-01 22:11:27 -04:00
Marcus Edel c954ab231c Merge branch 'master' into ada_belief 2021-05-01 15:07:10 -04:00
Nanubala Gnana Sai 0a1504ef2a Add braces 2021-04-29 01:45:37 +05:30
Nanubala Gnana SaiandMarcus Edel e975ee968f Update include/ensmallen_bits/utility/indicators/epsilon.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-04-29 01:34:17 +05:30
Nanubala Gnana SaiandMarcus Edel 00020ce08a Update include/ensmallen_bits/nsga2/nsga2.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-04-29 01:33:59 +05:30
Marcus Edel 61def4a04b Switch from Ubuntu Trusty 14.04 to Ubuntu Focal 20.04. 2021-04-27 02:41:51 +02:00
NanuSai 284b2f9d30 separate API for paretoset and paretofront 2021-04-26 00:14:59 +05:30
NanuSai 70ed598f53 redundant include 2021-04-25 23:53:00 +05:30
NanuSai 98ba659e86 restore cmakelists.txt 2021-04-25 23:52:03 +05:30
Nanubala Gnana Sai c013fcbaa6 Update .appveyor.yml 2021-04-25 23:48:23 +05:30
Nanubala Gnana Sai 6f79de7668 Update .appveyor.yml 2021-04-25 23:47:50 +05:30
NanuSai 9099b7400c revert appveyor. 2021-04-25 23:46:50 +05:30
NanuSai a62eda2ecc fix float error
compile only indicators
2021-04-25 23:30:00 +05:30
NanuSai 69361e98e5 Hence begins the RDP quest! 2021-04-25 22:48:40 +05:30
Nanubala Gnana Sai 18f7f2a736 use templated std::max
revert tolerance
2021-04-25 11:51:56 +05:30
Nanubala Gnana Sai a977492626 Update indicators_test.cpp
Change tolerance for MSVC15 (Assuming tolerance is causing the problem which I think it isn't, we'll see)
2021-04-25 02:16:29 +05:30
NanuSai b56b5b99c5 => epsilon ctor fix
=> add indicators test
=> Results match with hand calculated values.
2021-04-24 22:01:23 +05:30
NanuSai a1bd37c9a3 => rename igd -> igd+.
=> add public ctor similar to Metric Policy.
=> std::max() fix
2021-04-24 22:00:17 +05:30
NanuSai a26e271960 Zero div handled 2021-04-24 14:58:49 +05:30
Nanubala Gnana Sai ec75ddc04b -> further doc fixes in ensmallen.hpp
-> fix minor error in igd+
2021-04-24 01:04:09 +05:30
Nanubala Gnana Sai 7302ce1093 Doc cleanups 2021-04-24 00:32:20 +05:30
NanuSai 8613e1ba11 => Register at ensmallen.hpp
=> static and ElemType in Evaluate()
2021-04-17 13:35:29 +05:30
Nanubala Gnana Sai 5d90357602 Update nsga2_impl.hpp
fix spacing issue in github
2021-04-17 13:16:07 +05:30
NanuSai cc9d349f1f impl file fixed
test fixed
all test pass
2021-04-17 13:12:14 +05:30
NanuSai 8167ed1185 header arma::cube 2021-04-17 07:24:54 +05:30
NanuSai 41832e401c move to utility 2021-04-17 07:23:52 +05:30
NanuSai 5e2b5747cc shift doc to left 2021-04-16 09:08:47 +05:30
NanuSai 7acf499ceb nits 2021-04-16 09:03:58 +05:30
NanuSai 80955a75e5 spacing issues 2021-04-14 12:13:51 +05:30
Nanubala Gnana Sai 176c24b4fb Update History.md 2021-04-14 12:13:24 +05:30
Nanubala Gnana Sai ec9a93b171 Steal @favre49's work 2021-04-14 12:12:43 +05:30
NanuSai c2dfef1556 Minor style issues 2021-04-14 11:54:14 +05:30
Nanubala Gnana SaiandMarcus Edel 24367895df Update include/ensmallen_bits/problems/zdt1_function.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-04-14 11:54:14 +05:30
Nanubala Gnana SaiandMarcus Edel 499458d20f Update include/ensmallen_bits/problems/zdt1_function.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-04-14 11:54:14 +05:30
NanuSai 69520fbaa4 minor indent fix T_T 2021-04-14 11:54:14 +05:30
NanuSai 6894b7e03c ZDT history 2021-04-14 11:54:14 +05:30
NanuSai 8cbac229ad ElemType 2021-04-14 11:54:14 +05:30
NanuSai 7d20f81cfb => MatType return
=> Indent fix
2021-04-14 11:54:14 +05:30
NanuSai a62416b974 inner access outer. 2021-04-14 11:54:14 +05:30
NanuSai f9f3dc28ea Test working against pagmo2 2021-04-14 11:54:14 +05:30
NanuSai 7ac386e1ec Added
1) ZDT1
2) ZDT2
3) ZDT3
4) ZDT4
5) ZDT6
2021-04-14 11:54:14 +05:30
NanuSai 6924cf1c32 initial push
=> Documentation done.
=> Declared the class.
2021-04-14 11:54:14 +05:30
Marcus Edel 1e70823989 Merge pull request #263 from jonpsy/nsga2-better
Improvise NSGA2.
2021-04-13 20:04:39 -04:00
NanuSai 33974ce3f7 check arbitrary 2021-04-11 00:04:51 +05:30
Nanubala Gnana Sai 9463b153d1 Update HISTORY.md
white space
2021-04-10 23:57:11 +05:30
Nanubala Gnana Sai a4f320a418 Merge branch 'master' into nsga2-better 2021-04-10 23:56:17 +05:30
Marcus Edel 1b6c1d93f0 Merge pull request #283 from jonpsy/moo_traits
Recursively check for Evaluate() in MOO.
2021-04-10 13:34:22 -04:00
Marcus Edel 388bcd82cf Merge pull request #284 from zoq/code-analyzer-fixes
Code analyzer adjustments.
2021-04-09 17:04:56 -04:00
Nanubala Gnana Sai 6be8403fbb Merge branch 'nsga2-better' of https://github.com/jonpsy/ensmallen into nsga2-better 2021-04-09 01:29:42 +05:30
NanuSai 6714a178af Merge branch 'nsga2-better' of https://github.com/jonpsy/ensmallen into nsga2-better 2021-04-09 00:19:57 +05:30
Nanubala Gnana Sai 850612fd97 sanity fix 2021-04-08 19:14:01 +05:30
Marcus Edel 1cd90c6158 Initialize all class parameters. 2021-04-07 22:55:15 +02:00
Marcus Edel bccdbcc7de Remove unused parameter 'numBatches'. 2021-04-07 22:52:25 +02:00
Marcus Edel 089e9395de No need to worry about division by zero. 2021-04-07 22:51:33 +02:00
NanuSai ad8538602d fix compile time error 2021-04-08 01:17:36 +05:30
Nanubala Gnana Sai c6e76e2c62 indent fix 2021-04-07 09:38:47 +05:30
Nanubala Gnana Sai 782b994765 rm unsigned symnb 2021-04-07 09:26:11 +05:30
Nanubala Gnana SaiandMarcus Edel 8ecd483bd4 Update include/ensmallen_bits/function/static_checks.hpp
Co-authored-by: Marcus Edel <marcus.edel@fu-berlin.de>
2021-04-07 09:01:41 +05:30
Nanubala Gnana Sai 7bffa5df48 restore inline 2021-04-04 19:38:04 +05:30
Nanubala Gnana Sai 6f4362b23e style fixing 2021-04-04 19:35:40 +05:30
Nanubala Gnana Sai 750043d20a - reuse established API
- doc change for MOO trait
2021-04-04 19:31:42 +05:30
Nanubala Gnana Sai 563457848e Added History.MD 2021-04-04 12:57:31 +05:30
NanuSai ccf0dff819 ryans method 2021-04-04 15:50:06 +05:30
NanuSai 0069291572 temporary solution in:
a) static_check (possibly wrong)
b) check Arbitrary in for loop in EvaluateObjectives
2021-04-04 14:18:21 +05:30
NanuSai 9fc7013d8d type trait for multiarbitraryfunction 2021-04-03 23:51:42 +05:30
Nanubala Gnana Sai 02d8d94c18 appveyor from master 2021-04-02 07:18:18 +05:30
Nanubala Gnana Sai 7eafb8a2f5 Revert changes from RDP 2021-04-02 07:06:49 +05:30
Nanubala Gnana Sai 5c31f6ad51 stress test on appveyor proofs => run 3k times 2021-04-01 09:37:22 +05:30
Nanubala Gnana Sai 95bc44f4fa rm appveyor pass 2021-04-01 01:09:51 +05:30
Nanubala Gnana Sai fb5f23db8b revert appveyor and ctest settings 2021-04-01 01:08:30 +05:30
Nanubala Gnana Sai f3f699a508 run appveyor test 3000 times 2021-04-01 00:52:30 +05:30
Nanubala Gnana Sai 400720aa15 appveyor print when test fails 2021-04-01 00:47:00 +05:30
Nanubala Gnana Sai 36e43ae21f run only nsga2 test and use random seeds in main.cpp 2021-03-31 15:16:37 +05:30
Nanubala Gnana Sai 846b01f165 appveyor debug 2021-03-31 15:08:50 +05:30
NanuSai f58e0eba43 fix windows indentation 2021-03-31 12:24:31 +05:30
Nanubala Gnana Sai 252c500696 indent fix 2021-03-31 12:15:47 +05:30
Nanubala Gnana Sai d9f3e7b7f2 Update nsga2_impl.hpp
indent fix
2021-03-31 12:11:43 +05:30
Nanubala Gnana Sai b986687494 fix merge conflicts 2021-03-31 12:06:29 +05:30
Nanubala Gnana Sai bad9062cd6 increase tolerance 2021-03-31 11:57:46 +05:30
NanuSai 68157eede0 build in debug 2021-03-30 19:29:08 +05:30
NanuSai 12c513d26c appveyor debug to check tolerance level 2021-03-30 14:32:06 +05:30
Nanubala Gnana Sai 15618563b9 introduced tolerance 2021-03-30 11:17:18 +05:30
Nanubala Gnana Sai a975138f4e appveyor old 2021-03-30 02:37:26 +05:30
Nanubala Gnana Sai c98b16acd1 SchafferN1 double debug Appveyor 2021-03-30 01:40:03 +05:30
Nanubala Gnana Sai d3b2ce932a Use params from paper
1) crossoverProb: 0.9
2) mutationRate: 1/n; n = num vars
3) numGeneration = 250
2021-03-30 01:31:14 +05:30
Nanubala Gnana Sai 70bfceebc5 Reason for changing:
a) 5k gen is too much, papers stick to ~150
b) The test error which I get is off by 1e-2
c)  Solutions are loosing diversity at higher number of generations (repeating solutions even)
2021-03-29 22:30:04 +05:30
NanuSai 1ad7181e84 everyone use IsInBounds 2021-03-28 15:26:00 +05:30
NanuSai 38f88ab2f2 minor 2021-03-28 10:01:54 +05:30
NanuSai d9c049606a maybe the error should be ok now 2021-03-28 10:00:27 +05:30
NanuSai 2689d5c19e use absolute diff 2021-03-28 09:14:24 +05:30
NanuSai 1d16313112 build in debug 2021-03-28 08:54:09 +05:30
NanuSai d18192e251 building works, now just test fails on double 2021-03-28 07:27:04 +05:30
NanuSai 679d904539 cxx11 compiler error? 2021-03-28 05:55:13 +05:30
NanuSai 6c388a0cac appveyor checks again 2021-03-28 05:38:46 +05:30
NanuSai 0256405a4f check error 2021-03-28 05:33:31 +05:30
Ryan Birmingham 9f90ec92aa Merge pull request #281 from zoq/cmaes-doc-fix
Fix CMAES population size parameter comment
2021-03-27 12:07:55 -04:00
Marcus Edel 3d108b2313 Fix CMAES population size parameter comment. 2021-03-27 02:18:36 +01:00
Ryan Curtin 6dc293ec1d Add new block for next release to HISTORY.md. 2021-03-25 16:47:25 +01:00
NanuSai 1b0b51f570 appveyor to normal
MSVC Works!
2021-03-23 16:58:29 +05:30
NanuSai a1ef11a077 some more removals 2021-03-23 16:15:44 +05:30
NanuSai c19c5f6870 MSVC-15 fails back_inserter 2021-03-23 14:54:20 +05:30
NanuSai f76c2f2ae7 on finish 2021-03-23 14:19:56 +05:30
NanuSai a691584fa3 dont run test as well 2021-03-23 14:15:16 +05:30
NanuSai a43c447c84 dont build! 2021-03-23 14:08:59 +05:30
NanuSai 6254ac14b2 remove some inlines 2021-03-23 13:58:22 +05:30
NanuSai 8f6af30aec appveyor validated 2021-03-23 11:54:14 +05:30
NanuSai 1c290c3235 back2square1 2021-03-23 11:48:58 +05:30
Nanubala Gnana Sai eec6cad594 Update .appveyor.yml 2021-03-23 11:13:01 +05:30
Nanubala Gnana Sai 69906e100c test appveyor 2021-03-23 11:01:56 +05:30
NanuSai 31e96e2bb4 make class template 2021-03-22 20:21:54 +05:30
NanuSai e508278039 single threaded 2021-03-22 18:01:32 +05:30
NanuSai b12d050fd5 a minor change to spot error(will be removed) 2021-03-22 17:47:32 +05:30
NanuSai b2f525f5aa allow floatonly 2021-03-22 17:47:18 +05:30
Nanubala Gnana Sai 01dbfa3e7b Merge branch 'master' into nsga2-better 2021-03-22 16:11:43 +05:30
NanuSai e8506960a0 Changes (See below)
=> Fix crowdingAssignment
    => Type robust
    => Add bounds to initial population
    => Reduced if / for blocks
    => Added float test
    => Minor additional docs
2021-03-20 09:45:28 +05:30
Marcus Edel 6066feed05 Merge branch 'master' into DemonSGD 2020-12-01 22:07:00 +01:00
Marcus EdelandRyan Curtin 5e4a914f38 Minor spelling fix.
Co-authored-by: Ryan Curtin <ryan@ratml.org>
2020-12-01 22:05:52 +01:00
Marcus EdelandRyan Curtin 0265d8b31e Minor spelling fix.
Co-authored-by: Ryan Curtin <ryan@ratml.org>
2020-12-01 22:05:38 +01:00
Marcus EdelandRyan Curtin 7d9ceb1491 Minor spelling fix.
Co-authored-by: Ryan Curtin <ryan@ratml.org>
2020-12-01 22:05:28 +01:00
Marcus Edel f944ad4334 Add missing AdaSqrt test file. 2020-10-25 21:30:00 +01:00
Marcus Edel 5ffb6631f6 Update history - add AdaSqrt optimizer. 2020-10-25 21:27:22 +01:00
Marcus Edel 8e646faf4e Add AdaSqrt optimizer documentation. 2020-10-25 21:25:50 +01:00
Marcus Edel 204379ba65 Add AdaSqrt optimizer test cases. 2020-10-25 21:25:25 +01:00
Marcus Edel 77a6c3d16a Add AdaSqrt optimizer. 2020-10-25 21:25:05 +01:00
Marcus Edel a8be895fac Update histroy - add AdaBelief optimizer. 2020-10-22 01:20:53 +02:00
Marcus Edel 2f812cd01b Add AdaBelief documentation. 2020-10-22 01:19:01 +02:00
Marcus Edel d4802dbf46 Add AdaBelief test cases. 2020-10-22 01:18:34 +02:00
Marcus Edel 028b6cf9bd Add AdaBelief optimizer. 2020-10-22 01:17:56 +02:00
Marcus Edel 2cfbdad7fb Remove unused parameter. 2020-10-21 18:00:32 +02:00
Marcus Edel 5397799a5f Update histroy - add Yogi optimizer. 2020-10-21 00:32:46 +02:00
Marcus Edel 8bafa47040 Add Yogi test cases. 2020-10-21 00:29:49 +02:00
Marcus Edel 1d5e900381 Add Yogi documentation. 2020-10-21 00:28:18 +02:00
Marcus Edel fa7f682480 Add Yogi optimizer. 2020-10-19 23:48:06 +02:00
Marcus Edel c8f205c919 Merge branch 'master' into DemonSGD 2020-08-29 23:50:53 +02:00
Marcus Edel a64420b1f0 Make sure the momentum iterations parameter is non-zero. 2020-08-08 21:26:16 +02:00
Marcus Edel cd4a6366f8 Use number of iterations and batch size to intalize the momentum iterations. 2020-08-08 21:08:34 +02:00
Marcus Edel 4dd4cc4804 Remove momentum iterations parameter. 2020-08-08 21:07:26 +02:00
Marcus Edel 7af640705e Explicit type cast to avoid the loss of a fractional part and minor style fix. 2020-08-02 20:13:38 +02:00
Marcus Edel a57ff2d510 Explicit type cast to avoid the loss of a fractional part. 2020-08-02 17:49:25 +02:00
Marcus Edel 584cfe1de1 Minor style fix (indentation). 2020-08-02 17:47:42 +02:00
Marcus Edel 00d5304284 Add DemonSGD and DemonAdam optimizer to the history. 2020-08-02 17:40:30 +02:00
Marcus Edel 42bd092f87 Add DemonSGD and DemonAdam optimizer documentation. 2020-08-02 17:38:02 +02:00
Marcus Edel 006137ea63 Add DemonAdam optimizer tests. 2020-08-02 17:36:59 +02:00
Marcus Edel 1124e63fda Add DemonAdam optimizer. 2020-08-02 17:36:49 +02:00
Marcus Edel 760f9b9968 Add DemonSGD optimizer tests. 2020-08-02 17:36:27 +02:00
Marcus Edel dfc5dd3198 Add DemonSGD optimizer. 2020-08-02 17:36:05 +02:00
90 changed files with 7409 additions and 682 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
environment:
ARMADILLO_DOWNLOAD: "http://ftp.fau.de/macports/distfiles/armadillo/armadillo-8.400.0.tar.xz"
ARMADILLO_DOWNLOAD: "https://sourceforge.net/projects/arma/files/armadillo-9.800.6.tar.xz"
BLAS_LIBRARY: "%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll.a"
BLAS_LIBRARY_DLL: "%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/libopenblas.dll"
@@ -26,7 +26,7 @@ build_script:
- cd ..
- appveyor DownloadFile %ARMADILLO_DOWNLOAD% -FileName armadillo.tar.xz
- 7z x armadillo.tar.xz -so -txz | 7z x -si -ttar > nul
- cd armadillo-8.400.0 && mkdir build && cd build
- cd armadillo-9.800.6 && mkdir build && cd build
- >
cmake -G "%VSVER%"
-DBLAS_LIBRARY:FILEPATH=%BLAS_LIBRARY%
@@ -43,7 +43,7 @@ build_script:
- cd ensmallen && mkdir build && cd build
- >
cmake -G "%VSVER%"
-DARMADILLO_INCLUDE_DIR=%APPVEYOR_BUILD_FOLDER%/../armadillo-8.400.0/include/
-DARMADILLO_INCLUDE_DIR=%APPVEYOR_BUILD_FOLDER%/../armadillo-9.800.6/include/
-DARMADILLO_LIBRARIES=%BLAS_LIBRARY%
-DLAPACK_LIBRARY=%BLAS_LIBRARY%
-DBLAS_LIBRARY=%BLAS_LIBRARY%
+3 -3
View File
@@ -1,5 +1,5 @@
os: linux
dist: trusty
dist: focal
language: cpp
env:
@@ -23,10 +23,10 @@ script:
- if [ $ARMADILLO == "latest" ]; then
curl https://ftp.fau.de/macports/distfiles/armadillo/`curl https://ftp.fau.de/macports/distfiles/armadillo/ -- | grep '.tar.xz' | sed 's/^.*<a href="\(armadillo-[0-9]*.[0-9]*.[0-9]*.tar.xz\)".*$/\1/' | tail -1` | tar xvJ && cd armadillo*;
else
curl https://ftp.fau.de/macports/distfiles/armadillo/armadillo-8.400.0.tar.xz | tar -xvJ && cd armadillo*;
curl -L https://sourceforge.net/projects/arma/files/armadillo-9.800.6.tar.xz | tar -xvJ && cd armadillo*;
fi
- cmake . && make && sudo make install && cd ..
- mkdir build && cd build && cmake -DCMAKE_CXX_FLAGS="-Werror" -DCMAKE_C_FLAGS="-Werror" .. && make -j2
- mkdir build && cd build && cmake .. && make ensmallen_tests -j2
- CTEST_OUTPUT_ON_FAILURE=1 travis_wait 30 ctest -j2
notifications:
+3 -6
View File
@@ -2,12 +2,11 @@
# just installs the headers to the install location, and optionally builds the
# test program.
cmake_minimum_required(VERSION 3.3.2)
project(ensmallen
project(ensmallen
LANGUAGES C CXX)
# Configurable options for CMake.
option(USE_OPENMP "If available, use OpenMP for parallelization." ON)
option(BUILD_TESTS "Build tests." ON)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake")
@@ -58,7 +57,7 @@ if(USE_OPENMP)
endif()
# Find Armadillo and link it.
find_package(Armadillo 8.400.0 REQUIRED)
find_package(Armadillo 9.800.0 REQUIRED)
target_link_libraries(ensmallen INTERFACE Armadillo::Armadillo)
# Set helper variables for creating the version, config and target files.
@@ -96,6 +95,4 @@ install(FILES ${CMAKE_SOURCE_DIR}/include/ensmallen.hpp
# Enable testing and build tests.
enable_testing()
if (BUILD_TESTS)
add_subdirectory(tests)
endif()
add_subdirectory(tests)
+2 -2
View File
@@ -108,8 +108,8 @@ $ cd ensmallen
# - or -
$ wget http://ensmallen.org/files/ensmallen-2.16.2.tar.gz
$ tar -xvzpf ensmallen-2.16.2.tar.gz
$ wget http://ensmallen.org/files/ensmallen-2.19.0.tar.gz
$ tar -xvzpf ensmallen-2.19.0.tar.gz
$ cd ensmallen-latest
```
+102
View File
@@ -1,3 +1,105 @@
### ensmallen ?.??.?: "???"
###### ????-??-??
### ensmallen 2.19.0: "Eight Ball Deluxe"
###### 2022-04-06
* Added DemonSGD and DemonAdam optimizers
([#211](https://github.com/mlpack/ensmallen/pull/211)).
* Fix bug with Adam-like optimizers not resetting when `resetPolicy` is `true`.
([#340](https://github.com/mlpack/ensmallen/pull/340)).
* Add Yogi optimizer
([#232](https://github.com/mlpack/ensmallen/pull/232)).
* Add AdaBelief optimizer
([#233](https://github.com/mlpack/ensmallen/pull/233)).
* Add AdaSqrt optimizer
([#234](https://github.com/mlpack/ensmallen/pull/234)).
* Bump check for minimum supported version of Armadillo
([#342](https://github.com/mlpack/ensmallen/pull/342)).
### ensmallen 2.18.2: "Fairmount Bagel"
###### 2022-02-13
* Update Catch2 to 2.13.8
([#336](https://github.com/mlpack/ensmallen/pull/336)).
* Fix epoch timing output
([#337](https://github.com/mlpack/ensmallen/pull/337)).
### ensmallen 2.18.1: "Fairmount Bagel"
###### 2021-11-19
* Accelerate SGD test time
([#330](https://github.com/mlpack/ensmallen/pull/300)).
* Fix potential infinite loop in CMAES
([#331](https://github.com/mlpack/ensmallen/pull/331)).
* Fix SCD partial gradient test
([#332](https://github.com/mlpack/ensmallen/pull/332)).
### ensmallen 2.18.0: "Fairmount Bagel"
###### 2021-10-20
* Add gradient value clipping and gradient norm scaling callback
([#315](https://github.com/mlpack/ensmallen/pull/315)).
* Remove superfluous CMake option to build the tests
([#313](https://github.com/mlpack/ensmallen/pull/313)).
* Bump minimum Armadillo version to 9.800
([#318](https://github.com/mlpack/ensmallen/pull/318)).
* Update Catch2 to 2.13.7
([#322](https://github.com/mlpack/ensmallen/pull/322)).
* Remove redundant template argument for C++20 compatibility
([#324](https://github.com/mlpack/ensmallen/pull/324)).
* Fix MOEAD test stability
([#327](https://github.com/mlpack/ensmallen/pull/327)).
### ensmallen 2.17.0: "Pachis Din Me Pesa Double"
###### 2021-07-06
* CheckArbitraryFunctionTypeAPI extended for MOO support
([#283](https://github.com/mlpack/ensmallen/pull/283)).
* Refactor NSGA2
([#263](https://github.com/mlpack/ensmallen/pull/263),
[#304](https://github.com/mlpack/ensmallen/pull/304)).
* Add Indicators for Multiobjective optimizers
([#285](https://github.com/mlpack/ensmallen/pull/285)).
* Make Callback flexible for MultiObjective Optimizers
([#289](https://github.com/mlpack/ensmallen/pull/289)).
* Add ZDT Test Suite
([#273](https://github.com/mlpack/ensmallen/pull/273)).
* Add MOEA-D/DE Optimizer
([#269](https://github.com/mlpack/ensmallen/pull/269)).
* Introduce Policy Methods for MOEA/D-DE
([#293](https://github.com/mlpack/ensmallen/pull/293)).
* Add Das-Dennis weight initialization method
([#295](https://github.com/mlpack/ensmallen/pull/295)).
* Add Dirichlet Weight Initialization
([#296](https://github.com/mlpack/ensmallen/pull/296)).
* Improved installation and compilation instructions
([#300](https://github.com/mlpack/ensmallen/pull/300)).
* Disable building the tests by default for faster installation
([#303](https://github.com/mlpack/ensmallen/pull/303)).
* Modify matrix initialisation to take into account
default element zeroing in Armadillo 10.5
([#305](https://github.com/mlpack/ensmallen/pull/305)).
### ensmallen 2.16.2: "Severely Dented Can Of Polyurethane"
###### 2021-03-24
* Fix CNE test trials
+75 -36
View File
@@ -2,17 +2,16 @@
<a href="http://ensmallen.org/"><img src="http://ensmallen.org/img/ensmallen_text.svg" style="background-color:rgba(0,0,0,0);" height=230 alt="ensmallen: a C++ header-only library for numerical optimization"></a>
</h2>
**ensmallen** is a C++ header-only library for numerical optimization.
**ensmallen** is a high-quality C++ library for non-linear numerical optimization.
ensmallen provides many types of optimizers that can be used
for virtually any numerical optimization task.
This includes gradient descent techniques, gradient-free optimizers,
and constrained optimization.
ensmallen also allows optional callbacks to customize the optimization process.
Documentation and downloads: http://ensmallen.org
ensmallen provides a simple set of abstractions for writing an objective
function to optimize. It also provides a large set of standard and cutting-edge
optimizers that can be used for virtually any numerical optimization task.
These include full-batch gradient descent techniques, small-batch techniques,
gradient-free optimizers, and constrained optimization.
### Requirements
* C++ compiler with C++11 support
@@ -22,13 +21,17 @@ gradient-free optimizers, and constrained optimization.
### Installation
ensmallen can be installed with CMake 3.3 or later.
If CMake is not already available on your system, it can be obtained from https://cmake.org
ensmallen can be installed in several ways: either manually or via cmake,
with or without root access.
If you are using an older system such as RHEL 7 or CentOS 7,
an updated version of CMake is also available via the EPEL repository via the `cmake3` package.
The cmake based installation will check the requirements
and optionally build the tests. If cmake 3.3 (or a later version)
is not already available on your system, it can be obtained
from [cmake.org](https://cmake.org). If you are using an older
system such as RHEL 7 or CentOS 7, an updated version of cmake
is also available via the EPEL repository (see the `cmake3` package).
Example installation:
Example cmake based installation with root access:
```
mkdir build
@@ -37,10 +40,54 @@ cmake ..
sudo make install
```
Example cmake based installation without root access,
installing into `/home/blah/` (adapt as required):
### Example Usage
```
mkdir build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX:PATH=/home/blah/
make install
```
See [`example.cpp`](example.cpp) for example usage of the L-BFGS optimizer in a linear regression setting.
The above will create a directory named `/home/blah/include/`
and place all ensmallen headers there.
To optionally build and run the tests
(after running cmake as above),
use the following additional commands:
```
make ensmallen_tests
./ensmallen_tests --durations yes
```
Manual installation involves simply copying the `include/ensmallen.hpp` header
***and*** the associated `include/ensmallen_bits` directory to a location
such as `/usr/include/` which is searched by your C++ compiler.
If you can't use `sudo` or don't have write access to `/usr/include/`,
use a directory within your own home directory (eg. `/home/blah/include/`).
### Example Compilation
If you have installed ensmallen in a standard location such as `/usr/include/`:
g++ prog.cpp -o prog -O2 -larmadillo
If you have installed ensmallen in a non-standard location,
such as `/home/blah/include/`, you will need to make sure
that your C++ compiler searches `/home/blah/include/`
by explicitly specifying the directory as an argument/option.
For example, using the `-I` switch in gcc and clang:
g++ prog.cpp -o prog -O2 -I /home/blah/include/ -larmadillo
### Example Optimization
See [`example.cpp`](example.cpp) for example usage of the L-BFGS optimizer
in a linear regression setting.
### License
@@ -48,7 +95,7 @@ See [`example.cpp`](example.cpp) for example usage of the L-BFGS optimizer in a
Unless stated otherwise, the source code for **ensmallen** is licensed under the
3-clause BSD license (the "License"). A copy of the License is included in the
"LICENSE.txt" file. You may also obtain a copy of the License at
http://opensource.org/licenses/BSD-3-Clause .
http://opensource.org/licenses/BSD-3-Clause
### Citation
@@ -57,28 +104,20 @@ Please cite the following paper if you use ensmallen in your research and/or
software. Citations are useful for the continued development and maintenance of
the library.
* S. Bhardwaj, R. Curtin, M. Edel, Y. Mentekidis, C. Sanderson.
[ensmallen: a flexible C++ library for efficient function optimization](http://www.ensmallen.org/files/ensmallen_2018.pdf).
Workshop on Systems for ML and Open Source Software at NIPS 2018.
* Ryan R. Curtin, Marcus Edel, Rahul Ganesh Prabhu, Suryoday Basak, Zhihao Lou, Conrad Sanderson.
[The ensmallen library for flexible numerical optimization](https://jmlr.org/papers/volume22/20-416/20-416.pdf).
Journal of Machine Learning Research, Vol. 22, No. 166, 2021.
```
@article{DBLP:journals/corr/abs-1810-09361,
author = {Shikhar Bhardwaj and
Ryan R. Curtin and
Marcus Edel and
Yannis Mentekidis and
Conrad Sanderson},
title = {ensmallen: a flexible {C++} library for efficient function optimization},
journal = {CoRR},
volume = {abs/1810.09361},
doi = {10.5281/zenodo.2008650},
year = {2018},
url = {http://arxiv.org/abs/1810.09361},
archivePrefix = {arXiv},
eprint = {1810.09361},
timestamp = {Wed, 31 Oct 2018 14:24:29 +0100},
biburl = {https://dblp.org/rec/bib/journals/corr/abs-1810-09361},
bibsource = {dblp computer science bibliography, https://dblp.org}
@article{ensmallen_JMLR_2021,
author = {Ryan R. Curtin and Marcus Edel and Rahul Ganesh Prabhu and Suryoday Basak and Zhihao Lou and Conrad Sanderson},
title = {The ensmallen library for flexible numerical optimization},
journal = {Journal of Machine Learning Research},
year = {2021},
volume = {22},
number = {166},
pages = {1--6},
url = {http://jmlr.org/papers/v22/20-416.html}
}
```
+102 -2
View File
@@ -136,7 +136,7 @@ EarlyStopAtMinLoss cb(
// You could also, e.g., print the validation loss here to watch it converge.
return lrfValidation.Evaluate(coordinates);
});
arma::mat coordinates = lrfTrain.GetInitialPoint();
SMORMS3 smorms3;
smorms3.Optimize(lrfTrain, coordinates, cb);
@@ -144,6 +144,89 @@ smorms3.Optimize(lrfTrain, coordinates, cb);
</details>
### GradClipByNorm
One difficulty with optimization is that large parameter gradients can lead an
optimizer to update the parameters strongly into a region where the loss
function is much greater, effectively undoing much of the work done to get to
the current solution. Such large updates during the optimization can cause a
numerical overflow or underflow, often referred to as "exploding gradients". The
exploding gradient problem can be caused by: Choosing the wrong learning rate
which leads to huge updates in the gradients. Failing to scale a data set
leading to very large differences between data points. Applying a loss function
that computes very large error values.
A common answer to the exploding gradients problem is to change the derivative
of the error before applying the update step. One option is to clip the norm
`||g||` of the gradient `g` before a parameter update. So given the gradient,
and a maximum norm value, the callback normalizes the gradient so that its
L2-norm is less than or equal to the given maximum norm value.
#### Constructors
* `GradClipByNorm(`_`maxNorm`_`)`
#### Attributes
| **type** | **name** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `double` | **`maxNorm`** | The maximum clipping value. | |
#### Examples:
<details open>
<summary>Click to collapse/expand example code.
</summary>
```c++
AdaDelta optimizer(1.0, 1, 0.99, 1e-8, 1000, 1e-9, true);
RosenbrockFunction f;
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates, GradClipByNorm(0.3));
```
### GradClipByValue
One difficulty with optimization is that large parameter gradients can lead an
optimizer to update the parameters strongly into a region where the loss
function is much greater, effectively undoing much of the work done to get to
the current solution. Such large updates during the optimization can cause a
numerical overflow or underflow, often referred to as "exploding gradients". The
exploding gradient problem can be caused by: Choosing the wrong learning rate
which leads to huge updates in the gradients. Failing to scale a data set
leading to very large differences between data points. Applying a loss function
that computes very large error values.
A common answer to the exploding gradients problem is to change the derivative
of the error before applying the update step. One option is to clip the
parameter gradient element-wise before a parameter update.
#### Constructors
* `GradClipByValue(`_`min, max`_`)`
#### Attributes
| **type** | **name** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `double` | **`min`** | The minimum value to clip to. | |
| `double` | **`max`** | The maximum value to clip to. | |
#### Examples:
<details open>
<summary>Click to collapse/expand example code.
</summary>
```c++
AdaDelta optimizer(1.0, 1, 0.99, 1e-8, 1000, 1e-9, true);
RosenbrockFunction f;
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates, GradClipByValue(0, 1.3));
```
### PrintLoss
Callback that prints loss to stdout or a specified output stream.
@@ -208,7 +291,7 @@ optimizer.Optimize(f, coordinates, ProgressBar());
</details>
### Report
### Report
Callback that prints a optimizer report to stdout or a specified output stream.
@@ -472,6 +555,23 @@ an estimate depending on `exactObjective` value.
| `size_t` | **`epoch`** | The index of the current epoch. |
| `double` | **`objective`** | Objective value of the current point. |
### GenerationalStepTaken
Called after the evolution of a single generation. Intended specifically for
MultiObjective Optimizers.
* `GenerationalStepTaken(`_`optimizer, function, coordinates, objectives, frontIndices`_`)`
#### Attributes
| **type** | **name** | **description** |
|----------|----------|-----------------|
| `OptimizerType` | **`optimizer`** | The optimizer used to update the function. |
| `FunctionType` | **`function`** | The function to be optimized. |
| `MatType` | **`coordinates`** | The current function parameter. |
| `ObjectivesVecType` | **`objectives`** | The set of calculated objectives so far. |
| `IndicesType` | **`frontIndices`** | The indices of the members belonging to Pareto Front. |
## Custom Callbacks
### Learning rate scheduling
+5 -2
View File
@@ -554,9 +554,11 @@ Each of the implemented methods is allowed to have additional cv-modifiers
The following optimizers can be used with differentiable separable functions:
- [AdaBelief](#adabelief)
- [AdaBound](#adabound)
- [AdaDelta](#adadelta)
- [AdaGrad](#adagrad)
- [AdaSqrt](#adasqrt)
- [Adam](#adam)
- [AdaMax](#adamax)
- [AMSBound](#amsbound)
@@ -876,18 +878,19 @@ NSGA2 nsga;
double bestFrontSum = nsga.Optimize(objectives, coordinates);
// Set `bestFront` to contain all of the coordinates on the best front.
std::vector<arma::mat> bestFront = optimizer.Front();
arma::cube bestFront = optimizer.ParetoFront();
}
```
</details>
*Note*: all multi-objective function optimizers have both the function `Optimize()` to find the
best front, and also the function `Front()` to return all sets of coordinates that are on the
best front, and also the function `ParetoFront()` to return all sets of solutions that are on the
front.
The following optimizers can be used with multi-objective functions:
- [NSGA2](#nsga2)
- [MOEA/D-DE](#moead)
## Constrained functions
+415 -14
View File
@@ -1,3 +1,61 @@
## AdaBelief
*An optimizer for [differentiable separable functions](#differentiable-separable-functions).*
AdaBelief uses a different denominator from Adam, and is orthogonal to other
techniques such as recification, decoupled weight decay. The intuition for
AdaBelief is to adapt the stepsize according to the "belief" in the current
gradient direction.
#### Constructors
* `AdaBelief()`
* `AdaBelief(`_`stepSize, batchSize`_`)`
* `AdaBelief(`_`stepSize, batchSize, beta1, beta2, epsilon, maxIterations, tolerance, shuffle`_`)`
* `AdaBelief(`_`stepSize, batchSize, beta1, beta2, epsilon, maxIterations, tolerance, shuffle, resetPolicy, exactObjective`_`)`
#### Attributes
| **type** | **name** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `double` | **`stepSize`** | Step size for each iteration. | `0.001` |
| `size_t` | **`batchSize`** | Number of points to process in a single step. | `32` |
| `double` | **`beta1`** | The exponential decay rate for the 1st moment estimates. | `0.9` |
| `double` | **`beta2`** | The exponential decay rate for the 2nd moment estimates. | `0.999` |
| `double` | **`epsilon`** | A small constant for numerical stability. | `1e-8` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
| `bool` | **`exactObjective`** | Calculate the exact objective (Default: estimate the final objective obtained on the last pass over the data). | `false` |
The attributes of the optimizer may also be modified via the member methods
`StepSize()`, `BatchSize()`, `Beta1()`, `Beta2()`, `Epsilon()`, `MaxIterations()`,
`Tolerance()`, `Shuffle()`, `ResetPolicy()`, and `ExactObjective()`.
#### Examples
<details open>
<summary>Click to collapse/expand example code.
</summary>
```c++
RosenbrockFunction f;
arma::mat coordinates = f.GetInitialPoint();
AdaBelief optimizer(0.001, 32, 0.9, 0.999, 1e-12, 100000, 1e-5, true);
optimizer.Optimize(f, coordinates);
```
</details>
#### See also:
* [SGD in Wikipedia](https://en.wikipedia.org/wiki/Stochastic_gradient_descent)
* [SGD](#standard-sgd)
* [AdaBelief Optimizer: Adapting Stepsizes by the Belief in Observed Gradients](https://arxiv.org/abs/2010.07468)
* [Differentiable separable functions](#differentiable-separable-functions)
## AdaBound
*An optimizer for [differentiable separable functions](#differentiable-separable-functions).*
@@ -168,6 +226,64 @@ optimizer.Optimize(f, coordinates);
</details>
#### See also:
* [Adaptive Subgradient Methods for Online Learning and Stochastic Optimization](http://www.jmlr.org/papers/volume12/duchi11a/duchi11a.pdf)
* [AdaGrad in Wikipedia](https://en.wikipedia.org/wiki/Stochastic_gradient_descent#AdaGrad)
* [AdaDelta](#adadelta)
* [Differentiable separable functions](#differentiable-separable-functions)
## AdaSqrt
*An optimizer for [differentiable separable functions](#differentiable-separable-functions).*
AdaSqrt is an optimizer with parameter-specific learning rates, which are
adapted relative to how frequently a parameter gets updated during training.
Larger updates for more sparse parameters and smaller updates for less sparse
parameters. AdaSqrt, removes the square root in the denominator and scales the
learning rate by sqrt(T).
#### Constructors
- `AdaSqrt()`
- `AdaSqrt(`_`stepSize`_`)`
- `AdaSqrt(`_`stepSize, batchSize`_`)`
- `AdaSqrt(`_`stepSize, batchSize, epsilon, maxIterations, tolerance, shuffle`_`)`
- `AdaSqrt(`_`stepSize, batchSize, epsilon, maxIterations, tolerance, shuffle, resetPolicy, exactObjective`_`)`
#### Attributes
| **type** | **name** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `double` | **`stepSize`** | Step size for each iteration. | `0.01` |
| `size_t` | **`batchSize`** | Number of points to process in one step. | `32` |
| `double` | **`epsilon`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `tolerance` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
| `bool` | **`exactObjective`** | Calculate the exact objective (Default: estimate the final objective obtained on the last pass over the data). | `false` |
Attributes of the optimizer may also be changed via the member methods
`StepSize()`, `BatchSize()`, `Epsilon()`, `MaxIterations()`, `Tolerance()`,
`Shuffle()`, `ResetPolicy()`, and `ExactObjective()`.
#### Examples:
<details open>
<summary>Click to collapse/expand example code.
</summary>
```c++
AdaSqrt optimizer(1.0, 1, 1e-8, 1000, 1e-9, true);
RosenbrockFunction f;
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
```
</details>
#### See also:
* [Adaptive Subgradient Methods for Online Learning and Stochastic Optimization](http://www.jmlr.org/papers/volume12/duchi11a/duchi11a.pdf)
@@ -202,14 +318,14 @@ with _`UpdateRule`_` = AdamUpdate`.
| `double` | **`beta1`** | Exponential decay rate for the first moment estimates. | `0.9` |
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`eps`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
| `bool` | **`exactObjective`** | Calculate the exact objective (Default: estimate the final objective obtained on the last pass over the data). | `false` |
The attributes of the optimizer may also be modified via the member methods
`StepSize()`, `BatchSize()`, `Beta1()`, `Beta2()`, `Eps()`, `MaxIterations()`,
`StepSize()`, `BatchSize()`, `Beta1()`, `Beta2()`, `Epsilon()`, `MaxIterations()`,
`Tolerance()`, `Shuffle()`, `ResetPolicy()`, and `ExactObjective()`.
#### Examples
@@ -260,7 +376,7 @@ with _`UpdateRule`_` = AdaMaxUpdate`.
| `double` | **`beta1`** | Exponential decay rate for the first moment estimates. | `0.9` |
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`eps`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`exactObjective`** | Calculate the exact objective (Default: estimate the final objective obtained on the last pass over the data). | `false` |
@@ -380,7 +496,7 @@ with _`UpdateRule`_` = AMSGradUpdate`.
| `double` | **`beta1`** | Exponential decay rate for the first moment estimates. | `0.9` |
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`eps`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`exactObjective`** | Calculate the exact objective (Default: estimate the final objective obtained on the last pass over the data). | `false` |
@@ -744,6 +860,148 @@ optimizer.Optimize(f, coordinates);
* [Differential Evolution in Wikipedia](https://en.wikipedia.org/wiki/Differential_Evolution)
* [Arbitrary functions](#arbitrary-functions)
## DemonAdam
*An optimizer for [differentiable separable functions](#differentiable-separable-functions).*
DemonAdam is an Adam based optimizer. DemonAdam is motivated by decaying the
total contribution of a gradient to all future updates.
#### Constructors
* `DemonAdam()`
* `DemonAdam(`_`stepSize, batchSize`_`)`
* `DemonAdam(`_`stepSize, batchSize, momentum, beta1, beta2, eps, maxIterations, tolerance, shuffle`_`)`
* `DemonAdam(`_`stepSize, batchSize, momentum, beta1, beta2, eps, maxIterations, tolerance, shuffle, resetPolicy`_`)`
Note that the `DemonAdam` class is based on
the `DemonAdamType<`_`UpdateRule`_`>` class with _`UpdateRule`_` = AdamUpdate`.
For convenience the following typedefs have been defined:
* `DemonAdaMax` (equivalent to `DemonAdamType<AdaMaxUpdate>`): DemonAdam that
uses the AdaMax update rule.
* `DemonAMSGrad` (equivalent to `DemonAdamType<AMSGradUpdate>`): DemonAdam that
uses the AMSGrad update rule.
* `DemonNadam` (equivalent to `DemonAdamType<NadamUpdate>`): DemonAdam that
uses the Nadam update rule.
* `NadamUpdate` (equivalent to `DemonAdamType<NadaMaxUpdate>`): DemonAdam that
uses the NadaMax update rule.
* `DemonOptimisticAdam` (equivalent to `DemonAdamType<OptimisticAdamUpdate>`):
DemonAdam that uses the OptimisticAdam update rule.
#### Attributes
| **type** | **name** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `double` | **`stepSize`** | Step size for each iteration. | `0.001` |
| `size_t` | **`batchSize`** | Number of points to process in a single step. | `32` |
| `double` | **`momentum`** | The initial momentum coefficient. | `0.9` |
| `double` | **`beta1`** | Exponential decay rate for the first moment estimates. | `0.9` |
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`eps`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
The attributes of the optimizer may also be modified via the member methods
`StepSize()`, `BatchSize()`, `Momentum()`, `MomentumIterations()`, `Beta1()`,
`Beta2()`, `Eps()`, `MaxIterations()`, `Tolerance()`, `Shuffle()`, and
`ResetPolicy()`.
#### Examples
<details open>
<summary>Click to collapse/expand example code.
</summary>
```c++
MatyasFunction f;
arma::mat coordinates = f.GetInitialPoint();
DemonAdam optimizer(0.5, 1, 0.9);
optimizer.Optimize(f, coordinates);
```
</details>
#### See also:
* [SGD in Wikipedia](https://en.wikipedia.org/wiki/Stochastic_gradient_descent)
* [SGD](#standard-sgd)
* [Decaying momentum helps neural network training](https://arxiv.org/abs/1910.04952)
* [Differentiable separable functions](#differentiable-separable-functions)
## DemonSGD
*An optimizer for [differentiable separable functions](#differentiable-separable-functions).*
DemonSGD is an SGD based optimizer. DemonSGD is motivated by decaying the total
contribution of a gradient to all future updates.
For convenience ensmallen implements various Adam based versions of the Demon
optimizer:
* `DemonAdam` (equivalent to `DemonAdamType<AdamUpdate>`): DemonAdam that uses
the Adam update rule.
* `DemonAdaMax` (equivalent to `DemonAdamType<AdaMaxUpdate>`): DemonAdam that
uses the AdaMax update rule.
* `DemonAMSGrad` (equivalent to `DemonAdamType<AMSGradUpdate>`): DemonAdam that
uses the AMSGrad update rule.
* `DemonNadam` (equivalent to `DemonAdamType<NadamUpdate>`): DemonAdam that
uses the Nadam update rule.
* `NadamUpdate` (equivalent to `DemonAdamType<NadaMaxUpdate>`): DemonAdam that
uses the NadaMax update rule.
* `DemonOptimisticAdam` (equivalent to `DemonAdamType<OptimisticAdamUpdate>`):
DemonAdam that uses the OptimisticAdam update rule.
#### Constructors
* `DemonSGD()`
* `DemonSGD(`_`stepSize, batchSize`_`)`
* `DemonSGD(`_`stepSize, batchSize, momentum, maxIterations, tolerance, shuffle`_`)`
* `DemonSGD(`_`stepSize, batchSize, momentum, maxIterations, tolerance, shuffle, resetPolicy`_`)`
#### Attributes
| **type** | **name** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `double` | **`stepSize`** | Step size for each iteration. | `0.001` |
| `size_t` | **`batchSize`** | Number of points to process in a single step. | `32` |
| `double` | **`momentum`** | The initial momentum coefficient. | `0.9` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
The attributes of the optimizer may also be modified via the member methods
`StepSize()`, `BatchSize()`, `Momentum()`, `MomentumIterations()`,
`MaxIterations()`, `Tolerance()`, `Shuffle()`, and `ResetPolicy()`.
#### Examples
<details open>
<summary>Click to collapse/expand example code.
</summary>
```c++
MatyasFunction f;
arma::mat coordinates = f.GetInitialPoint();
DemonSGD optimizer(0.5, 1, 0.9);
optimizer.Optimize(f, coordinates);
```
</details>
#### See also:
* [SGD in Wikipedia](https://en.wikipedia.org/wiki/Stochastic_gradient_descent)
* [SGD](#standard-sgd)
* [Decaying momentum helps neural network training](https://arxiv.org/abs/1910.04952)
* [Differentiable separable functions](#differentiable-separable-functions)
## Eve
*An optimizer for [differentiable separable functions](#differentiable-separable-functions).*
@@ -766,8 +1024,8 @@ Eve is a stochastic gradient based optimization method with locally and globally
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`beta3`** | Exponential decay rate for relative change. | `0.999` |
| `double` | **`epsilon`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `double` | **`clip`** | Clipping range to avoid extreme values. | `10` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`clip`** | Clipping range to avoid extreme valus. | `10` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`exactObjective`** | Calculate the exact objective (Default: estimate the final objective obtained on the last pass over the data). | `false` |
@@ -875,7 +1133,7 @@ changes.
| `double` | **`beta1`** | Exponential decay rate for the first moment estimates. | `0.9` |
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`eps`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
@@ -1246,7 +1504,7 @@ can be paired with the `Lookahead` optimizer.
| `BaseOptimizerType` | **`baseOptimizer`** | Optimizer for the forward step. | Adam |
| `double` | **`stepSize`** | Step size for each iteration. | `0.5` |
| `size_t` | **`k`** | The synchronization period. | `5` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `DecayPolicyType` | **`decayPolicy`** | Instantiated decay policy used to adjust the step size. | `DecayPolicyType()` |
| `bool` | **`exactObjective`** | Calculate the exact objective (Default: estimate the final objective obtained on the last pass over the data). | `false` |
@@ -1408,7 +1666,7 @@ with _`UpdateRule`_` = NadamUpdate`.
| `double` | **`beta1`** | Exponential decay rate for the first moment estimates. | `0.9` |
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`eps`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
@@ -1466,7 +1724,7 @@ with _`UpdateRule`_` = NadaMaxUpdate`.
| `double` | **`beta1`** | Exponential decay rate for the first moment estimates. | `0.9` |
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`eps`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
@@ -1563,6 +1821,96 @@ optimizer.Optimize(f, coordinates);
* [SGD in Wikipedia](https://en.wikipedia.org/wiki/Stochastic_gradient_descent)
* [Differentiable separable functions](#differentiable-separable-functions)
## MOEA/D-DE
*An optimizer for arbitrary multi-objective functions.*
MOEA/D-DE (Multi Objective Evolutionary Algorithm based on Decomposition - Differential Evolution) is a multi
objective optimization algorithm. It works by decomposing the problem into a number of scalar optimization
subproblems which are solved simultaneously per generation. MOEA/D in itself is a framework, this particular
algorithm uses Differential Crossover followed by Polynomial Mutation to create offsprings which are then
decomposed to form a Single Objective Problem. A diversity preserving mechanism is also employed which encourages
a varied set of solution.
#### Constructors
* `MOEAD<`_`InitPolicyType, DecompPolicyType`_`>()`
* `MOEAD<`_`InitPolicyType, DecompPolicyType`_`>(`_`populationSize, maxGenerations, crossoverProb, neighborProb, neighborSize, distributionIndex, differentialWeight, maxReplace, epsilon, lowerBound, upperBound`_`)`
The _`InitPolicyType`_ template parameter refers to the strategy used to
initialize the reference directions.
The following types are available:
* **`Uniform`**
* **`BayesianBootstrap`**
* **`Dirichlet`**
The _`DecompPolicyType`_ template parameter refers to the strategy used to
decompose the weight vectors to form a scalar objective function.
The following types are available:
* **`Tchebycheff`**
* **`WeightedAverage`**
* **`PenaltyBoundaryIntersection`**
For convenience the following types can be used:
* **`DefaultMOEAD`** (equivalent to `MOEAD<Uniform, Tchebycheff>`): utilizes Uniform method for weight initialization
and Tchebycheff for weight decomposition.
* **`BBSMOEAD`** (equivalent to `MOEAD<BayesianBootstrap, Tchebycheff>`): utilizes Bayesian Bootstrap method for weight initialization and Tchebycheff for weight decomposition.
* **`DirichletMOEAD`** (equivalent to `MOEAD<Dirichlet, Tchebycheff>`): utilizes Dirichlet sampling for weight init
and Tchebycheff for weight decomposition.
#### Attributes
| **type** | **name** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `size_t` | **`populationSize`** | The number of candidates in the population. | `150` |
| `size_t` | **`maxGenerations`** | The maximum number of generations allowed. | `300` |
| `double` | **`crossoverProb`** | Probability that a crossover will occur. | `1.0` |
| `double` | **`neighborProb`** | The probability of sampling from neighbor. | `0.9` |
| `size_t` | **`neighborSize`** | The number of nearest-neighbours to consider per weight vector. | `20` |
| `double` | **`distributionIndex`** | The crowding degree of the mutation. | `20` |
| `double` | **`differentialWeight`** | Amplification factor of the differentiation. | `0.5` |
| `size_t` | **`maxReplace`** | The limit of solutions allowed to be replaced by a child. | `2`|
| `double` | **`epsilon`** | Handles numerical stability after weight initialization. | `1E-10`|
| `double`, `arma::vec` | **`lowerBound`** | Lower bound of the coordinates on the coordinates of the whole population during the search process. | `0` |
| `double`, `arma::vec` | **`upperBound`** | Lower bound of the coordinates on the coordinates of the whole population during the search process. | `1` |
| `InitPolicyType` | **`initPolicy`** | Instantiated init policy used to initialize weights. | `InitPolicyType()` |
| `DecompPolicyType` | **`decompPolicy`** | Instantiated decomposition policy used to create scalar objective problem. | `DecompPolicyType()` |
Attributes of the optimizer may also be changed via the member methods
`PopulationSize()`, `MaxGenerations()`, `CrossoverRate()`, `NeighborProb()`, `NeighborSize()`, `DistributionIndex()`,
`DifferentialWeight()`, `MaxReplace()`, `Epsilon()`, `LowerBound()`, `UpperBound()`, `InitPolicy()` and `DecompPolicy()`.
#### Examples:
<details open>
<summary>Click to collapse/expand example code.
</summary>
```c++
SchafferFunctionN1<arma::mat> SCH;
arma::vec lowerBound("-10 -10");
arma::vec upperBound("10 10");
DefaultMOEAD opt(300, 300, 1.0, 0.9, 20, 20, 0.5, 2, 1E-10, lowerBound, upperBound);
typedef decltype(SCH.objectiveA) ObjectiveTypeA;
typedef decltype(SCH.objectiveB) ObjectiveTypeB;
arma::mat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
// obj will contain the minimum sum of objectiveA and objectiveB found on the best front.
double obj = opt.Optimize(objectives, coords);
// Now obtain the best front.
arma::cube bestFront = opt.ParetoFront();
```
</details>
#### See also
* [MOEA/D-DE Algorithm](https://ieeexplore.ieee.org/document/4633340)
* [Multi-objective Functions in Wikipedia](https://en.wikipedia.org/wiki/Test_functions_for_optimization#Test_functions_for_multi-objective_optimization)
* [Multi-objective functions](#multi-objective-functions)
## NSGA2
*An optimizer for arbitrary multi-objective functions.*
@@ -1619,7 +1967,7 @@ std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
// obj will contain the minimum sum of objectiveA and objectiveB found on the best front.
double obj = opt.Optimize(objectives, coords);
// Now obtain the best front.
std::vector<arma::mat> bestFront = opt.Front();
arma::cube bestFront = opt.Front();
```
</details>
@@ -1661,7 +2009,7 @@ Note that the `OptimisticAdam` class is based on the
| `double` | **`beta1`** | Exponential decay rate for the first moment estimates. | `0.9` |
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`eps`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
@@ -1715,7 +2063,7 @@ Padam is a variant of Adam with a partially adaptive momentum estimation method.
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`partial`** | Partially adaptive parameter. | `0.25` |
| `double` | **`eps`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
@@ -2008,7 +2356,7 @@ the following other optimizers:
| `double` | **`beta1`** | Exponential decay rate for the first moment estimates. | `0.9` |
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`eps`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `size_t` | **`maxIterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
@@ -2886,3 +3234,56 @@ optimizer.Optimize(f, coordinates);
* [SGD](#standard-sgd)
* [SGD in Wikipedia](https://en.wikipedia.org/wiki/Stochastic_gradient_descent)
* [Differentiable separable functions](#differentiable-separable-functions)
## Yogi
*An optimizer for [differentiable separable functions](#differentiable-separable-functions).*
Yogi is an optimization algorithm based on Adam with more fine-grained effective
learning rate control, which uses additive updates instead of multiplicative
updates for the moving average of the squared gradient. In addition, Yogi has
similar theoretical guarantees on convergence as Adam.
#### Constructors
* `Yogi()`
* `Yogi(`_`stepSize, batchSize`_`)`
* `Yogi(`_`stepSize, batchSize, beta1, beta2, eps, maxIterations`_`)`
* `Yogi(`_`stepSize, batchSize, beta1, beta2, eps, maxIterations, tolerance, shuffle, resetPolicy, exactObjective`_`)`
#### Attributes
| **type** | **name** | **description** | **default** |
|----------|----------|-----------------|-------------|
| `double` | **`stepSize`** | Step size for each iteration. | `0.001` |
| `size_t` | **`batchSize`** | Number of points to process in a single step. | `32` |
| `double` | **`beta1`** | Exponential decay rate for the first moment estimates. | `0.9` |
| `double` | **`beta2`** | Exponential decay rate for the weighted infinity norm estimates. | `0.999` |
| `double` | **`eps`** | Value used to initialize the mean squared gradient parameter. | `1e-8` |
| `size_t` | **`max_iterations`** | Maximum number of iterations allowed (0 means no limit). | `100000` |
| `double` | **`tolerance`** | Maximum absolute tolerance to terminate algorithm. | `1e-5` |
| `bool` | **`shuffle`** | If true, the function order is shuffled; otherwise, each function is visited in linear order. | `true` |
| `bool` | **`resetPolicy`** | If true, parameters are reset before every Optimize call; otherwise, their values are retained. | `true` |
| `bool` | **`exactObjective`** | Calculate the exact objective (Default: estimate the final objective obtained on the last pass over the data). | `false` |
The attributes of the optimizer may also be modified via the member methods
`StepSize()`, `BatchSize()`, `Beta1()`, `Beta2()`, `Eps()`, `MaxIterations()`,
`Tolerance()`, `Shuffle()`, `ResetPolicy()`, and `ExactObjective()`.
#### Examples
```c++
RosenbrockFunction f;
arma::mat coordinates = f.GetInitialPoint();
Yogi optimizer(0.001, 32, 0.9, 0.999, 1e-8, 100000, 1e-5, true);
optimizer.Optimize(f, coordinates);
```
#### See also:
* [Adaptive Methods for Nonconvex Optimization](https://papers.nips.cc/paper/8186-adaptive-methods-for-nonconvex-optimization)
* [SGD in Wikipedia](https://en.wikipedia.org/wiki/Stochastic_gradient_descent)
* [SGD](#standard-sgd)
* [Adam](#adam)
* [Differentiable separable functions](#differentiable-separable-functions)
+13 -2
View File
@@ -29,8 +29,8 @@
#error "please enable C++11/C++14 mode in your compiler"
#endif
#if ((ARMA_VERSION_MAJOR < 8) || ((ARMA_VERSION_MAJOR == 8) && (ARMA_VERSION_MINOR < 400)))
#error "need Armadillo version 8.400 or later"
#if ((ARMA_VERSION_MAJOR < 9) || ((ARMA_VERSION_MAJOR == 9) && (ARMA_VERSION_MINOR < 800)))
#error "need Armadillo version 9.800 or later"
#endif
#include <cctype>
@@ -65,6 +65,8 @@
#include "ensmallen_bits/utility/any.hpp"
#include "ensmallen_bits/utility/arma_traits.hpp"
#include "ensmallen_bits/utility/indicators/epsilon.hpp"
#include "ensmallen_bits/utility/indicators/igd_plus.hpp"
// Contains traits, must be placed before report callback.
#include "ensmallen_bits/function.hpp" // TODO: should move to function/
@@ -72,18 +74,25 @@
// Callbacks.
#include "ensmallen_bits/callbacks/callbacks.hpp"
#include "ensmallen_bits/callbacks/early_stop_at_min_loss.hpp"
#include "ensmallen_bits/callbacks/grad_clip_by_norm.hpp"
#include "ensmallen_bits/callbacks/grad_clip_by_value.hpp"
#include "ensmallen_bits/callbacks/print_loss.hpp"
#include "ensmallen_bits/callbacks/progress_bar.hpp"
#include "ensmallen_bits/callbacks/query_front.hpp"
#include "ensmallen_bits/callbacks/report.hpp"
#include "ensmallen_bits/callbacks/store_best_coordinates.hpp"
#include "ensmallen_bits/callbacks/timer_stop.hpp"
#include "ensmallen_bits/problems/problems.hpp" // TODO: should move to another place
#include "ensmallen_bits/ada_belief/ada_belief.hpp"
#include "ensmallen_bits/ada_bound/ada_bound.hpp"
#include "ensmallen_bits/ada_delta/ada_delta.hpp"
#include "ensmallen_bits/ada_grad/ada_grad.hpp"
#include "ensmallen_bits/ada_sqrt/ada_sqrt.hpp"
#include "ensmallen_bits/adam/adam.hpp"
#include "ensmallen_bits/demon_adam/demon_adam.hpp"
#include "ensmallen_bits/demon_sgd/demon_sgd.hpp"
#include "ensmallen_bits/qhadam/qhadam.hpp"
#include "ensmallen_bits/aug_lagrangian/aug_lagrangian.hpp"
#include "ensmallen_bits/bigbatch_sgd/bigbatch_sgd.hpp"
@@ -100,6 +109,7 @@
#include "ensmallen_bits/katyusha/katyusha.hpp"
#include "ensmallen_bits/lbfgs/lbfgs.hpp"
#include "ensmallen_bits/lookahead/lookahead.hpp"
#include "ensmallen_bits/moead/moead.hpp"
#include "ensmallen_bits/nsga2/nsga2.hpp"
#include "ensmallen_bits/padam/padam.hpp"
#include "ensmallen_bits/parallel_sgd/parallel_sgd.hpp"
@@ -125,5 +135,6 @@
#include "ensmallen_bits/svrg/svrg.hpp"
#include "ensmallen_bits/swats/swats.hpp"
#include "ensmallen_bits/wn_grad/wn_grad.hpp"
#include "ensmallen_bits/yogi/yogi.hpp"
#endif
@@ -0,0 +1,186 @@
/**
* @file ada_belief.hpp
* @author Marcus Edel
*
* Class wrapper for the AdaBelief update Policy. The intuition for AdaBelief is
* to adapt the stepsize according to the "belief" in the current gradient
* direction.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_ADA_BELIEF_HPP
#define ENSMALLEN_ADA_BELIEF_HPP
#include <ensmallen_bits/sgd/sgd.hpp>
#include "ada_belief_update.hpp"
namespace ens {
/**
* The intuition for AdaBelief is to adapt the stepsize according to the
* "belief" in the current gradient direction. For more information, see the
* following.
*
* @code
* @misc{zhuang2020adabelief,
* title = {AdaBelief Optimizer: Adapting Stepsizes by the Belief in
* Observed Gradients},
* author = {Juntang Zhuang and Tommy Tang and Sekhar Tatikonda and
* Nicha Dvornek and Yifan Ding and Xenophon Papademetris
* and James S. Duncan},
* year = {2020},
* eprint = {2010.07468},
* archivePrefix = {arXiv},
* }
* @endcode
*
* AdaBelief can optimize differentiable separable functions. For more details,
* see the documentation on function types included with this distribution or
* on the ensmallen website.
*/
class AdaBelief
{
public:
/**
* Construct the AdaBelief optimizer with the given function and parameters.
* AdaBelief is sensitive to its parameters and hence a good hyperparameter
* selection is necessary as its default may not fit every case.
*
* The maximum number of iterations refers to the maximum number of
* points that are processed (i.e., one iteration equals one point; one
* iteration does not equal one pass over the dataset).
*
* @param stepSize Step size for each iteration.
* @param batchSize Number of points to process in a single step.
* @param beta1 The exponential decay rate for the 1st moment estimates.
* @param beta2 The exponential decay rate for the 2nd moment estimates.
* @param epsilon A small constant for numerical stability.
* @param maxIterations Maximum number of iterations allowed (0 means no
* limit).
* @param tolerance Maximum absolute tolerance to terminate algorithm.
* @param shuffle If true, the function order is shuffled; otherwise, each
* function is visited in linear order.
* @param resetPolicy If true, parameters are reset before every Optimize
* call; otherwise, their values are retained.
* @param exactObjective Calculate the exact objective (Default: estimate the
* final objective obtained on the last pass over the data).
*/
AdaBelief(const double stepSize = 0.001,
const size_t batchSize = 32,
const double beta1 = 0.9,
const double beta2 = 0.999,
const double epsilon = 1e-12,
const size_t maxIterations = 100000,
const double tolerance = 1e-5,
const bool shuffle = true,
const bool resetPolicy = true,
const bool exactObjective = false);
/**
* Optimize the given function using AdaBelief. The given starting point will
* be modified to store the finishing point of the algorithm, and the final
* objective value is returned.
*
* @tparam SeparableFunctionType Type of the function to optimize.
* @tparam MatType Type of matrix to optimize with.
* @tparam GradType Type of matrix to use to represent function gradients.
* @tparam CallbackTypes Types of callback functions.
* @param function Function to optimize.
* @param iterate Starting point (will be modified).
* @param callbacks Callback functions.
* @return Objective value of the final point.
*/
template<typename SeparableFunctionType,
typename MatType,
typename GradType,
typename... CallbackTypes>
typename std::enable_if<IsArmaType<GradType>::value,
typename MatType::elem_type>::type
Optimize(SeparableFunctionType& function,
MatType& iterate,
CallbackTypes&&... callbacks)
{
return optimizer.Optimize<SeparableFunctionType, MatType, GradType,
CallbackTypes...>(function, iterate,
std::forward<CallbackTypes>(callbacks)...);
}
//! Forward the MatType as GradType.
template<typename SeparableFunctionType,
typename MatType,
typename... CallbackTypes>
typename MatType::elem_type Optimize(SeparableFunctionType& function,
MatType& iterate,
CallbackTypes&&... callbacks)
{
return Optimize<SeparableFunctionType, MatType, MatType,
CallbackTypes...>(function, iterate,
std::forward<CallbackTypes>(callbacks)...);
}
//! Get the step size.
double StepSize() const { return optimizer.StepSize(); }
//! Modify the step size.
double& StepSize() { return optimizer.StepSize(); }
//! Get the batch size.
size_t BatchSize() const { return optimizer.BatchSize(); }
//! Modify the batch size.
size_t& BatchSize() { return optimizer.BatchSize(); }
//! Get the exponential decay rate for the 1st moment estimates.
double Beta1() const { return optimizer.UpdatePolicy().Beta1(); }
//! Modify the exponential decay rate for the 1st moment estimates.
double& Beta1() { return optimizer.UpdatePolicy().Beta1(); }
//! Get the exponential decay rate for the 2nd moment estimates.
double Beta2() const { return optimizer.UpdatePolicy().Beta2(); }
//! Get the second moment coefficient.
double& Beta2() { return optimizer.UpdatePolicy().Beta2(); }
//! Get the value for numerical stability.
double Epsilon() const { return optimizer.UpdatePolicy().Epsilon(); }
//! Modify the value used for numerical stability.
double& Epsilon() { return optimizer.UpdatePolicy().Epsilon(); }
//! Get the maximum number of iterations (0 indicates no limit).
size_t MaxIterations() const { return optimizer.MaxIterations(); }
//! Modify the maximum number of iterations (0 indicates no limit).
size_t& MaxIterations() { return optimizer.MaxIterations(); }
//! Get the tolerance for termination.
double Tolerance() const { return optimizer.Tolerance(); }
//! Modify the tolerance for termination.
double& Tolerance() { return optimizer.Tolerance(); }
//! Get whether or not the individual functions are shuffled.
bool Shuffle() const { return optimizer.Shuffle(); }
//! Modify whether or not the individual functions are shuffled.
bool& Shuffle() { return optimizer.Shuffle(); }
//! Get whether or not the actual objective is calculated.
bool ExactObjective() const { return optimizer.ExactObjective(); }
//! Modify whether or not the actual objective is calculated.
bool& ExactObjective() { return optimizer.ExactObjective(); }
//! Get whether or not the update policy parameters are reset before
//! Optimize call.
bool ResetPolicy() const { return optimizer.ResetPolicy(); }
//! Modify whether or not the update policy parameters
//! are reset before Optimize call.
bool& ResetPolicy() { return optimizer.ResetPolicy(); }
private:
//! The Stochastic Gradient Descent object with AdaBelief policy.
SGD<AdaBeliefUpdate> optimizer;
};
} // namespace ens
// Include implementation.
#include "ada_belief_impl.hpp"
#endif
@@ -0,0 +1,44 @@
/**
* @file ada_belief_impl.hpp
* @author Marcus Edel
*
* Implementation of AdaBelief class wrapper.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_ADA_BELIEF_ADA_BELIEF_IMPL_HPP
#define ENSMALLEN_ADA_BELIEF_ADA_BELIEF_IMPL_HPP
// In case it hasn't been included yet.
#include "ada_belief.hpp"
namespace ens {
inline AdaBelief::AdaBelief(
const double stepSize,
const size_t batchSize,
const double beta1,
const double beta2,
const double epsilon,
const size_t maxIterations,
const double tolerance,
const bool shuffle,
const bool resetPolicy,
const bool exactObjective) :
optimizer(stepSize,
batchSize,
maxIterations,
tolerance,
shuffle,
AdaBeliefUpdate(epsilon, beta1, beta2),
NoDecay(),
resetPolicy,
exactObjective)
{ /* Nothing to do. */ }
} // namespace ens
#endif
@@ -0,0 +1,153 @@
/**
* @file ada_belief_update.hpp
* @author Marcus Edel
*
* AdaBelief optimizer update policy. The intuition for AdaBelief is to adapt
* the stepsize according to the "belief" in the current gradient direction.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_ADA_BELIEF_ADA_BELIEF_UPDATE_HPP
#define ENSMALLEN_ADA_BELIEF_ADA_BELIEF_UPDATE_HPP
namespace ens {
/**
* The intuition for AdaBelief is to adapt the stepsize according to the
* "belief" in the current gradient direction.
*
* For more information, see the following.
*
* @code
* @misc{zhuang2020adabelief,
* title = {AdaBelief Optimizer: Adapting Stepsizes by the Belief in
* Observed Gradients},
* author = {Juntang Zhuang and Tommy Tang and Sekhar Tatikonda and
* Nicha Dvornek and Yifan Ding and Xenophon Papademetris
* and James S. Duncan},
* year = {2020},
* eprint = {2010.07468},
* archivePrefix = {arXiv},
* }
* @endcode
*/
class AdaBeliefUpdate
{
public:
/**
* Construct the AdaBelief update policy with the given parameters.
*
* @param epsilon A small constant for numerical stability.
* @param beta1 The exponential decay rate for the 1st moment estimates.
* @param beta2 The exponential decay rate for the 2nd moment estimates.
*/
AdaBeliefUpdate(const double epsilon = 1e-8,
const double beta1 = 0.9,
const double beta2 = 0.999) :
epsilon(epsilon),
beta1(beta1),
beta2(beta2)
{
// Nothing to do.
}
//! Get the value for numerical stability.
double Epsilon() const { return epsilon; }
//! Modify the value used for numerical stability.
double& Epsilon() { return epsilon; }
//! Get the exponential decay rate for the 1st moment estimates.
double Beta1() const { return beta1; }
//! Modify the exponential decay rate for the 1st moment estimates.
double& Beta1() { return beta1; }
//! Get the exponential decay rate for the 2nd moment estimates.
double Beta2() const { return beta2; }
//! Modify the exponential decay rate for the 2nd moment estimates.
double& Beta2() { return beta2; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
* instantiated at the start of the optimization, and holds parameters
* specific to an individual optimization.
*/
template<typename MatType, typename GradType>
class Policy
{
public:
/**
* This constructor is called by the SGD Optimize() method before the start
* of the iteration update process.
*
* @param parent AdaBeliefUpdate object.
* @param rows Number of rows in the gradient matrix.
* @param cols Number of columns in the gradient matrix.
*/
Policy(AdaBeliefUpdate& parent, const size_t rows, const size_t cols) :
parent(parent),
iteration(0)
{
m.zeros(rows, cols);
s.zeros(rows, cols);
}
/**
* Update step for AdaBelief.
*
* @param iterate Parameters that minimize the function.
* @param stepSize Step size to be used for the given iteration.
* @param gradient The gradient matrix.
*/
void Update(MatType& iterate,
const double stepSize,
const GradType& gradient)
{
// Increment the iteration counter variable.
++iteration;
m *= parent.beta1;
m += (1 - parent.beta1) * gradient;
s *= parent.beta2;
s += (1 - parent.beta2) * arma::pow(gradient - m, 2.0) + parent.epsilon;
const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
// And update the iterate.
iterate -= ((m / biasCorrection1) * stepSize) / (arma::sqrt(s /
biasCorrection2) + parent.epsilon);
}
private:
//! Instantiated parent object.
AdaBeliefUpdate& parent;
//! The exponential moving average of gradient values.
GradType m;
// The exponential moving average of squared gradient values.
GradType s;
// The number of iterations.
size_t iteration;
};
private:
// The epsilon value used to initialise the squared gradient parameter.
double epsilon;
// The xponential decay rate for the 1st moment estimates.
double beta1;
// The exponential decay rate for the 2nd moment estimates.
double beta2;
};
} // namespace ens
#endif
@@ -56,8 +56,7 @@ class AdaBoundUpdate
gamma(gamma),
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
iteration(0)
beta2(beta2)
{
// Nothing to do.
}
@@ -87,11 +86,6 @@ class AdaBoundUpdate
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
@@ -111,7 +105,7 @@ class AdaBoundUpdate
* @param cols Number of columns in the gradient matrix.
*/
Policy(AdaBoundUpdate& parent, const size_t rows, const size_t cols) :
parent(parent), first(true), initialStepSize(0)
parent(parent), first(true), initialStepSize(0), iteration(0)
{
m.zeros(rows, cols);
v.zeros(rows, cols);
@@ -139,7 +133,7 @@ class AdaBoundUpdate
}
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
// Decay the first and second moment running average coefficient.
m *= parent.beta1;
@@ -148,16 +142,12 @@ class AdaBoundUpdate
v *= parent.beta2;
v += (1 - parent.beta2) * (gradient % gradient);
const ElemType biasCorrection1 = 1.0 - std::pow(parent.beta1,
parent.iteration);
const ElemType biasCorrection2 = 1.0 - std::pow(parent.beta2,
parent.iteration);
const ElemType biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const ElemType biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
const ElemType fl = parent.finalLr * stepSize / initialStepSize;
const ElemType lower = fl * (1.0 - 1.0 / (parent.gamma *
parent.iteration + 1));
const ElemType upper = fl * (1.0 + 1.0 / (parent.gamma *
parent.iteration));
const ElemType lower = fl * (1.0 - 1.0 / (parent.gamma * iteration + 1));
const ElemType upper = fl * (1.0 + 1.0 / (parent.gamma * iteration));
// Applies bounds on actual learning rate.
iterate -= arma::clamp((stepSize *
@@ -180,6 +170,9 @@ class AdaBoundUpdate
// The initial (Adam) learning rate.
double initialStepSize;
// The number of iterations.
size_t iteration;
};
private:
@@ -197,9 +190,6 @@ class AdaBoundUpdate
// The second moment coefficient.
double beta2;
// The number of iterations.
size_t iteration;
};
} // namespace ens
@@ -56,8 +56,7 @@ class AMSBoundUpdate
gamma(gamma),
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
iteration(0)
beta2(beta2)
{
// Nothing to do.
}
@@ -87,11 +86,6 @@ class AMSBoundUpdate
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
@@ -111,7 +105,7 @@ class AMSBoundUpdate
* @param cols Number of columns in the gradient matrix.
*/
Policy(AMSBoundUpdate& parent, const size_t rows, const size_t cols) :
parent(parent), first(true), initialStepSize(0)
parent(parent), first(true), initialStepSize(0), iteration(0)
{
m.zeros(rows, cols);
v.zeros(rows, cols);
@@ -140,7 +134,7 @@ class AMSBoundUpdate
}
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
// Decay the first and second moment running average coefficient.
m *= parent.beta1;
@@ -149,16 +143,12 @@ class AMSBoundUpdate
v *= parent.beta2;
v += (1 - parent.beta2) * (gradient % gradient);
const ElemType biasCorrection1 = 1.0 - std::pow(parent.beta1,
parent.iteration);
const ElemType biasCorrection2 = 1.0 - std::pow(parent.beta2,
parent.iteration);
const ElemType biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const ElemType biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
const ElemType fl = parent.finalLr * stepSize / initialStepSize;
const ElemType lower = fl * (1.0 - 1.0 / (parent.gamma *
parent.iteration + 1));
const ElemType upper = fl * (1.0 + 1.0 / (parent.gamma *
parent.iteration));
const ElemType lower = fl * (1.0 - 1.0 / (parent.gamma * iteration + 1));
const ElemType upper = fl * (1.0 + 1.0 / (parent.gamma * iteration));
// Element wise maximum of past and present squared gradients.
vImproved = arma::max(vImproved, v);
@@ -187,6 +177,9 @@ class AMSBoundUpdate
// The optimal squared gradient value.
GradType vImproved;
// The number of iterations.
size_t iteration;
};
private:
@@ -204,9 +197,6 @@ class AMSBoundUpdate
// The second moment coefficient.
double beta2;
// The number of iterations.
size_t iteration;
};
} // namespace ens
@@ -0,0 +1,168 @@
/**
* @file ada_sqrt.hpp
* @author Marcus Edel
*
* Implementation of the AdaSqrt optimizer. AdaSqrt is an optimizer that
* chooses learning rate dynamically by adapting to the data and iteration.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_ADA_SQRT_ADA_SQRT_HPP
#define ENSMALLEN_ADA_SQRT_ADA_SQRT_HPP
#include "../sgd/sgd.hpp"
#include "ada_sqrt_update.hpp"
namespace ens {
/**
* AdaSqrt is a modified version of stochastic gradient descent which performs
* larger updates for more sparse parameters and smaller updates for less sparse
* parameters.
*
* For more information, see the following.
*
* @code
* @misc{hu2019secondorder,
* title = {Second-order Information in First-order Optimization Methods},
* author = {Yuzheng Hu and Licong Lin and Shange Tang},
* year = {2019},
* eprint = {1912.09926},
* }
* @endcode
*
* AdaSqrt can optimize differentiable separable functions. For more details,
* see the documentation on function types included with this distribution or on
* the ensmallen website.
*/
class AdaSqrt
{
public:
/**
* Construct the AdaSqrt optimizer with the given function and parameters.
* The defaults here are not necessarily good for the given problem, so it is
* suggested that the values used be tailored to the task at hand. The
* maximum number of iterations refers to the maximum number of points that
* are processed (i.e., one iteration equals one point; one iteration does not
* equal one pass over the dataset).
*
* @param stepSize Step size for each iteration.
* @param batchSize Number of points to process in one step.
* @param epsilon Value used to initialise the squared gradient parameter.
* @param maxIterations Maximum number of iterations allowed (0 means no
* limit).
* @param tolerance Maximum absolute tolerance to terminate algorithm.
* @param shuffle If true, the function order is shuffled; otherwise, each
* function is visited in linear order.
* @param resetPolicy If true, parameters are reset before every Optimize
* call; otherwise, their values are retained.
* @param exactObjective Calculate the exact objective (Default: estimate the
* final objective obtained on the last pass over the data).
*/
AdaSqrt(const double stepSize = 0.01,
const size_t batchSize = 32,
const double epsilon = 1e-8,
const size_t maxIterations = 100000,
const double tolerance = 1e-5,
const bool shuffle = true,
const bool resetPolicy = true,
const bool exactObjective = false);
/**
* Optimize the given function using AdaSqrt. The given starting point will
* be modified to store the finishing point of the algorithm, and the final
* objective value is returned.
*
* @tparam SeparableFunctionType Type of the function to be optimized.
* @tparam MatType Type of matrix to optimize with.
* @tparam GradType Type of matrix to use to represent function gradients.
* @tparam CallbackTypes Types of callback functions.
* @param function Function to optimize.
* @param iterate Starting point (will be modified).
* @param callbacks Callback functions.
* @return Objective value of the final point.
*/
template<typename SeparableFunctionType,
typename MatType,
typename GradType,
typename... CallbackTypes>
typename std::enable_if<IsArmaType<GradType>::value,
typename MatType::elem_type>::type
Optimize(SeparableFunctionType& function,
MatType& iterate,
CallbackTypes&&... callbacks)
{
return optimizer.Optimize<SeparableFunctionType, MatType, GradType,
CallbackTypes...>(function, iterate,
std::forward<CallbackTypes>(callbacks)...);
}
//! Forward the MatType as GradType.
template<typename SeparableFunctionType,
typename MatType,
typename... CallbackTypes>
typename MatType::elem_type Optimize(SeparableFunctionType& function,
MatType& iterate,
CallbackTypes&&... callbacks)
{
return Optimize<SeparableFunctionType, MatType, MatType,
CallbackTypes...>(function, iterate,
std::forward<CallbackTypes>(callbacks)...);
}
//! Get the step size.
double StepSize() const { return optimizer.StepSize(); }
//! Modify the step size.
double& StepSize() { return optimizer.StepSize(); }
//! Get the batch size.
size_t BatchSize() const { return optimizer.BatchSize(); }
//! Modify the batch size.
size_t& BatchSize() { return optimizer.BatchSize(); }
//! Get the value used to initialise the squared gradient parameter.
double Epsilon() const { return optimizer.UpdatePolicy().Epsilon(); }
//! Modify the value used to initialise the squared gradient parameter.
double& Epsilon() { return optimizer.UpdatePolicy().Epsilon(); }
//! Get the maximum number of iterations (0 indicates no limit).
size_t MaxIterations() const { return optimizer.MaxIterations(); }
//! Modify the maximum number of iterations (0 indicates no limit).
size_t& MaxIterations() { return optimizer.MaxIterations(); }
//! Get the tolerance for termination.
double Tolerance() const { return optimizer.Tolerance(); }
//! Modify the tolerance for termination.
double& Tolerance() { return optimizer.Tolerance(); }
//! Get whether or not the individual functions are shuffled.
bool Shuffle() const { return optimizer.Shuffle(); }
//! Modify whether or not the individual functions are shuffled.
bool& Shuffle() { return optimizer.Shuffle(); }
//! Get whether or not the actual objective is calculated.
bool ExactObjective() const { return optimizer.ExactObjective(); }
//! Modify whether or not the actual objective is calculated.
bool& ExactObjective() { return optimizer.ExactObjective(); }
//! Get whether or not the update policy parameters
//! are reset before Optimize call.
bool ResetPolicy() const { return optimizer.ResetPolicy(); }
//! Modify whether or not the update policy parameters
//! are reset before Optimize call.
bool& ResetPolicy() { return optimizer.ResetPolicy(); }
private:
//! The Stochastic Gradient Descent object with AdaSqrt policy.
SGD<AdaSqrtUpdate> optimizer;
};
} // namespace ens
// Include implementation.
#include "ada_sqrt_impl.hpp"
#endif
@@ -0,0 +1,38 @@
/**
* @file ada_sqrt_impl.hpp
* @author Marcus Edel
*
* Implementation of AdaSqrt optimizer.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_ADA_SQRT_ADA_SQRT_IMPL_HPP
#define ENSMALLEN_ADA_SQRT_ADA_SQRT_IMPL_HPP
namespace ens {
inline AdaSqrt::AdaSqrt(const double stepSize,
const size_t batchSize,
const double epsilon,
const size_t maxIterations,
const double tolerance,
const bool shuffle,
const bool resetPolicy,
const bool exactObjective) :
optimizer(stepSize,
batchSize,
maxIterations,
tolerance,
shuffle,
AdaSqrtUpdate(epsilon),
NoDecay(),
resetPolicy,
exactObjective)
{ /* Nothing to do. */ }
} // namespace ens
#endif
@@ -0,0 +1,118 @@
/**
* @file ada_sqrt_update.hpp
* @author Marcus Edel
*
* AdaSqrt update for Stochastic Gradient Descent.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_ADA_SQRT_ADA_SQRT_UPDATE_HPP
#define ENSMALLEN_ADA_SQRT_ADA_SQRT_UPDATE_HPP
namespace ens {
/**
* Implementation of the AdaSqrt update policy. AdaSqrt update policy chooses
* learning rate dynamically by adapting to the data and iteration.
*
* For more information, see the following.
*
* @code
* @misc{hu2019secondorder,
* title = {Second-order Information in First-order Optimization Methods},
* author = {Yuzheng Hu and Licong Lin and Shange Tang},
* year = {2019},
* eprint = {1912.09926},
* }
* @endcode
*
*/
class AdaSqrtUpdate
{
public:
/**
* Construct the AdaSqrt update policy with given epsilon parameter.
*
* @param epsilon The epsilon value used to initialise the squared gradient
* parameter.
*/
AdaSqrtUpdate(const double epsilon = 1e-8) : epsilon(epsilon)
{
// Nothing to do.
}
//! Get the value used to initialise the squared gradient parameter.
double Epsilon() const { return epsilon; }
//! Modify the value used to initialise the squared gradient parameter.
double& Epsilon() { return epsilon; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
* instantiated at the start of the optimization, and holds parameters
* specific to an individual optimization.
*/
template<typename MatType, typename GradType>
class Policy
{
public:
/**
* This constructor is called by the SGD optimizer before the start of the
* iteration update process. In AdaSqrt update policy, squared gradient
* matrix is initialized to the zeros matrix with the same size as gradient
* matrix (see ens::SGD<>).
*
* @param parent Instantiated parent class.
* @param rows Number of rows in the gradient matrix.
* @param cols Number of columns in the gradient matrix.
*/
Policy(AdaSqrtUpdate& parent, const size_t rows, const size_t cols) :
parent(parent),
squaredGradient(rows, cols),
iteration(0)
{
// Initialize an empty matrix for sum of squares of parameter gradient.
squaredGradient.zeros();
}
/**
* Update step for SGD. The AdaSqrt update adapts the learning rate by
* performing larger updates for more sparse parameters and smaller updates
* for less sparse parameters.
*
* @param iterate Parameters that minimize the function.
* @param stepSize Step size to be used for the given iteration.
* @param gradient The gradient matrix.
*/
void Update(MatType& iterate,
const double stepSize,
const GradType& gradient)
{
++iteration;
squaredGradient += arma::square(gradient);
iterate -= stepSize * std::sqrt(iteration) * gradient /
(squaredGradient + parent.epsilon);
}
private:
// Instantiated parent class.
AdaSqrtUpdate& parent;
// The squared gradient matrix.
GradType squaredGradient;
// The number of iterations.
size_t iteration;
};
private:
// The epsilon value used to initialise the squared gradient parameter.
double epsilon;
};
} // namespace ens
#endif
+9 -16
View File
@@ -52,8 +52,7 @@ class AdamUpdate
const double beta2 = 0.999) :
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
iteration(0)
beta2(beta2)
{
// Nothing to do.
}
@@ -73,11 +72,6 @@ class AdamUpdate
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
@@ -97,7 +91,8 @@ class AdamUpdate
* @param cols Number of columns in the gradient matrix.
*/
Policy(AdamUpdate& parent, const size_t rows, const size_t cols) :
parent(parent)
parent(parent),
iteration(0)
{
m.zeros(rows, cols);
v.zeros(rows, cols);
@@ -115,7 +110,7 @@ class AdamUpdate
const GradType& gradient)
{
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
// And update the iterate.
m *= parent.beta1;
@@ -124,10 +119,8 @@ class AdamUpdate
v *= parent.beta2;
v += (1 - parent.beta2) * (gradient % gradient);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1,
parent.iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2,
parent.iteration);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
/**
* It should be noted that the term, m / (arma::sqrt(v) + eps), in the
@@ -147,6 +140,9 @@ class AdamUpdate
// The exponential moving average of squared gradient values.
GradType v;
// The number of iterations.
size_t iteration;
};
private:
@@ -158,9 +154,6 @@ class AdamUpdate
// The second moment coefficient.
double beta2;
// The number of iterations.
size_t iteration;
};
} // namespace ens
+7 -14
View File
@@ -54,8 +54,7 @@ class AdaMaxUpdate
const double beta2 = 0.999) :
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
iteration(0)
beta2(beta2)
{
// Nothing to do.
}
@@ -75,11 +74,6 @@ class AdaMaxUpdate
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
@@ -99,7 +93,8 @@ class AdaMaxUpdate
* @param cols Number of columns in the gradient matrix.
*/
Policy(AdaMaxUpdate& parent, const size_t rows, const size_t cols) :
parent(parent)
parent(parent),
iteration(0)
{
m.zeros(rows, cols);
u.zeros(rows, cols);
@@ -117,7 +112,7 @@ class AdaMaxUpdate
const GradType& gradient)
{
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
// And update the iterate.
m *= parent.beta1;
@@ -127,8 +122,7 @@ class AdaMaxUpdate
u *= parent.beta2;
u = arma::max(u, arma::abs(gradient));
const double biasCorrection1 = 1.0 - std::pow(parent.beta1,
parent.iteration);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
if (biasCorrection1 != 0)
iterate -= (stepSize / biasCorrection1 * m / (u + parent.epsilon));
@@ -141,6 +135,8 @@ class AdaMaxUpdate
GradType m;
// The exponentially weighted infinity norm.
GradType u;
// The number of iterations.
size_t iteration;
};
private:
@@ -152,9 +148,6 @@ class AdaMaxUpdate
// The second moment coefficient.
double beta2;
// The number of iterations.
size_t iteration;
};
} // namespace ens
+9 -16
View File
@@ -47,8 +47,7 @@ class AMSGradUpdate
const double beta2 = 0.999) :
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
iteration(0)
beta2(beta2)
{
// Nothing to do.
}
@@ -68,11 +67,6 @@ class AMSGradUpdate
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
@@ -92,7 +86,8 @@ class AMSGradUpdate
* @param cols Number of columns in the gradient matrix.
*/
Policy(AMSGradUpdate& parent, const size_t rows, const size_t cols) :
parent(parent)
parent(parent),
iteration(0)
{
m.zeros(rows, cols);
v.zeros(rows, cols);
@@ -111,7 +106,7 @@ class AMSGradUpdate
const GradType& gradient)
{
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
// And update the iterate.
m *= parent.beta1;
@@ -120,10 +115,8 @@ class AMSGradUpdate
v *= parent.beta2;
v += (1 - parent.beta2) * (gradient % gradient);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1,
parent.iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2,
parent.iteration);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
// Element wise maximum of past and present squared gradients.
vImproved = arma::max(vImproved, v);
@@ -144,6 +137,9 @@ class AMSGradUpdate
// The optimal squared gradient value.
GradType vImproved;
// The number of iterations.
size_t iteration;
};
private:
@@ -155,9 +151,6 @@ class AMSGradUpdate
// The second moment coefficient.
double beta2;
// The number of iterations.
size_t iteration;
};
} // namespace ens
+10 -18
View File
@@ -50,8 +50,7 @@ class NadamUpdate
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
scheduleDecay(scheduleDecay),
iteration(0)
scheduleDecay(scheduleDecay)
{
// Nothing to do.
}
@@ -76,11 +75,6 @@ class NadamUpdate
//! Modify the decay parameter for decay coefficients
double& ScheduleDecay() { return scheduleDecay; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
@@ -101,7 +95,8 @@ class NadamUpdate
*/
Policy(NadamUpdate& parent, const size_t rows, const size_t cols) :
parent(parent),
cumBeta1(1)
cumBeta1(1),
iteration(0)
{
m.zeros(rows, cols);
v.zeros(rows, cols);
@@ -119,7 +114,7 @@ class NadamUpdate
const GradType& gradient)
{
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
// And update the iterate.
m *= parent.beta1;
@@ -129,18 +124,15 @@ class NadamUpdate
v += (1 - parent.beta2) * gradient % gradient;
double beta1T = parent.beta1 * (1 - (0.5 *
std::pow(0.96, parent.iteration * parent.scheduleDecay)));
std::pow(0.96, iteration * parent.scheduleDecay)));
double beta1T1 = parent.beta1 * (1 - (0.5 *
std::pow(0.96, (parent.iteration + 1) * parent.scheduleDecay)));
std::pow(0.96, (iteration + 1) * parent.scheduleDecay)));
cumBeta1 *= beta1T;
const double biasCorrection1 = 1.0 - cumBeta1;
const double biasCorrection2 = 1.0 - std::pow(parent.beta2,
parent.iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
const double biasCorrection3 = 1.0 - (cumBeta1 * beta1T1);
/* Note :- arma::sqrt(v) + epsilon * sqrt(biasCorrection2) is approximated
@@ -163,6 +155,9 @@ class NadamUpdate
// The cumulative product of decay coefficients.
double cumBeta1;
// The number of iterations.
size_t iteration;
};
private:
@@ -177,9 +172,6 @@ class NadamUpdate
// The decay parameter for decay coefficients.
double scheduleDecay;
// The number of iterations.
size_t iteration;
};
} // namespace ens
+9 -14
View File
@@ -50,8 +50,7 @@ class NadaMaxUpdate
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
scheduleDecay(scheduleDecay),
iteration(0)
scheduleDecay(scheduleDecay)
{
// Nothing to do.
}
@@ -76,11 +75,6 @@ class NadaMaxUpdate
//! Modify the decay parameter for decay coefficients
double& ScheduleDecay() { return scheduleDecay; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
@@ -101,7 +95,8 @@ class NadaMaxUpdate
*/
Policy(NadaMaxUpdate& parent, const size_t rows, const size_t cols) :
parent(parent),
cumBeta1(1)
cumBeta1(1),
iteration(0)
{
m.zeros(rows, cols);
u.zeros(rows, cols);
@@ -119,7 +114,7 @@ class NadaMaxUpdate
const GradType& gradient)
{
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
// And update the iterate.
m *= parent.beta1;
@@ -128,10 +123,10 @@ class NadaMaxUpdate
u = arma::max(u * parent.beta2, arma::abs(gradient));
double beta1T = parent.beta1 * (1 - (0.5 *
std::pow(0.96, parent.iteration * parent.scheduleDecay)));
std::pow(0.96, iteration * parent.scheduleDecay)));
double beta1T1 = parent.beta1 * (1 - (0.5 *
std::pow(0.96, (parent.iteration + 1) * parent.scheduleDecay)));
std::pow(0.96, (iteration + 1) * parent.scheduleDecay)));
cumBeta1 *= beta1T;
@@ -158,6 +153,9 @@ class NadaMaxUpdate
// The cumulative product of decay coefficients.
double cumBeta1;
// The number of iterations.
size_t iteration;
};
private:
@@ -172,9 +170,6 @@ class NadaMaxUpdate
// The decay parameter for decay coefficients.
double scheduleDecay;
// The number of iterations.
size_t iteration;
};
} // namespace ens
@@ -51,8 +51,7 @@ class OptimisticAdamUpdate
const double beta2 = 0.999) :
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
iteration(0)
beta2(beta2)
{
// Nothing to do.
}
@@ -72,11 +71,6 @@ class OptimisticAdamUpdate
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
@@ -96,7 +90,8 @@ class OptimisticAdamUpdate
* @param cols Number of columns in the gradient matrix.
*/
Policy(OptimisticAdamUpdate& parent, const size_t rows, const size_t cols) :
parent(parent)
parent(parent),
iteration(0)
{
m.zeros(rows, cols);
v.zeros(rows, cols);
@@ -115,7 +110,7 @@ class OptimisticAdamUpdate
const GradType& gradient)
{
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
// And update the iterate.
m *= parent.beta1;
@@ -124,13 +119,10 @@ class OptimisticAdamUpdate
v *= parent.beta2;
v += (1 - parent.beta2) * arma::square(gradient);
GradType mCorrected = m / (1.0 - std::pow(parent.beta1,
parent.iteration));
GradType vCorrected = v / (1.0 - std::pow(parent.beta2,
parent.iteration));
GradType mCorrected = m / (1.0 - std::pow(parent.beta1, iteration));
GradType vCorrected = v / (1.0 - std::pow(parent.beta2, iteration));
GradType update = mCorrected /
(arma::sqrt(vCorrected) + parent.epsilon);
GradType update = mCorrected / (arma::sqrt(vCorrected) + parent.epsilon);
iterate -= (2 * stepSize * update - stepSize * g);
@@ -149,6 +141,9 @@ class OptimisticAdamUpdate
// The previous update.
GradType g;
// The number of iterations.
size_t iteration;
};
private:
@@ -160,9 +155,6 @@ class OptimisticAdamUpdate
// The second moment coefficient.
double beta2;
// The number of iterations.
size_t iteration;
};
} // namespace ens
+107 -1
View File
@@ -744,6 +744,79 @@ class Callback
MatType& /* coordinates */)
{ return false; }
/**
* Invoke the GenerationalStepTaken() callback if it exists.
* Specialization for MultiObjective case.
*
* @param callback The callback to call.
* @param optimizer The optimizer used to update the function.
* @param function Function to optimize.
* @param coordinates Starting point.
* @param objectives The set of calculated objectives so far.
* @param frontIndices The indices of the members belonging to Pareto Front.
*/
template<typename CallbackType,
typename OptimizerType,
typename FunctionType,
typename MatType,
typename ObjectivesVecType,
typename IndicesType>
static typename std::enable_if<
callbacks::traits::HasGenerationalStepTakenSignature<
CallbackType, OptimizerType, FunctionType, MatType, ObjectivesVecType,
IndicesType>::hasBool, bool>::type
GenerationalStepTakenFunction(CallbackType& callback,
OptimizerType& optimizer,
FunctionType& function,
MatType& coordinates,
ObjectivesVecType& objectives,
IndicesType& frontIndices)
{
return const_cast<CallbackType&>(callback).GenerationalStepTaken(
optimizer, function, coordinates, objectives, frontIndices);
}
template<typename CallbackType,
typename OptimizerType,
typename FunctionType,
typename MatType,
typename ObjectivesVecType,
typename IndicesType>
static typename std::enable_if<
callbacks::traits::HasGenerationalStepTakenSignature<
CallbackType, OptimizerType, FunctionType, MatType, ObjectivesVecType,
IndicesType>::hasVoid, bool>::type
GenerationalStepTakenFunction(CallbackType& callback,
OptimizerType& optimizer,
FunctionType& function,
MatType& coordinates,
ObjectivesVecType& objectives,
IndicesType& frontIndices)
{
const_cast<CallbackType&>(callback).GenerationalStepTaken(
optimizer, function, coordinates, objectives, frontIndices);
return false;
}
template<typename CallbackType,
typename OptimizerType,
typename FunctionType,
typename MatType,
typename ObjectivesVecType,
typename IndicesType>
static typename std::enable_if<
callbacks::traits::HasGenerationalStepTakenSignature<
CallbackType, OptimizerType, FunctionType, MatType, ObjectivesVecType,
IndicesType>::hasNone, bool>::type
GenerationalStepTakenFunction(CallbackType& /* callback */,
OptimizerType& /* optimizer */,
FunctionType& /* function */,
MatType& /* coordinates */,
ObjectivesVecType& /* objectives */,
IndicesType& /* frontIndices */)
{ return false; }
/**
* Iterate over the callbacks and invoke the StepTaken() callback if it
* exists.
@@ -769,8 +842,41 @@ class Callback
function, coordinates)... };
return result;
}
};
/**
* Iterate over the callbacks and invoke the GenerationalStepTaken() callback if it
* exists.
*
* Specialization for MultiObjective case.
*
* @param optimizer The optimizer used to update the function.
* @param function Function to optimize.
* @param coordinates Starting point.
* @param objectives The set of calculated objectives so far.
* @param frontIndices The indices of the members belonging to Pareto Front.
* @param callbacks The callbacks container.
*/
template<typename OptimizerType,
typename FunctionType,
typename ObjectivesVecType,
typename IndicesType,
typename MatType,
typename ...CallbackTypes>
static bool GenerationalStepTaken(OptimizerType& optimizer,
FunctionType& functions,
MatType& coordinates,
ObjectivesVecType& objectives,
IndicesType& frontIndices,
CallbackTypes&... callbacks)
{
// This will return immediately once a callback returns true.
bool result = false;
(void)std::initializer_list<bool>{ result =
result || Callback::GenerationalStepTakenFunction(callbacks, optimizer,
functions, coordinates, objectives, frontIndices)... };
return result;
}
};
} // namespace ens
#endif
@@ -32,7 +32,7 @@ class EarlyStopAtMinLossType
* @param patienceIn The number of epochs to wait after the minimum loss has
* been reached or no improvement has been made (Default: 10).
*/
EarlyStopAtMinLossType<MatType>(const size_t patienceIn = 10) :
EarlyStopAtMinLossType(const size_t patienceIn = 10) :
callbackUsed(false),
patience(patienceIn),
bestObjective(std::numeric_limits<double>::max()),
@@ -47,7 +47,7 @@ class EarlyStopAtMinLossType
* @param patienceIn The number of epochs to wait after the minimum loss has
* been reached or no improvement has been made (Default: 10).
*/
EarlyStopAtMinLossType<MatType>(
EarlyStopAtMinLossType(
std::function<double(const MatType&)> func,
const size_t patienceIn = 10)
: callbackUsed(true),
@@ -0,0 +1,60 @@
/**
* @file grad_clip_by_norm.hpp
* @author Marcus Edel
*
* Clip the gradients by multiplying the unit vector of the gradients with the
* threshold.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_CALLBACKS_GRAD_CLIP_BY_NORM_HPP
#define ENSMALLEN_CALLBACKS_GRAD_CLIP_BY_NORM_HPP
namespace ens {
/**
* Clip the gradients by multiplying the unit vector of the gradients with the
* threshold.
*/
class GradClipByNorm
{
public:
/**
* Set up the gradient clip by norm callback class with the maximum clipping
* value.
*
* @param maxNorm The maximum clipping value.
*/
GradClipByNorm(const double maxNorm) : maxNorm(maxNorm)
{ /* Nothing to do here. */ }
/**
* Callback function called at any call to Gradient().
*
* @param optimizer The optimizer used to update the function.
* @param function Function to optimize.
* @param coordinates Starting point.
* @param gradient Matrix that holds the gradient.
*/
template<typename OptimizerType, typename FunctionType, typename MatType>
void Gradient(OptimizerType& /* optimizer */,
FunctionType& /* function */,
const MatType& /* coordinates */,
MatType& gradient)
{
const double gradientNorm = arma::norm(gradient);
if (gradientNorm > maxNorm)
gradient = maxNorm * gradient / gradientNorm;
}
private:
//! The maximum clipping value for gradient clipping.
const double maxNorm;
};
} // namespace ens
#endif
@@ -0,0 +1,60 @@
/**
* @file grad_clip_by_value.hpp
* @author Marcus Edel
*
* Clips the gradient to a specified min and max.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_CALLBACKS_GRAD_CLIP_BY_VALUE_HPP
#define ENSMALLEN_CALLBACKS_GRAD_CLIP_BY_VALUE_HPP
namespace ens {
/**
* Clip the gradient to a specified min and max.
*/
class GradClipByValue
{
public:
/**
* Set up the gradient clip by value callback class with the min and max
* value.
*
* @param min The minimum value to clip to.
* @param max The maximum value to clip to.
*/
GradClipByValue(const double min, const double max) : lower(min), upper(max)
{ /* Nothing to do here. */ }
/**
* Callback function called at any call to Gradient().
*
* @param optimizer The optimizer used to update the function.
* @param function Function to optimize.
* @param coordinates Starting point.
* @param gradient Matrix that holds the gradient.
*/
template<typename OptimizerType, typename FunctionType, typename MatType>
void Gradient(OptimizerType& /* optimizer */,
FunctionType& /* function */,
const MatType& /* coordinates */,
MatType& gradient)
{
gradient = arma::clamp(gradient, lower, upper);
}
private:
//! The minimum value to clip to.
const double lower;
//! The maximum value to clip to.
const double upper;
};
} // namespace ens
#endif
@@ -216,10 +216,10 @@ class ProgressBar
output << ".";
}
}
const size_t stepTime = epochTimer.toc() / (double) epochSize * 1000;
output << "] " << progress << "% - " << (size_t) epochTimer.toc() % 60
<< "s " << stepTime << "ms/step " << "- loss: " << objective << "\n";
const double epochTimerElapsed = epochTimer.toc();
const size_t stepTime = epochTimerElapsed / (double) epochSize * 1000;
output << "] " << progress << "% - " << epochTimerElapsed
<< "s/epoch; " << stepTime << "ms/step; loss: " << objective << "\n";
output.flush();
}
@@ -0,0 +1,85 @@
/**
* @file query_front.hpp
* @author Nanubala Gnana Sai
*
* Implementation of the query front callback function.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_CALLBACKS_QUERY_FRONT_HPP
#define ENSMALLEN_CALLBACKS_QUERY_FRONT_HPP
namespace ens {
/**
* Query the current Pareto Front after every GenerationalStepTaken callback function.
*/
class QueryFront
{
public:
/**
* Set up the query front callback class with the specified inputs.
*
* @param queryRate The frequency at which the Pareto Front is queried.
* @param paretoFrontArray A reference to a vector of cube to store the queried fronts.
*/
QueryFront(const size_t queryRate, std::vector<arma::cube>& paretoFrontArray) :
queryRate(queryRate),
paretoFrontArray(paretoFrontArray),
genCounter(0)
{ /* Nothing to do here */ }
/**
* Callback function called at the end of a single generational run.
*
* @param optimizer The optimizer used to update the function.
* @param function Function to optimize.
* @param coordinates Starting point.
* @param objectives The set of calculated objectives so far.
* @param frontIndices The indices of the members belonging to Pareto Front.
*/
template<typename OptimizerType,
typename FunctionType,
typename MatType,
typename ObjectivesVecType,
typename IndicesType>
void GenerationalStepTaken(OptimizerType& opt,
FunctionType& /* function */,
const MatType& /* coordinates */,
const ObjectivesVecType& objectives,
const IndicesType& frontIndices)
{
arma::cube currentParetoFront{};
if (genCounter % queryRate == 0)
{
currentParetoFront.resize(objectives[0].n_rows, objectives[0].n_cols,
frontIndices[0].size());
for (size_t solutionIdx = 0; solutionIdx < frontIndices[0].size(); ++solutionIdx)
{
currentParetoFront.slice(solutionIdx) =
arma::conv_to<arma::mat>::from(objectives[frontIndices[0][solutionIdx]]);
}
paretoFrontArray.emplace_back(std::move(currentParetoFront));
}
++genCounter;
}
private:
//! The rate of query.
size_t queryRate;
//! A reference to the array of pareto fronts.
std::vector<arma::cube>& paretoFrontArray;
//! A counter for the current generation.
size_t genCounter;
};
} // namespace ens
#endif
+115 -6
View File
@@ -37,6 +37,8 @@ ENS_HAS_EXACT_METHOD_FORM(BeginEpoch, HasBeginEpoch)
ENS_HAS_EXACT_METHOD_FORM(EndEpoch, HasEndEpoch)
//! Detect an StepTaken() method.
ENS_HAS_EXACT_METHOD_FORM(StepTaken, HasStepTaken)
//! Detect an GenerationalStepTaken() method.
ENS_HAS_EXACT_METHOD_FORM(GenerationalStepTaken, HasGenerationalStepTaken)
template<typename OptimizerType,
typename FunctionType,
@@ -86,6 +88,15 @@ struct TypedForms
const MatType&,
const MatType&);
//! This is the form of a bool Gradient() callback method where the gradient
//! is modifiable.
template<typename CallbackType>
using GradientBoolModifiableForm =
void(CallbackType::*)(OptimizerType&,
FunctionType&,
const MatType&,
MatType&);
//! This is the form of a void Gradient() callback method.
template<typename CallbackType>
using GradientVoidForm =
@@ -94,6 +105,15 @@ struct TypedForms
const MatType&,
const MatType&);
//! This is the form of a void Gradient() callback method where the gradient
//! is modifiable.
template<typename CallbackType>
using GradientVoidModifiableForm =
void(CallbackType::*)(OptimizerType&,
FunctionType&,
const MatType&,
MatType&);
//! This is the form of a bool GradientConstraint() callback method.
template<typename CallbackType>
using GradientConstraintBoolForm =
@@ -103,6 +123,16 @@ struct TypedForms
const size_t,
const MatType&);
//! This is the form of a bool GradientConstraint() callback method where the
//! gradient is modifiable.
template<typename CallbackType>
using GradientConstraintBoolModifiableForm =
void(CallbackType::*)(OptimizerType&,
FunctionType&,
const MatType&,
const size_t,
MatType&);
//! This is the form of a void GradientConstraint() callback method.
template<typename CallbackType>
using GradientConstraintVoidForm =
@@ -112,6 +142,16 @@ struct TypedForms
const size_t,
const MatType&);
//! This is the form of a void GradientConstraint() callback method where the
//! gradient is modifiable.
template<typename CallbackType>
using GradientConstraintVoidModifiableForm =
void(CallbackType::*)(OptimizerType&,
FunctionType&,
const MatType&,
const size_t,
MatType&);
//! This is the form of a bool BeginOptimization() callback method.
template<typename CallbackType>
using BeginOptimizationBoolForm =
@@ -228,9 +268,9 @@ struct HasEvaluateSignature
{
const static bool value =
HasEvaluate<CallbackType, TypedForms<OptimizerType,
FunctionType, MatType>::template EvaluateBoolForm>::value ||
FunctionType, MatType>::template EvaluateBoolForm>::value ||
HasEvaluate<CallbackType, TypedForms<OptimizerType,
FunctionType, MatType>::template EvaluateVoidForm>::value;
FunctionType, MatType>::template EvaluateVoidForm>::value;
};
//! Utility struct, check if either void EvaluateConstraint() or
@@ -243,9 +283,9 @@ struct HasEvaluateConstraintSignature
{
const static bool value =
HasEvaluateConstraint<CallbackType, TypedForms<OptimizerType,
FunctionType, MatType>::template EvaluateConstraintBoolForm>::value ||
FunctionType, MatType>::template EvaluateConstraintBoolForm>::value ||
HasEvaluateConstraint<CallbackType, TypedForms<OptimizerType,
FunctionType, MatType>::template EvaluateConstraintVoidForm>::value;
FunctionType, MatType>::template EvaluateConstraintVoidForm>::value;
};
//! Utility struct, check if either void Gradient() or bool Gradient()
@@ -259,9 +299,15 @@ struct HasGradientSignature
{
const static bool value =
HasGradient<CallbackType, TypedForms<OptimizerType,
FunctionType, MatType, Gradient>::template GradientBoolForm>::value ||
FunctionType, MatType, Gradient>::template GradientBoolForm>::value ||
HasGradient<CallbackType, TypedForms<OptimizerType,
FunctionType, MatType, Gradient>::template GradientVoidForm>::value;
FunctionType, MatType,
Gradient>::template GradientBoolModifiableForm>::value ||
HasGradient<CallbackType, TypedForms<OptimizerType,
FunctionType, MatType, Gradient>::template GradientVoidForm>::value ||
HasGradient<CallbackType, TypedForms<OptimizerType,
FunctionType, MatType,
Gradient>::template GradientVoidModifiableForm>::value;
};
//! Utility struct, check if either void GradientConstraint() or
@@ -365,6 +411,69 @@ struct HasStepTakenSignature
FunctionType, MatType>::template StepTakenVoidForm>::value;
};
//! A utility struct for Typed Forms required in
//! callbacks for MultiObjective Optimizers.
template<typename OptimizerType,
typename FunctionType,
typename MatType,
typename ObjectivesVecType,
typename IndicesType,
typename GradType = MatType>
struct MOOTypedForms
{
//! This is the form of a bool GenerationalStepTaken() for MOO callback method.
template<typename CallbackType>
using GenerationalStepTakenBoolForm =
bool(CallbackType::*)(OptimizerType&,
FunctionType&,
const MatType&,
const ObjectivesVecType&,
const IndicesType&);
//! This is the form of a void StepTaken() for MOO callback method.
template<typename CallbackType>
using GenerationalStepTakenVoidForm =
void(CallbackType::*)(OptimizerType&,
FunctionType&,
const MatType&,
const ObjectivesVecType&,
const IndicesType&);
};
//! Utility struct, check if either void StepTaken() or bool StepTaken() exists.
//! Specialization for Multiobjective case.
template<typename CallbackType,
typename OptimizerType,
typename FunctionType,
typename ObjectivesVecType,
typename IndicesType,
typename MatType>
struct HasGenerationalStepTakenSignature
{
const static bool hasBool =
HasGenerationalStepTaken<CallbackType, MOOTypedForms<OptimizerType,
FunctionType, MatType, ObjectivesVecType, IndicesType>::
template GenerationalStepTakenBoolForm>::value &&
!HasGenerationalStepTaken<CallbackType, MOOTypedForms<OptimizerType,
FunctionType, MatType, ObjectivesVecType, IndicesType>::
template GenerationalStepTakenVoidForm>::value;
const static bool hasVoid =
!HasGenerationalStepTaken<CallbackType, MOOTypedForms<OptimizerType,
FunctionType, MatType, ObjectivesVecType, IndicesType>::
template GenerationalStepTakenBoolForm>::value &&
HasGenerationalStepTaken<CallbackType, MOOTypedForms<OptimizerType,
FunctionType, MatType, ObjectivesVecType, IndicesType>::
template GenerationalStepTakenVoidForm>::value;
const static bool hasNone =
!HasGenerationalStepTaken<CallbackType, MOOTypedForms<OptimizerType,
FunctionType, MatType, ObjectivesVecType, IndicesType>::
template GenerationalStepTakenBoolForm>::value &&
!HasGenerationalStepTaken<CallbackType, MOOTypedForms<OptimizerType,
FunctionType, MatType, ObjectivesVecType, IndicesType>::
template GenerationalStepTakenVoidForm>::value;
};
} // namespace traits
} // namespace callbacks
} // namespace ens
+2 -2
View File
@@ -97,9 +97,9 @@ class CMAES
MatType& iterate,
CallbackTypes&&... callbacks);
//! Get the step size.
//! Get the population size.
size_t PopulationSize() const { return lambda; }
//! Modify the step size.
//! Modify the population size.
size_t& PopulationSize() { return lambda; }
//! Get the lower bound of decision variables.
+1 -1
View File
@@ -159,7 +159,7 @@ typename MatType::elem_type CMAES<SelectionPolicyType>::Optimize(
// add a small value and try again.
BaseMatType covLower;
while (!arma::chol(covLower, C[idx0], "lower"))
C[idx0].diag() += 1e-16;
C[idx0].diag() += std::numeric_limits<ElemType>::epsilon();
for (size_t j = 0; j < lambda; ++j)
{
@@ -0,0 +1,207 @@
/**
* @file demon_adam.hpp
* @author Marcus Edel
*
* Definition of DemonAdam.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_DEMON_ADAM_DEMON_ADAM_HPP
#define ENSMALLEN_DEMON_ADAM_DEMON_ADAM_HPP
#include "../sgd/sgd.hpp"
#include "../adam/adam_update.hpp"
#include "../adam/adamax_update.hpp"
#include "../adam/amsgrad_update.hpp"
#include "../adam/nadam_update.hpp"
#include "../adam/nadamax_update.hpp"
#include "../adam/optimisticadam_update.hpp"
#include "demon_adam_update.hpp"
namespace ens {
/**
* DemonAdam automatically decays momentum, motivated by decaying the total
* contribution of a gradient to all future updates.
*
* For more information, see the following.
*
* @code
* @misc{
* title = {Decaying momentum helps neural network training},
* author = {John Chen and Cameron Wolfe and Zhao Li
* and Anastasios Kyrillidis},
* url = {https://arxiv.org/abs/1910.04952}
* year = {2019}
* }
*
* DemonAdam can optimize differentiable separable functions. For more details,
* see the documentation on function types include with this distribution or on
* the ensmallen website.
*
* @tparam UpdateRule Adam optimizer update rule to be used.
*/
template<typename UpdateRule = AdamUpdate>
class DemonAdamType
{
public:
/**
* Construct the DemonAdam optimizer with the given function and parameters.
* The defaults here are not necessarily good for the given problem, so it is
* suggested that the values used be tailored to the task at hand. The
* maximum number of iterations refers to the maximum number of points that
* are processed (i.e., one iteration equals one point; one iteration does not
* equal one pass over the dataset).
*
* @param stepSize Step size for each iteration.
* @param batchSize Number of points to process in a single step.
* @param momentum The initial momentum coefficient.
* @param maxIterations Maximum number of iterations allowed (0 means no
* limit).
* @param beta1 Exponential decay rate for the first moment estimates.
* @param beta2 Exponential decay rate for the weighted infinity norm
* estimates.
* @param eps Value used to initialise the mean squared gradient parameter.
* @param tolerance Maximum absolute tolerance to terminate algorithm.
* @param shuffle If true, the function order is shuffled; otherwise, each
* function is visited in linear order.
* @param resetPolicy If true, parameters are reset before every Optimize
* call; otherwise, their values are retained.
* @param exactObjective Calculate the exact objective (Default: estimate the
* final objective obtained on the last pass over the data).
*/
DemonAdamType(const double stepSize = 0.001,
const size_t batchSize = 32,
const double momentum = 0.9,
const double beta1 = 0.9,
const double beta2 = 0.999,
const double eps = 1e-8,
const size_t maxIterations = 100000,
const double tolerance = 1e-5,
const bool shuffle = true,
const bool resetPolicy = true,
const bool exactObjective = false) :
optimizer(stepSize,
batchSize,
maxIterations,
tolerance,
shuffle,
DemonAdamUpdate<UpdateRule>(maxIterations * batchSize,
momentum, UpdateRule(eps, beta1, beta2)),
NoDecay(),
resetPolicy,
exactObjective)
{ /* Nothing to do here. */ }
/**
* Optimize the given function using DemonAdam. The given starting point will
* be modified to store the finishing point of the algorithm, and the final
* objective value is returned.
*
* @tparam SeparableFunctionType Type of the function to optimize.
* @tparam MatType Type of matrix to optimize with.
* @tparam GradType Type of matrix to use to represent function gradients.
* @tparam CallbackTypes Types of callback functions.
* @param function Function to optimize.
* @param iterate Starting point (will be modified).
* @param callbacks Callback functions.
* @return Objective value of the final point.
*/
template<typename SeparableFunctionType,
typename MatType,
typename GradType,
typename... CallbackTypes>
typename MatType::elem_type Optimize(SeparableFunctionType& function,
MatType& iterate,
CallbackTypes&&... callbacks)
{
return optimizer.template Optimize<
SeparableFunctionType, MatType, GradType, CallbackTypes...>(
function, iterate, std::forward<CallbackTypes>(callbacks)...);
}
//! Forward the MatType as GradType.
template<typename SeparableFunctionType,
typename MatType,
typename... CallbackTypes>
typename MatType::elem_type Optimize(SeparableFunctionType& function,
MatType& iterate,
CallbackTypes&&... callbacks)
{
return Optimize<SeparableFunctionType, MatType, MatType,
CallbackTypes...>(function, iterate,
std::forward<CallbackTypes>(callbacks)...);
}
//! Get the step size.
double StepSize() const { return optimizer.StepSize(); }
//! Modify the step size.
double& StepSize() { return optimizer.StepSize(); }
//! Get the batch size.
size_t BatchSize() const { return optimizer.BatchSize(); }
//! Modify the batch size.
size_t& BatchSize() { return optimizer.BatchSize(); }
//! Get the moment coefficient.
double Momentum() const { return optimizer.UpdatePolicy().Momentum(); }
//! Modify the moment coefficient.
double& Momentum() { return optimizer.UpdatePolicy().Momentum(); }
//! Get the momentum iteration number.
size_t MomentumIterations() const
{ return optimizer.UpdatePolicy().MomentumIterations(); }
//! Modify the momentum iteration number.
size_t& MomentumIterations()
{ return optimizer.UpdatePolicy().MomentumIterations(); }
//! Get the maximum number of iterations (0 indicates no limit).
size_t MaxIterations() const { return optimizer.MaxIterations(); }
//! Modify the maximum number of iterations (0 indicates no limit).
size_t& MaxIterations() { return optimizer.MaxIterations(); }
//! Get the tolerance for termination.
double Tolerance() const { return optimizer.Tolerance(); }
//! Modify the tolerance for termination.
double& Tolerance() { return optimizer.Tolerance(); }
//! Get whether or not the individual functions are shuffled.
bool Shuffle() const { return optimizer.Shuffle(); }
//! Modify whether or not the individual functions are shuffled.
bool& Shuffle() { return optimizer.Shuffle(); }
//! Get whether or not the actual objective is calculated.
bool ExactObjective() const { return optimizer.ExactObjective(); }
//! Modify whether or not the actual objective is calculated.
bool& ExactObjective() { return optimizer.ExactObjective(); }
//! Get whether or not the update policy parameters
//! are reset before Optimize call.
bool ResetPolicy() const { return optimizer.ResetPolicy(); }
//! Modify whether or not the update policy parameters
//! are reset before Optimize call.
bool& ResetPolicy() { return optimizer.ResetPolicy(); }
private:
//! The Stochastic Gradient Descent object with DemonAdam policy.
SGD<DemonAdamUpdate<UpdateRule>> optimizer;
};
using DemonAdam = DemonAdamType<AdamUpdate>;
using DemonAdaMax = DemonAdamType<AdaMaxUpdate>;
using DemonAMSGrad = DemonAdamType<AMSGradUpdate>;
using DemonNadam = DemonAdamType<NadamUpdate>;
using DemonNadaMax = DemonAdamType<NadaMaxUpdate>;
using DemonOptimisticAdam = DemonAdamType<OptimisticAdamUpdate>;
} // namespace ens
#endif
@@ -0,0 +1,169 @@
/**
* @file demon_sgd_update.hpp
* @author Marcus Edel
*
* Implementation of DemonAdam.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_DEMON_ADAM_DEMON_ADAM_UPDATE_HPP
#define ENSMALLEN_DEMON_ADAM_DEMON_ADAM_UPDATE_HPP
#include <assert.h>
namespace ens {
/**
* DemonAdam automatically decays momentum, motivated by decaying the total
* contribution of a gradient to all future updates.
*
* For more information, see the following.
*
* @code
* @misc{
* title = {Decaying momentum helps neural network training},
* author = {John Chen and Cameron Wolfe and Zhao Li
* and Anastasios Kyrillidis},
* url = {https://arxiv.org/abs/1910.04952}
* year = {2019}
* }
* @endcode
*
* @tparam UpdateRule DemonAdam optimizer update rule to be used.
*/
template<typename UpdateRule>
class DemonAdamUpdate
{
public:
/**
* Construct the DemonAdam update policy with the given parameters.
*
* @param momentumIterations The number of iterations before the momentum
* will decay to zero.
* @param momentum The initial momentum coefficient.
* @param adamUpdate Instantiated Adam update policy used to adjust the given
* parameters.
*/
DemonAdamUpdate(const size_t momentumIterations = 100,
const double momentum = 0.9,
const UpdateRule& adamUpdate = UpdateRule()) :
T(momentumIterations),
betaInit(momentum),
t(0),
adamUpdateInst(adamUpdate)
{
// Make sure the momentum iterations parameter is non-zero.
assert(momentumIterations != 0 && "The number of iterations before the "
"momentum will decay is zero, make sure the max iterations and "
"batch size parameter is set correctly. "
"Default: momentumIterations = maxIterations / batchSize.");
}
//! Get the momentum coefficient.
double Momentum() const { return betaInit; }
//! Modify the momentum coefficient.
double& Momentum() { return betaInit; }
//! Get the current iteration number.
size_t Iteration() const { return t; }
//! Modify the current iteration number.
size_t& Iteration() { return t; }
//! Get the momentum ion number.
size_t MomentumIterations() const { return T; }
//! Modify the momentum iteration number.
size_t& MomentumIterations() { return T; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
* instantiated at the start of the optimization, and holds parameters
* specific to an individual optimization.
*/
template<typename MatType, typename GradType>
class Policy
{
public:
// Convenient typedef.
typedef typename UpdateRule::template Policy<MatType, GradType>
InstUpdateRuleType;
/**
* This constructor is called by the SGD Optimize() method before the start
* of the iteration update process.
*
* @param parent Instantiated PadamUpdate parent object.
* @param rows Number of rows in the gradient matrix.
* @param cols Number of columns in the gradient matrix.
*/
Policy(DemonAdamUpdate& parent,
const size_t rows,
const size_t cols) :
parent(parent),
adamUpdate(new InstUpdateRuleType(parent.adamUpdateInst, rows, cols))
{ /* Nothing to do here */ }
/**
* Clean any memory associated with the Polciy object.
*/
~Policy()
{
delete adamUpdate;
}
/**
* Update step for DamonAdam.
*
* @param iterate Parameters that minimize the function.
* @param stepSize Step size to be used for the given iteration.
* @param gradient The gradient matrix.
*/
void Update(MatType& iterate,
const double stepSize,
const GradType& gradient)
{
double decayRate = 1;
if (parent.t > 0)
decayRate = 1.0 - (double) parent.t / (double) parent.T;
const double betaDecay = parent.betaInit * decayRate;
const double beta = betaDecay / ((1.0 - parent.betaInit) + betaDecay);
// Perform the update.
iterate *= beta;
// Apply the adam update.
adamUpdate->Update(iterate, stepSize, gradient);
// Increment the iteration counter variable.
++parent.t;
}
private:
//! Instantiated parent object.
DemonAdamUpdate<UpdateRule>& parent;
//! The update policy.
InstUpdateRuleType* adamUpdate;
};
private:
//! The number of momentum iterations.
size_t T;
//! Initial momentum coefficient.
double betaInit;
//! The number of iterations.
size_t t;
//! The adam update policy.
UpdateRule adamUpdateInst;
};
} // namespace ens
#endif
@@ -0,0 +1,178 @@
/**
* @file demon_sgd.hpp
* @author Marcus Edel
*
* Definition of DemonSGD.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_DEMON_SGD_DEMON_SGD_HPP
#define ENSMALLEN_DEMON_SGD_DEMON_SGD_HPP
#include "../sgd/sgd.hpp"
#include "demon_sgd_update.hpp"
namespace ens {
/**
* DemonSGD automatically decays momentum, motivated by decaying the total
* contribution of a gradient to all future updates.
*
* For more information, see the following.
*
* @code
* @misc{
* title = {Decaying momentum helps neural network training},
* author = {John Chen and Cameron Wolfe and Zhao Li
* and Anastasios Kyrillidis},
* url = {https://arxiv.org/abs/1910.04952}
* year = {2019}
* }
*
* DemonSGD can optimize differentiable separable functions. For more details,
* see the documentation on function types include with this distribution or on
* the ensmallen website.
*/
class DemonSGD
{
public:
/**
* Construct the DemonSGD optimizer with the given function and parameters.
* The defaults here are not necessarily good for the given problem, so it is
* suggested that the values used be tailored to the task at hand. The
* maximum number of iterations refers to the maximum number of points that
* are processed (i.e., one iteration equals one point; one iteration does not
* equal one pass over the dataset).
*
* @param stepSize Step size for each iteration.
* @param batchSize Number of points to process in a single step.
* @param momentum The initial momentum coefficient.
* @param maxIterations Maximum number of iterations allowed (0 means no
* limit).
* @param tolerance Maximum absolute tolerance to terminate algorithm.
* @param shuffle If true, the function order is shuffled; otherwise, each
* function is visited in linear order.
* @param resetPolicy If true, parameters are reset before every Optimize
* call; otherwise, their values are retained.
* @param exactObjective Calculate the exact objective (Default: estimate the
* final objective obtained on the last pass over the data).
*/
DemonSGD(const double stepSize = 0.001,
const size_t batchSize = 32,
const double momentum = 0.9,
const size_t maxIterations = 100000,
const double tolerance = 1e-5,
const bool shuffle = true,
const bool resetPolicy = true,
const bool exactObjective = false) :
optimizer(stepSize,
batchSize,
maxIterations,
tolerance,
shuffle,
DemonSGDUpdate(maxIterations * batchSize, momentum),
NoDecay(),
resetPolicy,
exactObjective)
{ /* Nothing to do here. */ }
/**
* Optimize the given function using DemonSGD. The given starting point will
* be modified to store the finishing point of the algorithm, and the final
* objective value is returned.
*
* @tparam SeparableFunctionType Type of the function to optimize.
* @tparam MatType Type of matrix to optimize with.
* @tparam GradType Type of matrix to use to represent function gradients.
* @tparam CallbackTypes Types of callback functions.
* @param function Function to optimize.
* @param iterate Starting point (will be modified).
* @param callbacks Callback functions.
* @return Objective value of the final point.
*/
template<typename SeparableFunctionType,
typename MatType,
typename GradType,
typename... CallbackTypes>
typename MatType::elem_type Optimize(SeparableFunctionType& function,
MatType& iterate,
CallbackTypes&&... callbacks)
{
return optimizer.template Optimize<
SeparableFunctionType, MatType, GradType, CallbackTypes...>(
function, iterate, std::forward<CallbackTypes>(callbacks)...);
}
//! Forward the MatType as GradType.
template<typename SeparableFunctionType,
typename MatType,
typename... CallbackTypes>
typename MatType::elem_type Optimize(SeparableFunctionType& function,
MatType& iterate,
CallbackTypes&&... callbacks)
{
return Optimize<SeparableFunctionType, MatType, MatType,
CallbackTypes...>(function, iterate,
std::forward<CallbackTypes>(callbacks)...);
}
//! Get the step size.
double StepSize() const { return optimizer.StepSize(); }
//! Modify the step size.
double& StepSize() { return optimizer.StepSize(); }
//! Get the batch size.
size_t BatchSize() const { return optimizer.BatchSize(); }
//! Modify the batch size.
size_t& BatchSize() { return optimizer.BatchSize(); }
//! Get the moment coefficient.
double Momentum() const { return optimizer.UpdatePolicy().Momentum(); }
//! Modify the moment coefficient.
double& Momentum() { return optimizer.UpdatePolicy().Momentum(); }
//! Get the momentum iteration number.
size_t MomentumIterations() const
{ return optimizer.UpdatePolicy().MomentumIterations(); }
//! Modify the momentum iteration number.
size_t& MomentumIterations()
{ return optimizer.UpdatePolicy().MomentumIterations(); }
//! Get the maximum number of iterations (0 indicates no limit).
size_t MaxIterations() const { return optimizer.MaxIterations(); }
//! Modify the maximum number of iterations (0 indicates no limit).
size_t& MaxIterations() { return optimizer.MaxIterations(); }
//! Get the tolerance for termination.
double Tolerance() const { return optimizer.Tolerance(); }
//! Modify the tolerance for termination.
double& Tolerance() { return optimizer.Tolerance(); }
//! Get whether or not the individual functions are shuffled.
bool Shuffle() const { return optimizer.Shuffle(); }
//! Modify whether or not the individual functions are shuffled.
bool& Shuffle() { return optimizer.Shuffle(); }
//! Get whether or not the actual objective is calculated.
bool ExactObjective() const { return optimizer.ExactObjective(); }
//! Modify whether or not the actual objective is calculated.
bool& ExactObjective() { return optimizer.ExactObjective(); }
//! Get whether or not the update policy parameters
//! are reset before Optimize call.
bool ResetPolicy() const { return optimizer.ResetPolicy(); }
//! Modify whether or not the update policy parameters
//! are reset before Optimize call.
bool& ResetPolicy() { return optimizer.ResetPolicy(); }
private:
//! The Stochastic Gradient Descent object with DemonSGD policy.
SGD<DemonSGDUpdate> optimizer;
};
} // namespace ens
#endif
@@ -0,0 +1,139 @@
/**
* @file demon_sgd_update.hpp
* @author Marcus Edel
*
* Implementation of DemonSGD.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_DEMON_SGD_DEMON_SGD_UPDATE_HPP
#define ENSMALLEN_DEMON_SGD_DEMON_SGD_UPDATE_HPP
namespace ens {
/**
* DemonSGD automatically decays momentum, motivated by decaying the total
* contribution of a gradient to all future updates.
*
* For more information, see the following.
*
* @code
* @misc{
* title = {Decaying momentum helps neural network training},
* author = {John Chen and Cameron Wolfe and Zhao Li
* and Anastasios Kyrillidis},
* url = {https://arxiv.org/abs/1910.04952}
* year = {2019}
* }
* @endcode
*/
class DemonSGDUpdate
{
public:
/**
* Construct the DemonSGD update policy with the given parameters.
*
* @param momentumIterations The number of iterations before the momentum
* will decay to zero.
* @param momentum The initial momentum coefficient.
*/
DemonSGDUpdate(const size_t momentumIterations = 100,
const double momentum = 0.9) :
T(momentumIterations),
betaInit(momentum),
t(0)
{
// Make sure the momentum iterations parameter is non-zero.
assert(momentumIterations != 0 && "The number of iterations before the "
"momentum will decay is zero, make sure the max iterations and "
"batch size parameter is set correctly. "
"Default: momentumIterations = maxIterations * batchSize.");
}
//! Get the momentum coefficient.
double Momentum() const { return betaInit; }
//! Modify the momentum coefficient.
double& Momentum() { return betaInit; }
//! Get the current iteration number.
size_t Iteration() const { return t; }
//! Modify the current iteration number.
size_t& Iteration() { return t; }
//! Get the momentum iteration number.
size_t MomentumIterations() const { return T; }
//! Modify the momentum iteration number.
size_t& MomentumIterations() { return T; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
* instantiated at the start of the optimization, and holds parameters
* specific to an individual optimization.
*/
template<typename MatType, typename GradType>
class Policy
{
public:
/**
* This constructor is called by the SGD Optimize() method before the start
* of the iteration update process.
*
* @param parent Instantiated PadamUpdate parent object.
* @param rows Number of rows in the gradient matrix.
* @param cols Number of columns in the gradient matrix.
*/
Policy(DemonSGDUpdate& parent,
const size_t /* rows */,
const size_t /* cols */) :
parent(parent)
{ /* Nothing to do here */ }
/**
* Update step for DemonSGD.
*
* @param iterate Parameters that minimize the function.
* @param stepSize Step size to be used for the given iteration.
* @param gradient The gradient matrix.
*/
void Update(MatType& iterate,
const double stepSize,
const GradType& gradient)
{
double decayRate = 1;
if (parent.t > 0)
decayRate = 1.0 - (double) parent.t / (double) parent.T;
const double betaDecay = parent.betaInit * decayRate;
const double beta = betaDecay / ((1.0 - parent.betaInit) + betaDecay);
// Perform the update.
iterate *= beta;
iterate -= stepSize * gradient;
// Increment the iteration counter variable.
++parent.t;
}
private:
//! Instantiated parent object.
DemonSGDUpdate& parent;
};
private:
//! The number of momentum iterations.
size_t T;
//! Initial momentum coefficient.
double betaInit;
//! The number of iterations.
size_t t;
};
} // namespace ens
#endif
+6 -6
View File
@@ -15,17 +15,17 @@
#define ENS_VERSION_MAJOR 2
// The minor version is two digits so regular numerical comparisons of versions
// work right. The first minor version of a release is always 10.
#define ENS_VERSION_MINOR 16
#define ENS_VERSION_PATCH 2
#define ENS_VERSION_MINOR 19
#define ENS_VERSION_PATCH 0
// If this is a release candidate, it will be reflected in the version name
// (i.e. the version name will be "RC1", "RC2", etc.). Otherwise the version
// name will typically be a seemingly arbitrary set of words that does not
// contain the capitalized string "RC".
#define ENS_VERSION_NAME "Severely Dented Can Of Polyurethane"
#define ENS_VERSION_NAME "Eight Ball Deluxe"
// Incorporate the date the version was released.
#define ENS_VERSION_YEAR "2021"
#define ENS_VERSION_MONTH "03"
#define ENS_VERSION_DAY "24"
#define ENS_VERSION_YEAR "2022"
#define ENS_VERSION_MONTH "04"
#define ENS_VERSION_DAY "06"
namespace ens {
+7 -15
View File
@@ -50,8 +50,7 @@ class FTMLUpdate
const double beta2 = 0.999) :
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
iteration(0)
beta2(beta2)
{ /* Do nothing. */ }
//! Get the value used to initialise the squared gradient parameter.
@@ -69,11 +68,6 @@ class FTMLUpdate
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
@@ -112,16 +106,14 @@ class FTMLUpdate
const GradType& gradient)
{
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
// And update the iterate.
v *= parent.beta2;
v += (1 - parent.beta2) * (gradient % gradient);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1,
parent.iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2,
parent.iteration);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
MatType sigma = -parent.beta1 * d;
d = biasCorrection1 / stepSize *
@@ -145,6 +137,9 @@ class FTMLUpdate
// Parameter update term.
MatType d;
// The number of iterations.
size_t iteration;
};
private:
@@ -156,9 +151,6 @@ class FTMLUpdate
// The second moment coefficient.
double beta2;
// The number of iterations.
size_t iteration;
};
} // namespace ens
@@ -387,6 +387,25 @@ inline void CheckArbitraryFunctionTypeAPI()
#endif
}
template<typename FunctionType, typename... RemainingTypes>
typename std::enable_if<(sizeof...(RemainingTypes) > 1), void>::type
CheckArbitraryFunctionTypeAPI()
{
#ifndef ENS_DISABLE_TYPE_CHECKS
constexpr size_t size = sizeof...(RemainingTypes);
using TupleType = typename std::tuple<RemainingTypes...>;
using MatType = typename std::tuple_element<size - 1, TupleType>::type;
static_assert(CheckEvaluate<FunctionType, MatType, MatType>::value,
"One of the provided FunctionType does not have a correct definition of Evaluate(). "
"Please check that the corresponding FunctionType fully satisfies the requirements "
"of the ArbitraryFunctionType API; see the optimizer tutorial for "
"more details.");
CheckArbitraryFunctionTypeAPI<RemainingTypes...>();
#endif
}
/**
* Perform checks for the ResolvableFunctionType API.
*/
@@ -45,7 +45,7 @@ inline void Proximal::ProjectToL1Ball(MatType& v, double tau)
MatType simplexSum = arma::cumsum(simplexSol);
double nu = 0;
size_t rho = 0;
size_t rho = simplexSol.n_rows - 1;
for (size_t j = 1; j <= simplexSol.n_rows; j++)
{
rho = simplexSol.n_rows - j;
@@ -53,7 +53,7 @@ inline void Proximal::ProjectToL1Ball(MatType& v, double tau)
if (nu > 0)
break;
}
double theta = (simplexSum(rho) - tau) / rho;
const double theta = (simplexSum(rho) - tau) / rho;
// Threshold on absolute value of v with theta.
for (arma::uword j = 0; j < simplexSol.n_rows; j++)
+2 -2
View File
@@ -79,7 +79,7 @@ double L_BFGS::ChooseScalingFactor(const size_t iterationNum,
{
typedef typename CubeType::elem_type CubeElemType;
double scalingFactor = 1.0;
double scalingFactor;
if (iterationNum > 0)
{
int previousPos = (iterationNum - 1) % numBasis;
@@ -378,7 +378,7 @@ L_BFGS::Optimize(FunctionType& function,
terminate |= Callback::EvaluateWithGradient(*this, f, iterate,
functionValue, gradient, callbacks...);
ElemType prevFunctionValue = functionValue;
ElemType prevFunctionValue;
// The main optimization loop.
terminate |= Callback::BeginOptimization(*this, f, iterate, callbacks...);
@@ -0,0 +1,81 @@
/**
* @file pbi_decomposition.hpp
* @author Nanubala Gnana Sai
*
* The Penalty Based Boundary Intersection (PBI) decomposition policy.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_MOEAD_PBI_HPP
#define ENSMALLEN_MOEAD_PBI_HPP
namespace ens {
/**
* Penalty Based Boundary Intersection (PBI) method is a weight decomposition method,
* it tries to find the intersection between bottom-most boundary of the attainable
* objective set with the reference directions.
*
* The goal is to minimize the distance between objective vectors with the ideal point
* along the reference direction. To handle equality constraints, a penalty parameter
* theta is used.
*
* For more information, see the following:
* @code
* article{zhang2007moea,
* title={MOEA/D: A multiobjective evolutionary algorithm based on decomposition},
* author={Zhang, Qingfu and Li, Hui},
* journal={IEEE Transactions on evolutionary computation},
* pages={712--731},
* year={2007}
* @endcode
*/
class PenaltyBoundaryIntersection
{
public:
/**
* Constructor for Penalty Based Boundary Intersection decomposition
* policy.
*
* @param theta The penalty value.
*/
PenaltyBoundaryIntersection(const double theta = 5) :
theta(theta)
{
/* Nothing to do. */
}
/**
* Decompose the weight vectors.
*
* @tparam VecType The type of the vector used in the decommposition.
* @param weight The weight vector corresponding to a subproblem.
* @param idealPoint The reference point in the objective space.
* @param candidateFitness The objective vector of the candidate.
*/
template<typename VecType>
typename VecType::elem_type Apply(const VecType& weight,
const VecType& idealPoint,
const VecType& candidateFitness)
{
typedef typename VecType::elem_type ElemType;
//! A unit vector in the same direction as the provided weight vector.
const VecType referenceDirection = weight / arma::norm(weight);
//! Distance of F(x) from the idealPoint along the reference direction.
const ElemType d1 = arma::dot(candidateFitness - idealPoint, referenceDirection);
//! The perpendicular distance of F(x) from reference direction.
const ElemType d2 = arma::norm(candidateFitness - (idealPoint + d1 * referenceDirection));
return d1 + static_cast<ElemType>(theta) * d2;
}
private:
double theta;
};
} // namespace ens
#endif
@@ -0,0 +1,66 @@
/**
* @file tchebycheff_decomposition.hpp
* @author Nanubala Gnana Sai
*
* The Tchebycheff Weight decomposition policy.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_MOEAD_TCHEBYCHEFF_HPP
#define ENSMALLEN_MOEAD_TCHEBYCHEFF_HPP
namespace ens {
/**
* The Tchebycheff method works by taking the maximum of element-wise product
* between reference direction and the line connecting objective vector and
* ideal point.
*
* Under mild conditions, for each Pareto Optimal point there exists a reference
* direction such that the given point is also the optimal solution
* to this scalar objective.
*
* For more information, see the following:
* @code
* article{zhang2007moea,
* title={MOEA/D: A multiobjective evolutionary algorithm based on decomposition},
* author={Zhang, Qingfu and Li, Hui},
* journal={IEEE Transactions on evolutionary computation},
* pages={712--731},
* year={2007}
* @endcode
*/
class Tchebycheff
{
public:
/**
* Constructor for Tchebycheff decomposition policy.
*/
Tchebycheff()
{
/* Nothing to do. */
}
/**
* Decompose the weight vectors.
*
* @tparam VecType The type of the vector used in the decommposition.
* @param weight The weight vector corresponding to a subproblem.
* @param idealPoint The reference point in the objective space.
* @param candidateFitness The objective vector of the candidate.
*/
template<typename VecType>
typename VecType::elem_type Apply(const VecType& weight,
const VecType& idealPoint,
const VecType& candidateFitness)
{
return arma::max(weight % arma::abs(candidateFitness - idealPoint));
}
};
} // namespace ens
#endif
@@ -0,0 +1,62 @@
/**
* @file weighted_decomposition.hpp
* @author Nanubala Gnana Sai
*
* The Weighted Average decomposition policy.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_MOEAD_WEIGHTED_HPP
#define ENSMALLEN_MOEAD_WEIGHTED_HPP
namespace ens {
/**
* The Weighted average method of decomposition. The working principle is to
* minimize the dot product between reference direction and the line connecting
* objective vector and ideal point.
*
* For more information, see the following:
* @code
* article{zhang2007moea,
* title={MOEA/D: A multiobjective evolutionary algorithm based on decomposition},
* author={Zhang, Qingfu and Li, Hui},
* journal={IEEE Transactions on evolutionary computation},
* pages={712--731},
* year={2007}
* @endcode
*/
class WeightedAverage
{
public:
/**
* Constructor for Weighted Average decomposition policy.
*/
WeightedAverage()
{
/* Nothing to do. */
}
/**
* Decompose the weight vectors.
*
* @tparam VecType The type of the vector used in the decommposition.
* @param weight The weight vector corresponding to a subproblem.
* @param idealPoint The reference point in the objective space.
* @param candidateFitness The objective vector of the candidate.
*/
template<typename VecType>
typename VecType::elem_type Apply(const VecType& weight,
const VecType& /* idealPoint */,
const VecType& candidateFitness)
{
return arma::dot(weight, candidateFitness);
}
};
} // namespace ens
#endif
+338
View File
@@ -0,0 +1,338 @@
/**
* @file moead.hpp
* @author Nanubala Gnana Sai
*
* MOEA/D-DE is a multi objective optimization algorithm. MOEA/D-DE
* uses genetic algorithms along with a set of reference directions
* to drive the population towards the Optimal Front.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_MOEAD_MOEAD_HPP
#define ENSMALLEN_MOEAD_MOEAD_HPP
//! Decomposition policies.
#include "decomposition_policies/tchebycheff_decomposition.hpp"
#include "decomposition_policies/weighted_decomposition.hpp"
#include "decomposition_policies/pbi_decomposition.hpp"
//! Weight initialization policies.
#include "weight_init_policies/uniform_init.hpp"
#include "weight_init_policies/bbs_init.hpp"
#include "weight_init_policies/dirichlet_init.hpp"
namespace ens {
/**
* MOEA/D-DE (Multi Objective Evolutionary Algorithm based on Decompositon -
* Differential Variant) is a multiobjective optimization algorithm. This class
* implements the said optimizer.
*
* The algorithm works by generating a candidate population from a fixed starting point.
* Reference directions are generated to guide the optimization process towards the Pareto Front.
* Further, a decomposition function is defined to decompose the problem to a scalar optimization
* objective. Utilizing genetic operators, offsprings are generated with better decomposition values
* to replace the neighboring parent solutions.
*
* For more information, see the following:
* @code
* @article{li2008multiobjective,
* title={Multiobjective optimization problems with complicated Pareto sets, MOEA/D and NSGA-II},
* author={Li, Hui and Zhang, Qingfu},
* journal={IEEE transactions on evolutionary computation},
* pages={284--302},
* year={2008},
* @endcode
*/
template<typename InitPolicyType = Uniform,
typename DecompPolicyType = Tchebycheff>
class MOEAD {
public:
/**
* Constructor for the MOEA/D optimizer.
*
* The default values provided here are not necessarily suitable for a
* given function. Therefore, it is highly recommended to adjust the
* parameters according to the problem.
*
* @param populationSize The number of elements in the population.
* @param maxGenerations The maximum number of generations allowed.
* @param crossoverProb The probability that a crossover will occur.
* @param neighborProb The probability of sampling from neighbor.
* @param neighborSize The number of nearest neighbours of weights
* to find.
* @param distributionIndex The crowding degree of the mutation.
* @param differentialWeight A parameter used in the mutation of candidate
* solutions controls amplification factor of the differentiation.
* @param maxReplace The limit of solutions allowed to be replaced by a child.
* @param epsilon Handle numerical stability after weight initialization.
* @param lowerBound The lower bound on each variable of a member
* of the variable space.
* @param upperBound The upper bound on each variable of a member
* of the variable space.
*/
MOEAD(const size_t populationSize = 300,
const size_t maxGenerations = 500,
const double crossoverProb = 1.0,
const double neighborProb = 0.9,
const size_t neighborSize = 20,
const double distributionIndex = 20,
const double differentialWeight = 0.5,
const size_t maxReplace = 2,
const double epsilon = 1E-10,
const arma::vec& lowerBound = arma::zeros(1, 1),
const arma::vec& upperBound = arma::ones(1, 1),
const InitPolicyType initPolicy = InitPolicyType(),
const DecompPolicyType decompPolicy = DecompPolicyType());
/**
* Constructor for the MOEA/D optimizer. This constructor is provides an
* overload to use lowerBound and upperBound as doubles, in case all the
* variables in the problem have the same limits.
*
* The default values provided here are not necessarily suitable for a
* given function. Therefore, it is highly recommended to adjust the
* parameters according to the problem.
*
* @param populationSize The number of elements in the population.
* @param maxGenerations The maximum number of generations allowed.
* @param crossoverProb The probability that a crossover will occur.
* @param neighborProb The probability of sampling from neighbor.
* @param neighborSize The number of nearest neighbours of weights
* to find.
* @param distributionIndex The crowding degree of the mutation.
* @param differentialWeight A parameter used in the mutation of candidate
* solutions controls amplification factor of the differentiation.
* @param maxReplace The limit of solutions allowed to be replaced by a child.
* @param epsilon Handle numerical stability after weight initialization.
* @param lowerBound The lower bound on each variable of a member
* of the variable space.
* @param upperBound The upper bound on each variable of a member
* of the variable space.
*/
MOEAD(const size_t populationSize = 300,
const size_t maxGenerations = 500,
const double crossoverProb = 1.0,
const double neighborProb = 0.9,
const size_t neighborSize = 20,
const double distributionIndex = 20,
const double differentialWeight = 0.5,
const size_t maxReplace = 2,
const double epsilon = 1E-10,
const double lowerBound = 0,
const double upperBound = 1,
const InitPolicyType initPolicy = InitPolicyType(),
const DecompPolicyType decompPolicy = DecompPolicyType());
/**
* Optimize a set of objectives. The initial population is generated
* using the initial point. The output is the best generated front.
*
* @tparam MatType The type of matrix used to store coordinates.
* @tparam ArbitraryFunctionType The type of objective function.
* @tparam CallbackTypes Types of callback function.
* @param objectives std::tuple of the objective functions.
* @param iterate The initial reference point for generating population.
* @param callbacks The callback functions.
*/
template<typename MatType,
typename... ArbitraryFunctionType,
typename... CallbackTypes>
typename MatType::elem_type Optimize(std::tuple<ArbitraryFunctionType...>& objectives,
MatType& iterate,
CallbackTypes&&... callbacks);
//! Retrieve population size.
size_t PopulationSize() const { return populationSize; }
//! Modify the population size.
size_t& PopulationSize() { return populationSize; }
//! Retrieve number of generations.
size_t MaxGenerations() const { return maxGenerations; }
//! Modify the number of generations.
size_t& MaxGenerations() { return maxGenerations; }
//! Retrieve crossover rate.
double CrossoverRate() const { return crossoverProb; }
//! Modify the crossover rate.
double& CrossoverRate() { return crossoverProb; }
//! Retrieve size of the weight neighbor.
size_t NeighborSize() const { return neighborSize; }
//! Modify the size of the weight neighbor.
size_t& NeighborSize() { return neighborSize; }
//! Retrieve value of the distribution index.
double DistributionIndex() const { return distributionIndex; }
//! Modify the value of the distribution index.
double& DistributionIndex() { return distributionIndex; }
//! Retrieve value of neighbor probability.
double NeighborProb() const { return neighborProb; }
//! Modify the value of neigbourhood probability.
double& NeighborProb() { return neighborProb; }
//! Retrieve value of scaling factor.
double DifferentialWeight() const { return differentialWeight; }
//! Modify the value of scaling factor.
double& DifferentialWeight() { return differentialWeight; }
//! Retrieve value of maxReplace.
size_t MaxReplace() const { return maxReplace; }
//! Modify value of maxReplace.
size_t& MaxReplace() { return maxReplace; }
//! Retrieve value of epsilon.
double Epsilon() const { return epsilon; }
//! Modify value of maxReplace.
double& Epsilon() { return epsilon; }
//! Retrieve value of lowerBound.
const arma::vec& LowerBound() const { return lowerBound; }
//! Modify value of lowerBound.
arma::vec& LowerBound() { return lowerBound; }
//! Retrieve value of upperBound.
const arma::vec& UpperBound() const { return upperBound; }
//! Modify value of upperBound.
arma::vec& UpperBound() { return upperBound; }
//! Retrieve the Pareto optimal points in variable space. This returns an empty cube
//! until `Optimize()` has been called.
const arma::cube& ParetoSet() const { return paretoSet; }
//! Retrieve the best front (the Pareto frontier). This returns an empty cube until
//! `Optimize()` has been called.
const arma::cube& ParetoFront() const { return paretoFront; }
//! Get the weight initialization policy.
const InitPolicyType& InitPolicy() const { return initPolicy; }
//! Modify the weight initialization policy.
InitPolicyType& InitPolicy() { return initPolicy; }
//! Get the weight decomposition policy.
const DecompPolicyType& DecompPolicy() const { return decompPolicy; }
//! Modify the weight decomposition policy.
DecompPolicyType& DecompPolicy() { return decompPolicy; }
private:
/**
* @brief Randomly selects two members from the population.
*
* @param subProblemIdx Index of the current subproblem.
* @param neighborSize A matrix containing indices of the neighbors.
* @return std::tuple<size_t, size_t> The chosen pair of indices.
*/
std::tuple<size_t, size_t> Mating(size_t subProblemIdx,
const arma::umat& neighborSize,
bool sampleNeighbor);
/**
* Mutate the child formed by the crossover of two random members of the
* population. Uses polynomial mutation.
*
* @tparam MatType The type of matrix used to store coordinates.
* @param child The candidate to be mutated.
* @param mutationRate The probability of mutation.
* @param lowerBound The lower bound on each variable in the matrix.
* @param upperBound The upper bound on each variable in the matrix.
* @return The mutated child.
*/
template<typename MatType>
void Mutate(MatType& child,
double mutationRate,
const MatType& lowerBound,
const MatType& upperBound);
/**
* Evaluate objectives for the elite population.
*
* @tparam ArbitraryFunctionType std::tuple of multiple function types.
* @tparam MatType Type of matrix to optimize.
* @param population The elite population.
* @param objectives The set of objectives.
* @param calculatedObjectives Vector to store calculated objectives.
*/
template<std::size_t I = 0,
typename MatType,
typename ...ArbitraryFunctionType>
typename std::enable_if<I == sizeof...(ArbitraryFunctionType), void>::type
EvaluateObjectives(
std::vector<MatType>&,
std::tuple<ArbitraryFunctionType...>&,
std::vector<arma::Col<typename MatType::elem_type> >&);
template<std::size_t I = 0,
typename MatType,
typename ...ArbitraryFunctionType>
typename std::enable_if<I < sizeof...(ArbitraryFunctionType), void>::type
EvaluateObjectives(
std::vector<MatType>& population,
std::tuple<ArbitraryFunctionType...>& objectives,
std::vector<arma::Col<typename MatType::elem_type> >&
calculatedObjectives);
//! Size of the population.
size_t populationSize;
//! Maximum number of generations before termination criteria is met.
size_t maxGenerations;
//! Probability of crossover between two members.
double crossoverProb;
//! The probability that two elements will be chosen from the neighbor.
double neighborProb;
//! Number of nearest neighbours of weights to consider.
size_t neighborSize;
//! The crowding degree of the mutation. Higher value produces a mutant
//! resembling its parent.
double distributionIndex;
//! Amplification factor for differentiation.
double differentialWeight;
//! Maximum number of childs which can replace the parent. Higher value
//! leads to a loss of diversity.
size_t maxReplace;
//! A small numeric value to be added to the weights after initialization.
//! Prevents zero value inside inited weights.
double epsilon;
//! Lower bound on each variable in the variable space.
arma::vec lowerBound;
//! Upper bound on each variable in the variable space.
arma::vec upperBound;
//! The set of all the Pareto optimal points.
//! Stored after Optimize() is called.
arma::cube paretoSet;
//! The set of all the Pareto optimal objective vectors.
//! Stored after Optimize() is called.
arma::cube paretoFront;
//! Policy to initialize the reference directions (weights) matrix.
InitPolicyType initPolicy;
//! Policy to decompose the weights.
DecompPolicyType decompPolicy;
};
using DefaultMOEAD = MOEAD<Uniform, Tchebycheff>;
using BBSMOEAD = MOEAD<BayesianBootstrap, Tchebycheff>;
using DirichletMOEAD = MOEAD<Dirichlet, Tchebycheff>;
} // namespace ens
// Include implementation.
#include "moead_impl.hpp"
#endif
+441
View File
@@ -0,0 +1,441 @@
/**
* @file moead_impl.hpp
* @author Nanubala Gnana Sai
*
* Implementation of the MOEA/D-DE algorithm. Used for multi-objective
* optimization problems on arbitrary functions.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more Information.
*/
#ifndef ENSMALLEN_MOEAD_MOEAD_IMPL_HPP
#define ENSMALLEN_MOEAD_MOEAD_IMPL_HPP
#include "moead.hpp"
#include <assert.h>
namespace ens {
template <typename InitPolicyType, typename DecompPolicyType>
inline MOEAD<InitPolicyType, DecompPolicyType>::
MOEAD(const size_t populationSize,
const size_t maxGenerations,
const double crossoverProb,
const double neighborProb,
const size_t neighborSize,
const double distributionIndex,
const double differentialWeight,
const size_t maxReplace,
const double epsilon,
const arma::vec& lowerBound,
const arma::vec& upperBound,
const InitPolicyType initPolicy,
const DecompPolicyType decompPolicy) :
populationSize(populationSize),
maxGenerations(maxGenerations),
crossoverProb(crossoverProb),
neighborProb(neighborProb),
neighborSize(neighborSize),
distributionIndex(distributionIndex),
differentialWeight(differentialWeight),
maxReplace(maxReplace),
epsilon(epsilon),
lowerBound(lowerBound),
upperBound(upperBound),
initPolicy(initPolicy),
decompPolicy(decompPolicy)
{ /* Nothing to do here. */ }
template <typename InitPolicyType, typename DecompPolicyType>
inline MOEAD<InitPolicyType, DecompPolicyType>::
MOEAD(const size_t populationSize,
const size_t maxGenerations,
const double crossoverProb,
const double neighborProb,
const size_t neighborSize,
const double distributionIndex,
const double differentialWeight,
const size_t maxReplace,
const double epsilon,
const double lowerBound,
const double upperBound,
const InitPolicyType initPolicy,
const DecompPolicyType decompPolicy) :
populationSize(populationSize),
maxGenerations(maxGenerations),
crossoverProb(crossoverProb),
neighborProb(neighborProb),
neighborSize(neighborSize),
distributionIndex(distributionIndex),
differentialWeight(differentialWeight),
maxReplace(maxReplace),
epsilon(epsilon),
lowerBound(lowerBound * arma::ones(1, 1)),
upperBound(upperBound * arma::ones(1, 1)),
initPolicy(initPolicy),
decompPolicy(decompPolicy)
{ /* Nothing to do here. */ }
//! Optimize the function.
template <typename InitPolicyType, typename DecompPolicyType>
template<typename MatType,
typename... ArbitraryFunctionType,
typename... CallbackTypes>
typename MatType::elem_type MOEAD<InitPolicyType, DecompPolicyType>::
Optimize(std::tuple<ArbitraryFunctionType...>& objectives,
MatType& iterateIn,
CallbackTypes&&... callbacks)
{
// Population Size must be at least 3 for MOEA/D-DE to work.
if (populationSize < 3)
{
throw std::logic_error("MOEA/D-DE::Optimize(): population size should be at least"
" 3!");
}
// Convenience typedefs.
typedef typename MatType::elem_type ElemType;
typedef typename MatTypeTraits<MatType>::BaseMatType BaseMatType;
BaseMatType& iterate = (BaseMatType&) iterateIn;
// Make sure that we have the methods that we need. Long name...
traits::CheckArbitraryFunctionTypeAPI<ArbitraryFunctionType...,
BaseMatType>();
RequireDenseFloatingPointType<BaseMatType>();
if (neighborSize < 2)
{
throw std::invalid_argument(
"neighborSize should be atleast 2, however "
+ std::to_string(neighborSize) + " was detected."
);
}
if (neighborSize > populationSize - 1u)
{
std::ostringstream oss;
oss << "MOEAD::Optimize(): " << "neighborSize is " << neighborSize
<< " but populationSize is " << populationSize << "(should be"
<< " atleast " << (neighborSize + 1u) << ")" << std::endl;
throw std::logic_error(oss.str());
}
// Check if lower bound is a vector of a single dimension.
if (lowerBound.n_rows == 1)
lowerBound = lowerBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols);
// Check if upper bound is a vector of a single dimension.
if (upperBound.n_rows == 1)
upperBound = upperBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols);
// Check the dimensions of lowerBound and upperBound.
assert(lowerBound.n_rows == iterate.n_rows && "The dimensions of "
"lowerBound are not the same as the dimensions of iterate.");
assert(upperBound.n_rows == iterate.n_rows && "The dimensions of "
"upperBound are not the same as the dimensions of iterate.");
const size_t numObjectives = sizeof...(ArbitraryFunctionType);
const size_t numVariables = iterate.n_rows;
//! Useful temporaries for float-like comparisons.
const BaseMatType castedLowerBound = arma::conv_to<BaseMatType>::from(lowerBound);
const BaseMatType castedUpperBound = arma::conv_to<BaseMatType>::from(upperBound);
// Controls early termination of the optimization process.
bool terminate = false;
// The weight matrix. Each vector represents a decomposition subproblem (M X N).
const BaseMatType weights = initPolicy.template Generate<BaseMatType>(
numObjectives, populationSize, epsilon);
// 1.1 Storing the indices of nearest neighbors of each weight vector.
arma::umat neighborIndices(neighborSize, populationSize);
for (size_t i = 0; i < populationSize; ++i)
{
// Cache the distance between weights[i] and other weights.
const arma::Row<ElemType> distances =
arma::sqrt(arma::sum(arma::square(weights.col(i) - weights.each_col())));
arma::uvec sortedIndices = arma::stable_sort_index(distances);
// Ignore distance from self.
neighborIndices.col(i) = sortedIndices(arma::span(1, neighborSize));
}
// 1.2 Random generation of the initial population.
std::vector<BaseMatType> population(populationSize);
for (BaseMatType& individual : population)
{
individual = arma::randu<BaseMatType>(
iterate.n_rows, iterate.n_cols) - 0.5 + iterate;
// Constrain all genes to be within bounds.
individual = arma::min(arma::max(individual, castedLowerBound), castedUpperBound);
}
Info << "MOEA/D-DE initialized successfully. Optimization started." << std::endl;
std::vector<arma::Col<ElemType>> populationFitness(populationSize);
std::fill(populationFitness.begin(), populationFitness.end(),
arma::Col<ElemType>(numObjectives, arma::fill::zeros));
EvaluateObjectives(population, objectives, populationFitness);
// 1.3 Initialize the ideal point z.
arma::Col<ElemType> idealPoint(numObjectives);
idealPoint.fill(std::numeric_limits<ElemType>::max());
for (const arma::Col<ElemType>& individualFitness : populationFitness)
idealPoint = arma::min(idealPoint, individualFitness);
terminate |= Callback::BeginOptimization(*this, objectives, iterate, callbacks...);
// 2 The main loop.
for (size_t generation = 1; generation <= maxGenerations && !terminate; ++generation)
{
// Shuffle indexes of subproblems.
const arma::uvec shuffle = arma::shuffle(
arma::linspace<arma::uvec>(0, populationSize - 1, populationSize));
for (size_t subProblemIdx : shuffle)
{
// 2.1 Randomly select two indices in neighborIndices[subProblemIdx] and use them
// to make a child.
size_t r1, r2, r3;
r1 = subProblemIdx;
// Randomly choose to sample from the population or the neighbors.
const bool sampleNeighbor = arma::randu() < neighborProb;
std::tie(r2, r3) =
Mating(subProblemIdx, neighborIndices, sampleNeighbor);
// 2.2 - 2.3 Reproduction and Repair: Differential Operator followed by
// Polynomial Mutation.
BaseMatType candidate(iterate.n_rows, iterate.n_cols);
for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx)
{
if (arma::randu() < crossoverProb)
{
candidate(geneIdx) = population[r1](geneIdx) +
differentialWeight * (population[r2](geneIdx) -
population[r3](geneIdx));
// Boundary conditions.
if (candidate(geneIdx) < castedLowerBound(geneIdx))
{
candidate(geneIdx) = castedLowerBound(geneIdx) +
arma::randu() * (population[r1](geneIdx) - castedLowerBound(geneIdx));
}
if (candidate(geneIdx) > castedUpperBound(geneIdx))
{
candidate(geneIdx) = castedUpperBound(geneIdx) -
arma::randu() * (castedUpperBound(geneIdx) - population[r1](geneIdx));
}
}
else
candidate(geneIdx) = population[r1](geneIdx);
}
Mutate(candidate, 1.0 / static_cast<double>(numVariables),
castedLowerBound, castedUpperBound);
arma::Col<ElemType> candidateFitness(numObjectives);
//! Creating temp vectors to pass to EvaluateObjectives.
std::vector<BaseMatType> candidateContainer { candidate };
std::vector<arma::Col<ElemType>> fitnessContainer { candidateFitness };
EvaluateObjectives(candidateContainer, objectives, fitnessContainer);
candidateFitness = std::move(fitnessContainer[0]);
//! Flush out the dummy containers.
fitnessContainer.clear();
candidateContainer.clear();
// 2.4 Update of ideal point.
idealPoint = arma::min(idealPoint, candidateFitness);
// 2.5 Update of the population.
size_t replaceCounter = 0;
const size_t sampleSize = sampleNeighbor ? neighborSize : populationSize;
const arma::uvec idxShuffle = arma::shuffle(
arma::linspace<arma::uvec>(0, sampleSize - 1, sampleSize));
for (size_t idx : idxShuffle)
{
// Preserve diversity by controlling replacement of neighbors
// by child solution.
if (replaceCounter >= maxReplace)
break;
const size_t pick = sampleNeighbor ?
neighborIndices(idx, subProblemIdx) : idx;
const ElemType candidateDecomposition = decompPolicy.template
Apply<arma::Col<ElemType>>(weights.col(pick), idealPoint, candidateFitness);
const ElemType parentDecomposition = decompPolicy.template
Apply<arma::Col<ElemType>>(weights.col(pick), idealPoint, populationFitness[pick]);
if (candidateDecomposition < parentDecomposition)
{
population[pick] = candidate;
populationFitness[pick] = candidateFitness;
++replaceCounter;
}
}
} // End of pass over all subproblems.
// The final population itself is the best front.
const std::vector<arma::uvec> frontIndices { arma::shuffle(
arma::linspace<arma::uvec>(0, populationSize - 1, populationSize)) };
terminate |= Callback::GenerationalStepTaken(*this, objectives, iterate,
populationFitness, frontIndices, callbacks...);
} // End of pass over all the generations.
// Set the candidates from the Pareto Set as the output.
paretoSet.set_size(population[0].n_rows, population[0].n_cols, population.size());
// The Pareto Front is stored, can be obtained via ParetoSet() getter.
for (size_t solutionIdx = 0; solutionIdx < population.size(); ++solutionIdx)
{
paretoSet.slice(solutionIdx) =
arma::conv_to<arma::mat>::from(population[solutionIdx]);
}
// Set the candidates from the Pareto Front as the output.
paretoFront.set_size(populationFitness[0].n_rows, populationFitness[0].n_cols,
populationFitness.size());
// The Pareto Front is stored, can be obtained via ParetoFront() getter.
for (size_t solutionIdx = 0; solutionIdx < populationFitness.size(); ++solutionIdx)
{
paretoFront.slice(solutionIdx) =
arma::conv_to<arma::mat>::from(populationFitness[solutionIdx]);
}
// Assign iterate to first element of the Pareto Set.
iterate = population[0];
Callback::EndOptimization(*this, objectives, iterate, callbacks...);
ElemType performance = std::numeric_limits<ElemType>::max();
for (size_t geneIdx = 0; geneIdx < numObjectives; ++geneIdx)
{
if (arma::accu(populationFitness[geneIdx]) < performance)
performance = arma::accu(populationFitness[geneIdx]);
}
return performance;
}
//! Randomly chooses to select from parents or neighbors.
template <typename InitPolicyType, typename DecompPolicyType>
inline std::tuple<size_t, size_t>
MOEAD<InitPolicyType, DecompPolicyType>::
Mating(size_t subProblemIdx,
const arma::umat& neighborIndices,
bool sampleNeighbor)
{
//! Indexes of two points from the sample space.
size_t pointA = sampleNeighbor
? neighborIndices(
arma::randi(arma::distr_param(0, neighborSize - 1u)), subProblemIdx)
: arma::randi(arma::distr_param(0, populationSize - 1u));
size_t pointB = sampleNeighbor
? neighborIndices(
arma::randi(arma::distr_param(0, neighborSize - 1u)), subProblemIdx)
: arma::randi(arma::distr_param(0, populationSize - 1u));
//! If the sampled points are equal, then modify one of them
//! within reasonable bounds.
if (pointA == pointB)
{
if (pointA == populationSize - 1u)
--pointA;
else
++pointA;
}
return std::make_tuple(pointA, pointB);
}
//! Perform Polynomial mutation of the candidate.
template <typename InitPolicyType, typename DecompPolicyType>
template<typename MatType>
inline void MOEAD<InitPolicyType, DecompPolicyType>::
Mutate(MatType& candidate,
double mutationRate,
const MatType& lowerBound,
const MatType& upperBound)
{
const size_t numVariables = candidate.n_rows;
for (size_t geneIdx = 0; geneIdx < numVariables; ++geneIdx)
{
// Should this gene be mutated?
if (arma::randu() > mutationRate)
continue;
const double geneRange = upperBound(geneIdx) - lowerBound(geneIdx);
// Normalised distance from the bounds.
const double lowerDelta = (candidate(geneIdx) - lowerBound(geneIdx)) / geneRange;
const double upperDelta = (upperBound(geneIdx) - candidate(geneIdx)) / geneRange;
const double mutationPower = 1. / (distributionIndex + 1.0);
const double rand = arma::randu();
double value, perturbationFactor;
if (rand < 0.5)
{
value = 2.0 * rand + (1.0 - 2.0 * rand) *
std::pow(upperDelta, distributionIndex + 1.0);
perturbationFactor = std::pow(value, mutationPower) - 1.0;
}
else
{
value = 2.0 * (1.0 - rand) + 2.0 *(rand - 0.5) *
std::pow(lowerDelta, distributionIndex + 1.0);
perturbationFactor = 1.0 - std::pow(value, mutationPower);
}
candidate(geneIdx) += perturbationFactor * geneRange;
}
//! Enforce bounds.
candidate = arma::min(arma::max(candidate, lowerBound), upperBound);
}
//! No objectives to evaluate.
template <typename InitPolicyType, typename DecompPolicyType>
template<std::size_t I,
typename MatType,
typename ...ArbitraryFunctionType>
typename std::enable_if<I == sizeof...(ArbitraryFunctionType), void>::type
MOEAD<InitPolicyType, DecompPolicyType>::
EvaluateObjectives(
std::vector<MatType>&,
std::tuple<ArbitraryFunctionType...>&,
std::vector<arma::Col<typename MatType::elem_type> >&)
{
// Nothing to do here.
}
//! Evaluate the objectives for the entire population.
template <typename InitPolicyType, typename DecompPolicyType>
template<std::size_t I,
typename MatType,
typename ...ArbitraryFunctionType>
typename std::enable_if<I < sizeof...(ArbitraryFunctionType), void>::type
MOEAD<InitPolicyType, DecompPolicyType>::
EvaluateObjectives(
std::vector<MatType>& population,
std::tuple<ArbitraryFunctionType...>& objectives,
std::vector<arma::Col<typename MatType::elem_type> >& calculatedObjectives)
{
for (size_t i = 0; i < population.size(); i++)
{
calculatedObjectives[i](I) = std::get<I>(objectives).Evaluate(population[i]);
EvaluateObjectives<I+1, MatType, ArbitraryFunctionType...>(population, objectives,
calculatedObjectives);
}
}
} // namespace ens
#endif
@@ -0,0 +1,76 @@
/**
* @file bbs_init.hpp
* @author Nanubala Gnana Sai
*
* The Bayesian Bootstrap (BBS) method of Weight Initialization.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_MOEAD_BBS_HPP
#define ENSMALLEN_MOEAD_BBS_HPP
namespace ens {
/**
* The Bayesian Bootstrap method for initializing weights. Samples are randomly picked from uniform
* distribution followed by sorting and finding adjacent difference. This gives you a list of
* numbers which is guaranteed to sum up to 1.
*
* @code
* @article{rubin1981bayesian,
* title={The bayesian bootstrap},
* author={Rubin, Donald B},
* journal={The annals of statistics},
* pages={130--134},
* year={1981},
* @endcode
*
*/
class BayesianBootstrap
{
public:
/**
* Constructor for Bayesian Bootstrap policy.
*/
BayesianBootstrap()
{
/* Nothing to do. */
}
/**
* Generate the reference direction matrix.
*
* @tparam MatType The type of the matrix used for constructing weights.
* @param numObjectives The dimensionality of objective space.
* @param numPoints The number of reference directions requested.
* @param epsilon Handle numerical stability after weight initialization.
*/
template<typename MatType>
MatType Generate(const size_t numObjectives,
const size_t numPoints,
const double epsilon)
{
typedef typename MatType::elem_type ElemType;
typedef typename arma::Col<ElemType> VecType;
MatType weights(numObjectives, numPoints);
for (size_t pointIdx = 0; pointIdx < numPoints; ++pointIdx)
{
VecType referenceDirection(numObjectives + 1, arma::fill::randu);
referenceDirection(0) = 0;
referenceDirection(numObjectives) = 1;
referenceDirection = arma::sort(referenceDirection);
referenceDirection = arma::diff(referenceDirection);
weights.col(pointIdx) = std::move(referenceDirection) + epsilon;
}
return weights;
}
};
} // namespace ens
#endif
@@ -0,0 +1,55 @@
/**
* @file dirichlet_init.hpp
* @author Nanubala Gnana Sai
*
* The Dirichlet method of Weight Initialization.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_MOEAD_DIRICHLET_HPP
#define ENSMALLEN_MOEAD_DIRICHLET_HPP
namespace ens {
/**
* The Dirichlet method for initializing weights. Sampling a
* Dirichlet distribution with parameters set to one returns
* point lying on unit simplex with uniform distribution.
*/
class Dirichlet
{
public:
/**
* Constructor for Dirichlet policy.
*/
Dirichlet()
{
/* Nothing to do. */
}
/**
* Generate the reference direction matrix.
*
* @tparam MatType The type of the matrix used for constructing weights.
* @param numObjectives The dimensionality of objective space.
* @param numPoints The number of reference directions requested.
* @param epsilon Handle numerical stability after weight initialization.
*/
template<typename MatType>
MatType Generate(const size_t numObjectives,
const size_t numPoints,
const double epsilon)
{
MatType weights = arma::randg<MatType>(numObjectives, numPoints,
arma::distr_param(1.0, 1.0)) + epsilon;
// Normalize each column.
return arma::normalise(weights, 1, 0);
}
};
} // namespace ens
#endif
@@ -0,0 +1,208 @@
/**
* @file uniform_init.hpp
* @author Nanubala Gnana Sai
*
* The Uniform (Das Dennis) methodology of Weight Initialization.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_MOEAD_UNIFORM_HPP
#define ENSMALLEN_MOEAD_UNIFORM_HPP
namespace ens {
/**
* The Uniform (Das Dennis) method for initializing weights. This algorithm guarantees
* that the distance between adjacent points would be uniform.
*
* For more information, see the following:
*
* @code
* article{zhang2007moea,
* title={MOEA/D: A multiobjective evolutionary algorithm based on decomposition},
* author={Zhang, Qingfu and Li, Hui},
* journal={IEEE Transactions on evolutionary computation},
* pages={712--731},
* year={2007}
* @endcode
*/
class Uniform
{
public:
/**
* Constructor for Uniform Weight Initializatoin Policy.
*/
Uniform()
{
/* Nothing to do. */
}
/**
* Generate the reference direction matrix.
*
* @tparam MatType The type of the matrix used for constructing weights.
* @param numObjectives The dimensionality of objective space.
* @param numPoints The number of reference directions requested.
* @param epsilon Handle numerical stability after weight initialization.
*/
template<typename MatType>
MatType Generate(size_t numObjectives,
size_t numPoints,
double epsilon)
{
size_t numPartitions = FindNumParitions(numObjectives, numPoints);
size_t validNumPoints = FindNumUniformPoints(numObjectives, numPartitions);
//! The requested number of points is not matching any partition number.
if (numPoints != validNumPoints)
{
size_t nextValidNumPoints = FindNumUniformPoints(numObjectives, numPartitions + 1);
std::ostringstream oss;
oss << "DasDennis::Generate(): " << "The requested numPoints " << numPoints
<< " cannot be generated uniformly.\n " << "Either choose numPoints as "
<< validNumPoints << " (numPartition = " << numPartitions << ") or "
<< "numPoints as " << nextValidNumPoints << " (numPartition = "
<< numPartitions + 1 << ").";
throw std::logic_error(oss.str());
}
return DasDennis<MatType>(numObjectives, numPoints,
numPartitions, epsilon);
}
private:
/**
* Finds the number of points which can be sampled uniformly from a
* unit simplex given the number of partitions.
*/
size_t FindNumUniformPoints(const size_t numObjectives,
const size_t numPartitions)
{
//! O(N) algorithm to calculate binomial coefficient.
//! Source: https://www.geeksforgeeks.org/space-and-time-efficient-binomial-coefficient/
auto BinomialCoefficient =
[](size_t n, size_t k) -> size_t
{
size_t retval = 1;
// Since, C(n, k) = C(n, n - k).
if (k > n - k)
k = n - k;
// [n * (n - 1) * .... * (n - k + 1)] / [k * (k - 1) * .... * 1].
for (size_t i = 0; i < k; ++i)
{
retval *= (n - i);
retval /= (i + 1);
}
return retval;
};
return BinomialCoefficient(numObjectives + numPartitions - 1, numPartitions);
}
/**
* Calculates the appropriate number of partitions such that, the binomial
* coefficient value is closest to the number of points requested.
*/
size_t FindNumParitions(size_t numObjectives, size_t numPoints)
{
if (numObjectives == 1) return 0;
// Iteratively increase numPartitions so that the binomial coefficient
// comes near to numPoints;
size_t numPartitions {1};
size_t sampledNumPoints = FindNumUniformPoints(numPartitions,
numObjectives);
while (sampledNumPoints <= numPoints)
{
++numPartitions;
sampledNumPoints = FindNumUniformPoints(numObjectives,
numPartitions);
}
return numPartitions - 1;
}
/**
* A helper function for DasDennis
*/
template<typename AuxInfoStackType,
typename MatType>
void DasDennisHelper(AuxInfoStackType& progressStack,
MatType& weights,
const size_t numObjectives,
const size_t numPoints,
const size_t numPartitions,
const double epsilon)
{
typedef typename MatType::elem_type ElemType;
typedef typename arma::Row<ElemType> RowType;
size_t counter = 0;
const ElemType delta = 1.0 / (ElemType)numPartitions;
while ((counter < numPoints) && !progressStack.empty())
{
MatType point{};
size_t beta{};
std::tie(point, beta) = progressStack.back();
progressStack.pop_back();
if (point.size() + 1 == numObjectives)
{
point.insert_rows(point.n_rows, RowType(1).fill(
delta * static_cast<ElemType>(beta)));
weights.col(counter) = point + epsilon;
++counter;
}
else
{
for (size_t i = 0; i <= beta; ++i)
{
MatType pointClone(point);
pointClone.insert_rows(pointClone.n_rows, RowType(1).fill(
delta * static_cast<ElemType>(i)));
progressStack.push_back({pointClone, beta - i});
}
}
}
}
/**
* Generates the weight matrix after verifying the
* validity of the parameters.
*/
template <typename MatType>
MatType DasDennis(const size_t numObjectives,
const size_t numPoints,
const size_t numPartitions,
const double epsilon)
{
//! Holds auxillary information required for the helper function.
//! Holds the current point and beta value.
using AuxContainer = std::pair<MatType, size_t>;
std::vector<AuxContainer> progressStack{};
//! Init the progress stack.
progressStack.push_back({{}, numPartitions});
MatType weights(numObjectives, numPoints);
weights.fill(arma::datum::nan);
DasDennisHelper<decltype(progressStack), MatType>(
progressStack,
weights,
numObjectives,
numPoints,
numPartitions,
epsilon);
return weights;
}
};
} // namespace ens
#endif
+61 -18
View File
@@ -1,6 +1,7 @@
/**
* @file nsga2.hpp
* @author Sayan Goswami
* @author Nanubala Gnana Sai
*
* NSGA-II is a multi-objective optimization algorithm, widely used in
* many real-world applications. NSGA-II generates offsprings using
@@ -50,7 +51,8 @@ namespace ens {
* see the documentation on function types included with this distribution or
* on the ensmallen website.
*/
class NSGA2 {
class NSGA2
{
public:
/**
* Constructor for the NSGA2 optimizer.
@@ -168,9 +170,33 @@ class NSGA2 {
//! Modify value of upperBound.
arma::vec& UpperBound() { return upperBound; }
//! Retrieve the best front (the Pareto frontier). This returns an empty vector until `Optimize()`
//! has been called.
const std::vector<arma::mat>& Front() const { return bestFront; }
//! Retrieve the Pareto optimal points in variable space. This returns an empty cube
//! until `Optimize()` has been called.
const arma::cube& ParetoSet() const { return paretoSet; }
//! Retrieve the best front (the Pareto frontier). This returns an empty cube until
//! `Optimize()` has been called.
const arma::cube& ParetoFront() const { return paretoFront; }
/**
* Retrieve the best front (the Pareto frontier). This returns an empty
* vector until `Optimize()` has been called. Note that this function is
* deprecated and will be removed in ensmallen 3.x! Use `ParetoFront()`
* instead.
*/
ens_deprecated const std::vector<arma::mat>& Front()
{
if (rcFront.size() == 0)
{
// Match the old return format.
for (size_t i = 0; i < paretoFront.n_slices; ++i)
{
rcFront.push_back(arma::mat(paretoFront.slice(i)));
}
}
return rcFront;
}
private:
/**
@@ -188,7 +214,7 @@ class NSGA2 {
typename std::enable_if<I == sizeof...(ArbitraryFunctionType), void>::type
EvaluateObjectives(std::vector<MatType>&,
std::tuple<ArbitraryFunctionType...>&,
std::vector<arma::Col<double> >&);
std::vector<arma::Col<typename MatType::elem_type> >&);
template<std::size_t I = 0,
typename MatType,
@@ -196,7 +222,8 @@ class NSGA2 {
typename std::enable_if<I < sizeof...(ArbitraryFunctionType), void>::type
EvaluateObjectives(std::vector<MatType>& population,
std::tuple<ArbitraryFunctionType...>& objectives,
std::vector<arma::Col<double> >& calculatedObjectives);
std::vector<arma::Col<typename MatType::elem_type> >&
calculatedObjectives);
/**
* Reproduce candidates from the elite population to generate a new
@@ -210,8 +237,8 @@ class NSGA2 {
*/
template<typename MatType>
void BinaryTournamentSelection(std::vector<MatType>& population,
const arma::vec& lowerBound,
const arma::vec& upperBound);
const MatType& lowerBound,
const MatType& upperBound);
/**
* Crossover two parents to create a pair of new children.
@@ -239,8 +266,8 @@ class NSGA2 {
*/
template<typename MatType>
void Mutate(MatType& child,
const arma::vec& lowerBound,
const arma::vec& upperBound);
const MatType& lowerBound,
const MatType& upperBound);
/**
* Sort the candidate population using their domination count and the set of
@@ -281,11 +308,15 @@ class NSGA2 {
* Assigns crowding distance metric for sorting.
*
* @param front The previously generated Pareto fronts.
* @param objectives The set of objectives.
* @param crowdingDistance The previously calculated objectives.
* @param calculatedObjectives The previously calculated objectives.
* @param crowdingDistance The crowding distance for each individual in
* the population.
*/
void CrowdingDistanceAssignment(const std::vector<size_t>& front,
std::vector<double>& crowdingDistance);
template <typename MatType>
void CrowdingDistanceAssignment(
const std::vector<size_t>& front,
std::vector<arma::Col<typename MatType::elem_type>>& calculatedObjectives,
std::vector<typename MatType::elem_type>& crowdingDistance);
/**
* The operator used in the crowding distance based sorting.
@@ -299,13 +330,15 @@ class NSGA2 {
* @param idxQ The index of the second cadidate from the elite population
* being sorted.
* @param ranks The previously calculated ranks.
* @param crowdingDistance The previously calculated objectives.
* @param crowdingDistance The crowding distance for each individual in
* the population.
* @return true if the first candidate is preferred, otherwise, false.
*/
template<typename MatType>
bool CrowdingOperator(size_t idxP,
size_t idxQ,
const std::vector<size_t>& ranks,
const std::vector<double>& crowdingDistance);
const std::vector<typename MatType::elem_type>& crowdingDistance);
//! The number of objectives being optimised for.
size_t numObjectives;
@@ -337,8 +370,18 @@ class NSGA2 {
//! Upper bound of the initial swarm.
arma::vec upperBound;
//! Best front, stored after Optimize() is called.
std::vector<arma::mat> bestFront;
//! The set of all the Pareto optimal points.
//! Stored after Optimize() is called.
arma::cube paretoSet;
//! The set of all the Pareto optimal objective vectors.
//! Stored after Optimize() is called.
arma::cube paretoFront;
//! A different representation of the Pareto front, for reverse compatibility
//! purposes. This can be removed when ensmallen 3.x is released! (Along
//! with `Front()`.) This is only populated when `Front()` is called.
std::vector<arma::mat> rcFront;
};
} // namespace ens
+126 -76
View File
@@ -1,6 +1,7 @@
/**
* @file nsga2_impl.hpp
* @author Sayan Goswami
* @author Nanubala Gnana Sai
*
* Implementation of the NSGA-II algorithm. Used for multi-objective
* optimization problems on arbitrary functions.
@@ -27,6 +28,8 @@ inline NSGA2::NSGA2(const size_t populationSize,
const double epsilon,
const arma::vec& lowerBound,
const arma::vec& upperBound) :
numObjectives(0),
numVariables(0),
populationSize(populationSize),
maxGenerations(maxGenerations),
crossoverProb(crossoverProb),
@@ -45,6 +48,8 @@ inline NSGA2::NSGA2(const size_t populationSize,
const double epsilon,
const double lowerBound,
const double upperBound) :
numObjectives(0),
numVariables(0),
populationSize(populationSize),
maxGenerations(maxGenerations),
crossoverProb(crossoverProb),
@@ -61,7 +66,7 @@ template<typename MatType,
typename... CallbackTypes>
typename MatType::elem_type NSGA2::Optimize(
std::tuple<ArbitraryFunctionType...>& objectives,
MatType& iterate,
MatType& iterateIn,
CallbackTypes&&... callbacks)
{
// Make sure for evolution to work at least four candidates are present.
@@ -71,6 +76,17 @@ typename MatType::elem_type NSGA2::Optimize(
" least 4, and, a multiple of 4!");
}
// Convenience typedefs.
typedef typename MatType::elem_type ElemType;
typedef typename MatTypeTraits<MatType>::BaseMatType BaseMatType;
BaseMatType& iterate = (BaseMatType&) iterateIn;
// Make sure that we have the methods that we need. Long name...
traits::CheckArbitraryFunctionTypeAPI<ArbitraryFunctionType...,
BaseMatType>();
RequireDenseFloatingPointType<BaseMatType>();
// Check if lower bound is a vector of a single dimension.
if (lowerBound.n_rows == 1)
lowerBound = lowerBound(0, 0) * arma::ones(iterate.n_rows, iterate.n_cols);
@@ -85,29 +101,29 @@ typename MatType::elem_type NSGA2::Optimize(
assert(upperBound.n_rows == iterate.n_rows && "The dimensions of "
"upperBound are not the same as the dimensions of iterate.");
// Convenience typedefs.
typedef typename MatType::elem_type ElemType;
numObjectives = sizeof...(ArbitraryFunctionType);
numVariables = iterate.n_rows;
// Cache calculated objectives.
std::vector<arma::Col<ElemType> > calculatedObjectives;
// Pre-allocate space for the calculated objectives.
calculatedObjectives.resize(populationSize);
std::vector<arma::Col<ElemType> > calculatedObjectives(populationSize);
// Population size reserved to 2 * populationSize + 1 to accommodate
// for the size of intermediate candidate population.
std::vector<MatType> population;
std::vector<BaseMatType> population;
population.reserve(2 * populationSize + 1);
// Pareto fronts, initialized during non-dominated sorting.
// Stores indices of population belonging to a certain front.
std::vector<std::vector<size_t> > fronts;
// Initialised in CrowdingDistanceAssignment.
std::vector<double> crowdingDistance;
std::vector<ElemType> crowdingDistance;
// Initialised during non-dominated sorting.
std::vector<size_t> ranks;
//! Useful temporaries for float-like comparisons.
const BaseMatType castedLowerBound = arma::conv_to<BaseMatType>::from(lowerBound);
const BaseMatType castedUpperBound = arma::conv_to<BaseMatType>::from(upperBound);
// Controls early termination of the optimization process.
bool terminate = false;
@@ -115,87 +131,103 @@ typename MatType::elem_type NSGA2::Optimize(
// starting point.
for (size_t i = 0; i < populationSize; i++)
{
population.push_back(arma::randu<MatType>(iterate.n_rows,
population.push_back(arma::randu<BaseMatType>(iterate.n_rows,
iterate.n_cols) - 0.5 + iterate);
// Constrain all genes to be within bounds.
population[i] = arma::min(arma::max(population[i], castedLowerBound), castedUpperBound);
}
Info << "NSGA2 initialized successfully. Optimization started." << std::endl;
// Evaluate the fitness before optimization.
for (size_t i = 0; i < population.size(); i++)
calculatedObjectives[i] = arma::Col<ElemType>(numObjectives, arma::fill::zeros);
EvaluateObjectives(population, objectives, calculatedObjectives);
// Iterate until maximum number of generations is obtained.
terminate |= Callback::BeginOptimization(*this, objectives, iterate, callbacks...);
for (size_t generation = 1; generation <= maxGenerations && !terminate; generation++)
{
Info << "NSGA2: iteration " << generation << "." << std::endl;
terminate |= Callback::StepTaken(*this, objectives, iterate, callbacks...);
// Create new population of candidate from the present elite population.
// Have P_t, generate G_t using P_t.
BinaryTournamentSelection(population, lowerBound, upperBound);
BinaryTournamentSelection(population, castedLowerBound, castedUpperBound);
// Evaluate the objectives for the new population.
calculatedObjectives.resize(population.size());
for (size_t i = 0; i < population.size(); i++)
calculatedObjectives[i] = arma::Col<ElemType>(numObjectives, arma::fill::zeros);
std::fill(calculatedObjectives.begin(), calculatedObjectives.end(),
arma::Col<ElemType>(numObjectives, arma::fill::zeros));
EvaluateObjectives(population, objectives, calculatedObjectives);
// Perform fast non dominated sort on P_t G_t.
ranks.resize(population.size());
FastNonDominatedSort<MatType>(fronts, ranks, calculatedObjectives);
FastNonDominatedSort<BaseMatType>(fronts, ranks, calculatedObjectives);
// Perform crowding distance assignment.
crowdingDistance.resize(population.size());
std::fill(crowdingDistance.begin(), crowdingDistance.end(), 0.);
for (size_t fNum = 0; fNum < fronts.size(); fNum++)
{
CrowdingDistanceAssignment(fronts[fNum], crowdingDistance);
CrowdingDistanceAssignment<BaseMatType>(
fronts[fNum], calculatedObjectives, crowdingDistance);
}
// Sort based on crowding distance.
std::sort(population.begin(), population.end(),
[this, ranks, crowdingDistance, population](MatType candidateP,
MatType candidateQ)
{
size_t idxP, idxQ;
for (size_t i = 0; i < population.size(); i++)
{
if (arma::approx_equal(population[i], candidateP, "absdiff", epsilon))
idxP = i;
[this, ranks, crowdingDistance, population]
(BaseMatType candidateP, BaseMatType candidateQ)
{
size_t idxP{}, idxQ{};
for (size_t i = 0; i < population.size(); i++)
{
if (arma::approx_equal(population[i], candidateP, "absdiff", epsilon))
idxP = i;
if (arma::approx_equal(population[i], candidateQ, "absdiff", epsilon))
idxQ = i;
}
if (arma::approx_equal(population[i], candidateQ, "absdiff", epsilon))
idxQ = i;
}
return CrowdingOperator(idxP, idxQ, ranks, crowdingDistance);
}
return CrowdingOperator<BaseMatType>(idxP, idxQ, ranks, crowdingDistance);
}
);
// Yield a new population P_{t+1} of size populationSize.
// Discards unfit population from the R_{t} to yield P_{t+1}.
population.resize(populationSize);
terminate |= Callback::GenerationalStepTaken(*this, objectives, iterate,
calculatedObjectives, fronts, callbacks...);
}
// Set the candidates from the best front as the output.
std::vector<MatType> front;
// Set the candidates from the Pareto Set as the output.
paretoSet.set_size(population[0].n_rows, population[0].n_cols, fronts[0].size());
// The Pareto Set is stored, can be obtained via ParetoSet() getter.
for (size_t solutionIdx = 0; solutionIdx < fronts[0].size(); ++solutionIdx)
{
paretoSet.slice(solutionIdx) =
arma::conv_to<arma::mat>::from(population[fronts[0][solutionIdx]]);
}
for (size_t f: fronts[0])
front.push_back(population[f]);
// Set the candidates from the Pareto Front as the output.
paretoFront.set_size(calculatedObjectives[0].n_rows, calculatedObjectives[0].n_cols,
fronts[0].size());
// The Pareto Front is stored, can be obtained via ParetoFront() getter.
for (size_t solutionIdx = 0; solutionIdx < fronts[0].size(); ++solutionIdx)
{
paretoFront.slice(solutionIdx) =
arma::conv_to<arma::mat>::from(calculatedObjectives[fronts[0][solutionIdx]]);
}
// bestFront is stored, can be obtained by the Front() getter.
bestFront = front;
// Clear rcFront, in case it is later requested by the user for reverse
// compatibility reasons.
rcFront.clear();
// Assign iterate to first element of the best front.
iterate = bestFront[0];
// Assign iterate to first element of the Pareto Set.
iterate = population[fronts[0][0]];
Callback::EndOptimization(*this, objectives, iterate, callbacks...);
ElemType performance = std::numeric_limits<ElemType>::max();
for(arma::Col<ElemType> objective: calculatedObjectives)
for (const arma::Col<ElemType>& objective: calculatedObjectives)
if (arma::accu(objective) < performance)
performance = arma::accu(objective);
@@ -210,7 +242,7 @@ typename std::enable_if<I == sizeof...(ArbitraryFunctionType), void>::type
NSGA2::EvaluateObjectives(
std::vector<MatType>&,
std::tuple<ArbitraryFunctionType...>&,
std::vector<arma::Col<double> >&)
std::vector<arma::Col<typename MatType::elem_type> >&)
{
// Nothing to do here.
}
@@ -223,7 +255,7 @@ typename std::enable_if<I < sizeof...(ArbitraryFunctionType), void>::type
NSGA2::EvaluateObjectives(
std::vector<MatType>& population,
std::tuple<ArbitraryFunctionType...>& objectives,
std::vector<arma::Col<double> >& calculatedObjectives)
std::vector<arma::Col<typename MatType::elem_type> >& calculatedObjectives)
{
for (size_t i = 0; i < populationSize; i++)
{
@@ -236,8 +268,8 @@ NSGA2::EvaluateObjectives(
//! Reproduce and generate new candidates.
template<typename MatType>
inline void NSGA2::BinaryTournamentSelection(std::vector<MatType>& population,
const arma::vec& lowerBound,
const arma::vec& upperBound)
const MatType& lowerBound,
const MatType& upperBound)
{
std::vector<MatType> children;
@@ -292,20 +324,14 @@ inline void NSGA2::Crossover(MatType& childA,
//! Perform mutation of the candidates weights with some noise.
template<typename MatType>
inline void NSGA2::Mutate(MatType& child,
const arma::vec& lowerBound,
const arma::vec& upperBound)
const MatType& lowerBound,
const MatType& upperBound)
{
child += (arma::randu<MatType>(child.n_rows, child.n_cols) < mutationProb) %
(mutationStrength * arma::randn<MatType>(child.n_rows, child.n_cols));
// Constrain all genes to be between bounds.
for (size_t idx = 0; idx < numVariables; idx++)
{
if (child[idx] < lowerBound(idx))
child[idx] = lowerBound(idx);
else if (child[idx] > upperBound(idx))
child[idx] = upperBound(idx);
}
child = arma::min(arma::max(child, lowerBound), upperBound);
}
//! Sort population into Pareto fronts.
@@ -344,7 +370,7 @@ inline void NSGA2::FastNonDominatedSort(
size_t i = 0;
while (fronts[i].size() > 0)
while (!fronts[i].empty())
{
std::vector<size_t> nextFront;
@@ -365,6 +391,8 @@ inline void NSGA2::FastNonDominatedSort(
i++;
fronts.push_back(nextFront);
}
// Remove the empty final set.
fronts.pop_back();
}
//! Check if a candidate Pareto dominates another candidate.
@@ -393,37 +421,59 @@ inline bool NSGA2::Dominates(
}
//! Assign crowding distance to the population.
inline void NSGA2::CrowdingDistanceAssignment(const std::vector<size_t>& front,
std::vector<double>& crowdingDistance)
template <typename MatType>
inline void NSGA2::CrowdingDistanceAssignment(
const std::vector<size_t>& front,
std::vector<arma::Col<typename MatType::elem_type>>& calculatedObjectives,
std::vector<typename MatType::elem_type>& crowdingDistance)
{
if (front.size() > 0)
// Convenience typedefs.
typedef typename MatType::elem_type ElemType;
size_t fSize = front.size();
// Stores the sorted indices of the fronts.
arma::uvec sortedIdx = arma::regspace<arma::uvec>(0, 1, fSize - 1);
for (size_t m = 0; m < numObjectives; m++)
{
for (size_t elem: front)
crowdingDistance[elem] = 0;
// Cache fValues of individuals for current objective.
arma::Col<ElemType> fValues(fSize);
std::transform(front.begin(), front.end(), fValues.begin(),
[&](const size_t& individual)
{
return calculatedObjectives[individual](m);
});
size_t fSize = front.size();
// Sort front indices by ascending fValues for current objective.
std::sort(sortedIdx.begin(), sortedIdx.end(),
[&](const size_t& frontIdxA, const size_t& frontIdxB)
{
return (fValues(frontIdxA) < fValues(frontIdxB));
});
for (size_t m = 0; m < numObjectives; m++)
crowdingDistance[front[sortedIdx(0)]] =
std::numeric_limits<ElemType>::max();
crowdingDistance[front[sortedIdx(fSize - 1)]] =
std::numeric_limits<ElemType>::max();
ElemType minFval = fValues(sortedIdx(0));
ElemType maxFval = fValues(sortedIdx(fSize - 1));
ElemType scale =
std::abs(maxFval - minFval) == 0. ? 1. : std::abs(maxFval - minFval);
for (size_t i = 1; i < fSize - 1; i++)
{
crowdingDistance[front[0]] = std::numeric_limits<double>::max();
crowdingDistance[front[fSize - 1]] = std::numeric_limits<double>::max();
for (size_t i = 1; i < fSize - 1 ; i++)
{
crowdingDistance[front[i]] += (crowdingDistance[front[i - 1]] -
crowdingDistance[front[i + 1]]) /
(std::numeric_limits<double>::max() -
std::numeric_limits<double>::min());
}
crowdingDistance[front[sortedIdx(i)]] +=
(fValues(sortedIdx(i + 1)) - fValues(sortedIdx(i - 1))) / scale;
}
}
}
//! Comparator for crowding distance based sorting.
template<typename MatType>
inline bool NSGA2::CrowdingOperator(size_t idxP,
size_t idxQ,
const std::vector<size_t>& ranks,
const std::vector<double>& crowdingDistance)
const std::vector<typename MatType::elem_type>& crowdingDistance)
{
if (ranks[idxP] < ranks[idxQ])
return true;
+9 -16
View File
@@ -50,8 +50,7 @@ class PadamUpdate
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
partial(partial),
iteration(0)
partial(partial)
{
// Nothing to do.
}
@@ -76,11 +75,6 @@ class PadamUpdate
//! Modify the partial adaptive parameter.
double& Partial() { return partial; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
@@ -100,7 +94,8 @@ class PadamUpdate
* @param cols Number of columns in the gradient matrix.
*/
Policy(PadamUpdate& parent, const size_t rows, const size_t cols) :
parent(parent)
parent(parent),
iteration(0)
{
m.zeros(rows, cols);
v.zeros(rows, cols);
@@ -119,7 +114,7 @@ class PadamUpdate
const GradType& gradient)
{
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
// And update the iterate.
m *= parent.beta1;
@@ -128,10 +123,8 @@ class PadamUpdate
v *= parent.beta2;
v += (1 - parent.beta2) * (gradient % gradient);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1,
parent.iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2,
parent.iteration);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
// Element wise maximum of past and present squared gradients.
vImproved = arma::max(vImproved, v);
@@ -152,6 +145,9 @@ class PadamUpdate
//! The optimal sqaured gradient value.
GradType vImproved;
//! The number of iterations.
size_t iteration;
};
private:
@@ -166,9 +162,6 @@ class PadamUpdate
//! Partial adaptive parameter.
double partial;
//! The number of iterations.
size_t iteration;
};
} // namespace ens
@@ -42,5 +42,10 @@
#include "styblinski_tang_function.hpp"
#include "three_hump_camel_function.hpp"
#include "wood_function.hpp"
#include "zdt/zdt1_function.hpp"
#include "zdt/zdt2_function.hpp"
#include "zdt/zdt3_function.hpp"
#include "zdt/zdt4_function.hpp"
#include "zdt/zdt6_function.hpp"
#endif
@@ -114,7 +114,7 @@ class SchwefelFunction
template<typename MatType = arma::mat>
MatType GetFinalPoint() const
{
MatType result(initialPoint.n_rows, initialPoint.n_cols);
MatType result(initialPoint.n_rows, initialPoint.n_cols, arma::fill::none);
result.fill(420.9687);
return result;
}
@@ -0,0 +1,157 @@
/**
* @file zdt1_function.hpp
* @author Nanubala Gnana Sai
*
* Implementation of the first ZDT(Zitzler, Deb and Thiele) test.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_PROBLEMS_ZDT_ONE_FUNCTION_HPP
#define ENSMALLEN_PROBLEMS_ZDT_ONE_FUNCTION_HPP
namespace ens {
namespace test {
/**
* The ZDT1 function, defined by:
* \f[
* g(x) = 1 + 9(\sum_{i=2}^{n} x_i )/(n-1)
* f_1(x) = x_1
* h(f_1, g) = g(x)[1-\sqrt{f_1/g}\ ]
* f_2(x) = g(x) * h(f_1, g)
* \f]
*
* This is a 30-variable problem (n = 30) with a convex optimal set.
*
* Bounds of the variable space is:
* 0 <= x_i <= 1 for i = 1,...,n.
*
* This should be optimized to g(x) = 1.0, at:
* x_1* in [0, 1] ; x_i* = 0 for i = 2,...,n
*
* For more information, please refer to:
*
* @code
* @article{Zitzler2000,
* title = {Comparison of multiobjective evolutionary algorithms:
* Empirical results},
* author = {Zitzler, Eckart and Deb, Kalyanmoy and Thiele, Lothar},
* journal = {Evolutionary computation},
* year = {2000},
* doi = {10.1162/106365600568202}
* }
* @endcode
*
* @tparam MatType Type of matrix to optimize.
*/
template<typename MatType = arma::mat>
class ZDT1
{
private:
size_t numParetoPoints {100};
size_t numObjectives {2};
size_t numVariables {30};
public:
//! Initialize the ZDT1
ZDT1(size_t numParetoPoints = 100) :
numParetoPoints(numParetoPoints),
objectiveF1(*this),
objectiveF2(*this)
{/* Nothing to do here. */}
/**
* Evaluate the objectives with the given coordinate.
*
* @param coords The function coordinates.
* @return arma::Col<typename MatType::elem_type>
*/
arma::Col<typename MatType::elem_type> Evaluate(const MatType& coords)
{
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
arma::Col<ElemType> objectives(numObjectives);
objectives(0) = coords[0];
ElemType sum = arma::accu(coords(arma::span(1, numVariables - 1), 0));
ElemType g = 1. + 9. * sum / (static_cast<ElemType>(numVariables) - 1.);
ElemType objectiveRatio = objectives(0) / g;
objectives(1) = g * (1. - std::sqrt(objectiveRatio));
return objectives;
}
//! Get the starting point.
MatType GetInitialPoint()
{
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
return arma::Col<ElemType>(numVariables, 1, arma::fill::zeros);
}
struct ObjectiveF1
{
ObjectiveF1(ZDT1& zdtClass) : zdtClass(zdtClass)
{/*Nothing to do here */}
typename MatType::elem_type Evaluate(const MatType& coords)
{
return coords[0];
}
ZDT1& zdtClass;
};
struct ObjectiveF2
{
ObjectiveF2(ZDT1& zdtClass) : zdtClass(zdtClass)
{/*Nothing to do here */}
typename MatType::elem_type Evaluate(const MatType& coords)
{
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
size_t numVariables = zdtClass.numVariables;
ElemType sum = arma::accu(coords(arma::span(1, numVariables - 1), 0));
ElemType g = 1. + 9. * sum / (static_cast<ElemType>(numVariables - 1));
ElemType objectiveRatio = zdtClass.objectiveF1.Evaluate(coords) / g;
return g * (1. - std::sqrt(objectiveRatio));
}
ZDT1& zdtClass;
};
//! Get objective functions.
std::tuple<ObjectiveF1, ObjectiveF2> GetObjectives()
{
return std::make_tuple(objectiveF1, objectiveF2);
}
//! Get the Reference Front.
//! Refer PR #273 Ipynb notebook to see the plot of Reference
//! Front. The implementation has been taken from pymoo.
arma::cube GetReferenceFront()
{
arma::cube front(2, 1, numParetoPoints);
arma::vec x = arma::linspace(0, 1, numParetoPoints);
arma::vec y = 1 - arma::sqrt(x);
for (size_t idx = 0; idx < numParetoPoints; ++idx)
front.slice(idx) = arma::vec{ x(idx), y(idx) };
return front;
}
ObjectiveF1 objectiveF1;
ObjectiveF2 objectiveF2;
};
} //namespace test
} //namespace ens
#endif
@@ -0,0 +1,158 @@
/**
* @file zdt2_function.hpp
* @author Nanubala Gnana Sai
*
* Implementation of the second ZDT(Zitzler, Deb and Thiele) test.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_PROBLEMS_ZDT_TWO_FUNCTION_HPP
#define ENSMALLEN_PROBLEMS_ZDT_TWO_FUNCTION_HPP
namespace ens {
namespace test {
/**
* The ZDT2 function, defined by:
* \f[
* g(x) = 1 + 9(\sum_{i=2}^{n} x_i )/(n-1)
* f_1(x) = x_1
* h(f_1, g) = 1 - (f_1/g)^2
* f_2(x) = g(x) * h(f_1, g)
* \f]
*
* This is a 30-variable problem(n = 30) with a
* non convex optimal set.
*
* Bounds of the variable space is:
* 0 <= x_i <= 1 for i = 1,..,n.
*
* This should be optimized to g(x) = 1.0, at:
* x_1* in [0, 1] ; x_i* = 0 for i = 2,...,n
*
* For more information, please refer to:
*
* @code
* @article{Zitzler2000,
* title = {Comparison of multiobjective evolutionary algorithms:
* Empirical results},
* author = {Zitzler, Eckart and Deb, Kalyanmoy and Thiele, Lothar},
* journal = {Evolutionary computation},
* year = {2000},
* doi = {10.1162/106365600568202}
* }
* @endcode
*
* @tparam MatType Type of matrix to optimize.
*/
template<typename MatType = arma::mat>
class ZDT2
{
private:
size_t numParetoPoints {100};
size_t numObjectives {2};
size_t numVariables {30};
public:
//! Initialize the ZDT2
ZDT2(size_t numParetoPoints = 100) :
numParetoPoints(numParetoPoints),
objectiveF1(*this),
objectiveF2(*this)
{/* Nothing to do here. */}
/**
* Evaluate the objectives with the given coordinate.
*
* @param coords The function coordinates.
* @return arma::Col<typename MatType::elem_type>
*/
arma::Col<typename MatType::elem_type> Evaluate(const MatType& coords)
{
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
arma::Col<ElemType> objectives(numObjectives);
objectives(0) = coords[0];
ElemType sum = arma::accu(coords(arma::span(1, numVariables - 1), 0));
ElemType g = 1. + 9. * sum / (static_cast<ElemType>(numVariables) - 1.);
ElemType objectiveRatio = objectives(0) / g;
objectives(1) = g * (1. - std::pow(objectiveRatio, 2));
return objectives;
}
//! Get the starting point.
MatType GetInitialPoint()
{
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
return arma::Col<ElemType>(numVariables, 1, arma::fill::zeros);
}
struct ObjectiveF1
{
ObjectiveF1(ZDT2& zdtClass) : zdtClass(zdtClass)
{/*Nothing to do here */}
typename MatType::elem_type Evaluate(const MatType& coords)
{
return coords[0];
}
ZDT2& zdtClass;
};
struct ObjectiveF2
{
ObjectiveF2(ZDT2& zdtClass) : zdtClass(zdtClass)
{/*Nothing to do here */}
typename MatType::elem_type Evaluate(const MatType& coords)
{
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
size_t numVariables = zdtClass.numVariables;
ElemType sum = arma::accu(coords(arma::span(1, numVariables - 1), 0));
ElemType g = 1. + 9. * sum / (static_cast<ElemType>(numVariables - 1));
ElemType objectiveRatio = zdtClass.objectiveF1.Evaluate(coords) / g;
return g * (1. - std::pow(objectiveRatio, 2));
}
ZDT2& zdtClass;
};
//! Get objective functions.
std::tuple<ObjectiveF1, ObjectiveF2> GetObjectives()
{
return std::make_tuple(objectiveF1, objectiveF2);
}
//! Get the Reference Front.
//! Refer PR #273 Ipynb notebook to see the plot of Reference
//! Front. The implementation has been taken from pymoo.
arma::cube GetReferenceFront()
{
arma::cube front(2, 1, numParetoPoints);
arma::vec x = arma::linspace(0, 1, numParetoPoints);
arma::vec y = 1 - arma::square(x);
for (size_t idx = 0; idx < numParetoPoints; ++idx)
front.slice(idx) = arma::vec{ x(idx), y(idx) };
return front;
}
ObjectiveF1 objectiveF1;
ObjectiveF2 objectiveF2;
};
} //namespace test
} //namespace ens
#endif
@@ -0,0 +1,188 @@
/**
* @file zdt3_function.hpp
* @author Nanubala Gnana Sai
*
* Implementation of the third ZDT(Zitzler, Deb and Thiele) test.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_PROBLEMS_ZDT_THREE_FUNCTION_HPP
#define ENSMALLEN_PROBLEMS_ZDT_THREE_FUNCTION_HPP
namespace ens {
namespace test {
/**
* The ZDT3 function, defined by:
* \f[
* g(x) = 1 + 9(\sum_{i=2}^{n} x_i )/(n-1)
* f_1(x) = x_1
* h(f_1,g) = 1 - \sqrt{f_1/g} - (f_1/g)sin(10\pi f_1)
* f_2(x) = g(x) * h(f_1, g)
* \f]
*
* This is a 30-variable problem(n = 30) with a number
* of disconnected optimal fronts.
*
* Bounds of the variable space is:
* 0 <= x_i <= 1 for i = 1,...,n.
*
* This should be optimized to g(x) = 1.0, at:
*
* x_1* in [0.0000, 0.0830] OR
* x_1* in [0.1822, 0.2577] OR
* x_1* in [0.4093, 0.4538] OR
* x_1* in [0.6183, 0.6525] OR
* x_1* in [0.8233, 0.8518].
*
* x_i* = 0 for i = 2,...,n.
*
* For more information, please refer to:
*
* @code
* @article{Zitzler2000,
* title = {Comparison of multiobjective evolutionary algorithms:
* Empirical results},
* author = {Zitzler, Eckart and Deb, Kalyanmoy and Thiele, Lothar},
* journal = {Evolutionary computation},
* year = {2000},
* doi = {10.1162/106365600568202}
* }
* @endcode
*
* @tparam MatType Type of matrix to optimize.
*/
template<typename MatType = arma::mat>
class ZDT3
{
private:
size_t numParetoPoints {100};
size_t numObjectives {2};
size_t numVariables {30};
public:
//! Initialize the ZDT3
ZDT3(size_t numParetoPoints = 100) :
numParetoPoints(numParetoPoints),
objectiveF1(*this),
objectiveF2(*this)
{/* Nothing to do here. */}
/**
* Evaluate the objectives with the given coordinate.
*
* @param coords The function coordinates.
* @return arma::Col<typename MatType::elem_type>
*/
arma::Col<typename MatType::elem_type> Evaluate(const MatType& coords)
{
typedef typename MatType::elem_type ElemType;
arma::Col<ElemType> objectives(numObjectives);
objectives(0) = coords[0];
ElemType sum = arma::accu(coords(arma::span(1, numVariables - 1), 0));
ElemType g = 1. + 9. * sum / (static_cast<ElemType>(numVariables) - 1.);
ElemType objectiveRatio = objectives(0) / g;
objectives(1) = g * (1. - std::sqrt(objectiveRatio) -
(objectiveRatio) * std::sin(10. * arma::datum::pi * coords[0]));
return objectives;
}
//! Get the starting point.
MatType GetInitialPoint()
{
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
return arma::Col<ElemType>(numVariables, 1, arma::fill::zeros);
}
struct ObjectiveF1
{
ObjectiveF1(ZDT3& zdtClass) : zdtClass(zdtClass)
{/*Nothing to do here */}
typename MatType::elem_type Evaluate(const MatType& coords)
{
return coords[0];
}
ZDT3& zdtClass;
};
struct ObjectiveF2
{
ObjectiveF2(ZDT3& zdtClass) : zdtClass(zdtClass)
{/*Nothing to do here */}
typename MatType::elem_type Evaluate(const MatType& coords)
{
typedef typename MatType::elem_type ElemType;
size_t numVariables = zdtClass.numVariables;
ElemType sum = arma::accu(coords(arma::span(1, numVariables - 1), 0));
ElemType g = 1. + 9. * sum / (static_cast<ElemType>(numVariables - 1));
ElemType objectiveRatio = zdtClass.objectiveF1.Evaluate(coords) / g;
return g * (1. - std::sqrt(objectiveRatio) -
(objectiveRatio) * std::sin(10. * arma::datum::pi * coords[0]));
}
ZDT3& zdtClass;
};
//! Get objective functions.
std::tuple<ObjectiveF1, ObjectiveF2> GetObjectives()
{
return std::make_tuple(objectiveF1, objectiveF2);
}
//! Get the Reference Front.
//! Refer PR #273 Ipynb notebook to see the plot of Reference
//! Front. The implementation has been taken from pymoo.
arma::cube GetReferenceFront()
{
size_t numRegions = 5;
size_t regionDensity = std::floor(numParetoPoints / numRegions);
size_t apparentParetoPoints = numRegions * regionDensity;
arma::cube front(2, 1, apparentParetoPoints);
arma::mat regions{
{0.0, 0.182228780, 0.4093136748,
0.6183967944, 0.8233317983},
{0.0830015349, 0.2577623634, 0.4538821041,
0.6525117038, 0.8518328654}
};
for (size_t regionIdx = 0; regionIdx < numRegions; ++regionIdx)
{
arma::vec region = regions.col(regionIdx);
//! Generate x and y coordinates for the region.
arma::vec x = arma::linspace(
region(0), region(1), regionDensity);
arma::vec y = 1 - arma::sqrt(x) - x
% arma::sin(10 * arma::datum::pi * x);
//! Fill the front with the generated points.
for (size_t pointIdx = 0; pointIdx < regionDensity; ++pointIdx)
{
size_t sliceIdx = regionIdx * regionDensity + pointIdx;
front.slice(sliceIdx) = arma::vec{ x(pointIdx), y(pointIdx) };
}
}
return front;
}
ObjectiveF1 objectiveF1;
ObjectiveF2 objectiveF2;
};
} //namespace test
} //namespace ens
#endif
@@ -0,0 +1,160 @@
/**
* @file zdt4_function.hpp
* @author Nanubala Gnana Sai
*
* Implementation of the fourth ZDT(Zitzler, Deb and Thiele) test.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_PROBLEMS_ZDT_FOUR_FUNCTION_HPP
#define ENSMALLEN_PROBLEMS_ZDT_FOUR_FUNCTION_HPP
namespace ens {
namespace test {
/**
* The ZDT4 function, defined by:
* \f[
* g(x) = 1 + 10(n-1) + \sum_{i=2}^{n}(x_i^2 - 10cos(4\pi x_i))
* f_1(x) = x_i
* h(f_1,g) = 1 - \sqrt{f_i/g}
* f_2(x) = g(x) * h(f_1, g)
* \f]
*
* This is a 10-variable problem(n = 10) with a convex
* optimal front. This problem contains several local
* optimum, making it difficult to reach the global optimum.
*
* Bounds of the variable space is:
* 0 <= x_1 <= 1;
* -10 <= x_i <= 10 for i = 2,...,n.
*
* This should be optimized to g(x) = 1.0, at:
* x_1* in [0, 1] ; x_i* = 0 for i = 2,...,n
*
* For more information, please refer to:
*
* @code
* @article{Zitzler2000,
* title = {Comparison of multiobjective evolutionary algorithms:
* Empirical results},
* author = {Zitzler, Eckart and Deb, Kalyanmoy and Thiele, Lothar},
* journal = {Evolutionary computation},
* year = {2000},
* doi = {10.1162/106365600568202}
* }
* @endcode
*
* @tparam MatType Type of matrix to optimize.
*/
template<typename MatType = arma::mat>
class ZDT4
{
private:
size_t numParetoPoints {100};
size_t numObjectives {2};
size_t numVariables {10};
public:
//! Initialize the ZDT4
ZDT4(size_t numParetoPoints = 100) :
numParetoPoints(numParetoPoints),
objectiveF1(*this),
objectiveF2(*this)
{/* Nothing to do here. */}
/**
* Evaluate the objectives with the given coordinate.
*
* @param coords The function coordinates.
* @return arma::Col<typename MatType::elem_type>
*/
arma::Col<typename MatType::elem_type> Evaluate(const MatType& coords)
{
typedef typename MatType::elem_type ElemType;
arma::Col<ElemType> objectives(numObjectives);
objectives(0) = coords[0];
MatType truncatedCoords = coords(arma::span(1, numVariables - 1), 0);
ElemType sum = arma::accu(arma::square(truncatedCoords) -
10. * arma::cos(4 * arma::datum::pi * truncatedCoords));
ElemType g = 1. + 10. * static_cast<ElemType>(numVariables - 1) + sum;
ElemType objectiveRatio = objectives(0) / g;
objectives(1) = g * (1. - std::sqrt(objectiveRatio));
return objectives;
}
//! Get the starting point.
MatType GetInitialPoint()
{
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
return arma::Col<ElemType>(numVariables, 1, arma::fill::zeros);
}
struct ObjectiveF1
{
ObjectiveF1(ZDT4& zdtClass) : zdtClass(zdtClass)
{/*Nothing to do here */}
typename MatType::elem_type Evaluate(const MatType& coords)
{
return coords[0];
}
ZDT4& zdtClass;
};
struct ObjectiveF2
{
ObjectiveF2(ZDT4& zdtClass) : zdtClass(zdtClass)
{/*Nothing to do here */}
typename MatType::elem_type Evaluate(const MatType& coords)
{
typedef typename MatType::elem_type ElemType;
size_t numVariables = zdtClass.numVariables;
MatType truncatedCoords = coords(arma::span(1, numVariables - 1), 0);
ElemType sum = arma::accu(arma::square(truncatedCoords) -
10. * arma::cos(4 * arma::datum::pi * truncatedCoords));
ElemType g = 1. + 10 * static_cast<ElemType>(numVariables - 1) + sum;
ElemType objectiveRatio = zdtClass.objectiveF1.Evaluate(coords) / g;
return g * (1. - std::sqrt(objectiveRatio));
}
ZDT4& zdtClass;
};
//! Get objective functions.
std::tuple<ObjectiveF1, ObjectiveF2> GetObjectives()
{
return std::make_tuple(objectiveF1, objectiveF2);
}
//! Get the Reference Front.
//! Refer PR #273 Ipynb notebook to see the plot of Reference
//! Front. The implementation has been taken from pymoo.
arma::cube GetReferenceFront()
{
arma::cube front(2, 1, numParetoPoints);
arma::vec x = arma::linspace(0, 1, numParetoPoints);
arma::vec y = 1 - arma::sqrt(x);
for (size_t idx = 0; idx < numParetoPoints; ++idx)
front.slice(idx) = arma::vec{ x(idx), y(idx) };
return front;
}
ObjectiveF1 objectiveF1;
ObjectiveF2 objectiveF2;
};
} //namespace test
} //namespace ens
#endif
@@ -0,0 +1,162 @@
/**
* @file zdt6_function.hpp
* @author Nanubala Gnana Sai
*
* Implementation of the sixth ZDT(Zitzler, Deb and Thiele) test.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_PROBLEMS_ZDT_SIX_FUNCTION_HPP
#define ENSMALLEN_PROBLEMS_ZDT_SIX_FUNCTION_HPP
namespace ens {
namespace test {
/**
* The ZDT6 function, defined by:
* \f[
* g(x) = 1 + 9[ \sum_{i=2}^{n}(x_i^2)/9]^{0.25}
* f_1(x) = 1 - e^{-4x_1}sin^{6}(6\pi x_1)
* h(f1, g) = 1 - (f_1/g)^{2}
* f_2(x) = g(x) * h(f_1, g)
* \f]
*
* This is a 10-variable problem(n = 10) with a
* non-convex optimal front. The density of the
* solutions across optimal region is non-uniform.
*
* Bounds of the variable space is:
* 0 <= x_i <= 1 for i = 1,...,n
*
* This should be optimized to g(x) = 1.0, at:
* x_1* in [0, 1] ; x_i* = 0 for i = 2,...,n
*
*
* For more information, please refer to:
*
* @code
* @article{Zitzler2000,
* title = {Comparison of multiobjective evolutionary algorithms:
* Empirical results},
* author = {Zitzler, Eckart and Deb, Kalyanmoy and Thiele, Lothar},
* journal = {Evolutionary computation},
* year = {2000},
* doi = {10.1162/106365600568202}
* }
* @endcode
*
* @tparam MatType Type of matrix to optimize.
*/
template<typename MatType = arma::mat>
class ZDT6
{
private:
size_t numParetoPoints {100};
size_t numObjectives {2};
size_t numVariables {10};
public:
//! Initialize the ZDT6
ZDT6(size_t numParetoPoints = 100) :
numParetoPoints(numParetoPoints),
objectiveF1(*this),
objectiveF2(*this)
{/* Nothing to do here. */}
/**
* Evaluate the objectives with the given coordinate.
*
* @param coords The function coordinates.
* @return arma::Col<typename MatType::elem_type>
*/
arma::Col<typename MatType::elem_type> Evaluate(const MatType& coords)
{
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
arma::Col<ElemType> objectives(numObjectives);
objectives(0) = 1. - std::exp(-4 * coords[0]) *
std::pow(std::sin(6 * arma::datum::pi * coords[0]), 6);
ElemType sum = std::pow(
arma::accu(coords(arma::span(1, numVariables - 1), 0)) / 9, 0.25);
ElemType g = 1. + 9. * sum;
ElemType objectiveRatio = objectives(0) / g;
objectives(1) = g * (1. - std::pow(objectiveRatio, 2));
return objectives;
}
//! Get the starting point.
MatType GetInitialPoint()
{
// Convenience typedef.
typedef typename MatType::elem_type ElemType;
return arma::Col<ElemType>(numVariables, 1, arma::fill::zeros);
}
struct ObjectiveF1
{
ObjectiveF1(ZDT6& zdtClass) : zdtClass(zdtClass)
{/*Nothing to do here */}
typename MatType::elem_type Evaluate(const MatType& coords)
{
return 1. - std::exp(-4. * coords[0]) *
std::pow(std::sin(6. * arma::datum::pi * coords[0]), 6.);
}
ZDT6& zdtClass;
};
struct ObjectiveF2
{
ObjectiveF2(ZDT6& zdtClass) : zdtClass(zdtClass)
{/*Nothing to do here */}
typename MatType::elem_type Evaluate(const MatType& coords)
{
typedef typename MatType::elem_type ElemType;
size_t numVariables = zdtClass.numVariables;
ElemType sum = std::pow(
arma::accu(coords(arma::span(1, numVariables - 1), 0)) / 9, 0.25);
ElemType g = 1. + 9. * sum;
ElemType objectiveRatio = zdtClass.objectiveF1.Evaluate(coords) / g;
return g * (1. - std::pow(objectiveRatio, 2));
}
ZDT6& zdtClass;
};
//! Get objective functions.
std::tuple<ObjectiveF1, ObjectiveF2> GetObjectives()
{
return std::make_tuple(objectiveF1, objectiveF2);
}
//! Get the Reference Front.
//! Refer PR #273 Ipynb notebook to see the plot of Reference
//! Front. The implementation has been taken from pymoo.
arma::cube GetReferenceFront()
{
arma::cube front(2, 1, numParetoPoints);
arma::vec x = arma::linspace(0.2807753191, 1, numParetoPoints);
arma::vec y = 1 - arma::square(x);
for (size_t idx = 0; idx < numParetoPoints; ++idx)
front.slice(idx) = arma::vec{ x(idx), y(idx) };
return front;
}
ObjectiveF1 objectiveF1;
ObjectiveF2 objectiveF2;
};
} //namespace test
} //namespace ens
#endif
@@ -73,7 +73,8 @@ class LBestUpdate
*
* @param parent Instantiated parent class.
*/
Policy(const LBestUpdate& /* parent */) { /* Do nothing. */ }
Policy(const LBestUpdate& /* parent */) : n(0)
{ /* Do nothing. */ }
/**
* The Initialize method is called by PSO Optimizer method before the
@@ -54,8 +54,7 @@ class QHAdamUpdate
beta1(beta1),
beta2(beta2),
v1(v1),
v2(v2),
iteration(0)
v2(v2)
{
// Nothing to do.
}
@@ -75,11 +74,6 @@ class QHAdamUpdate
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
//! Get the first quasi-hyperbolic term.
double V1() const { return v1; }
//! Modify the first quasi-hyperbolic term.
@@ -109,7 +103,8 @@ class QHAdamUpdate
* @param cols Number of columns in the gradient matrix.
*/
Policy(QHAdamUpdate& parent, const size_t rows, const size_t cols) :
parent(parent)
parent(parent),
iteration(0)
{
m.zeros(rows, cols);
v.zeros(rows, cols);
@@ -127,7 +122,7 @@ class QHAdamUpdate
const GradType& gradient)
{
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
// And update the iterate.
m *= parent.beta1;
@@ -136,10 +131,8 @@ class QHAdamUpdate
v *= parent.beta2;
v += (1 - parent.beta2) * (gradient % gradient);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1,
parent.iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2,
parent.iteration);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
GradType mDash = m / biasCorrection1;
GradType vDash = v / biasCorrection2;
@@ -160,6 +153,9 @@ class QHAdamUpdate
// The exponential moving average of squared gradient values.
GradType v;
// The number of iterations.
size_t iteration;
};
private:
@@ -177,9 +173,6 @@ class QHAdamUpdate
// The second quasi-hyperbolic term.
double v2;
// The number of iterations.
size_t iteration;
};
} // namespace ens
+2 -2
View File
@@ -70,13 +70,13 @@ typename MatType::elem_type SA<CoolingScheduleType>::Optimize(
ElemType energy = function.Evaluate(iterate);
Callback::Evaluate(*this, function, iterate, energy, callbacks...);
ElemType oldEnergy = energy;
ElemType oldEnergy;
size_t idx = 0;
size_t sweepCounter = 0;
BaseMatType accept(rows, cols, arma::fill::zeros);
BaseMatType moveSize(rows, cols);
BaseMatType moveSize(rows, cols, arma::fill::none);
moveSize.fill(initMoveCoef);
terminate |= Callback::BeginOptimization(*this, function, iterate,
@@ -89,11 +89,6 @@ SARAHType<UpdatePolicyType>::Optimize(
BaseGradType gradient0(iterate.n_rows, iterate.n_cols);
BaseMatType iterate0;
// Find the number of batches.
size_t numBatches = numFunctions / batchSize;
if (numFunctions % batchSize != 0)
++numBatches; // Capture last few.
const size_t actualMaxIterations = (maxIterations == 0) ?
std::numeric_limits<size_t>::max() : maxIterations;
terminate |= Callback::BeginOptimization(*this, function, iterate,
@@ -162,8 +162,8 @@ SolveKKTSystem(const SparseConstraintType& aSparse,
"solve KKT system.");
}
MatType subTerm(aSparse.n_cols, 1);
subTerm.zeros();
MatType subTerm(aSparse.n_cols, 1, arma::fill::zeros);
if (aSparse.n_rows)
{
dySparse = dy(arma::span(0, aSparse.n_rows - 1), 0);
@@ -303,7 +303,7 @@ typename MatType::elem_type PrimalDualSolver::Optimize(
eInvFaSparseT.set_size(n2bar, sdp.NumSparseConstraints());
eInvFaDenseT.set_size(n2bar, sdp.NumDenseConstraints());
m.set_size(sdp.NumConstraints(), sdp.NumConstraints());
m.zeros(sdp.NumConstraints(), sdp.NumConstraints());
// Controls early termination of the optimization process.
bool terminate = false;
@@ -64,6 +64,7 @@ class SnapshotEnsembles
constStepSize(stepSize),
nextRestart(epochRestart),
batchRestart(0),
epochBatches(0),
epoch(0)
{
snapshotEpochs = 0;
@@ -178,7 +178,6 @@ SPALeRASGD<DecayPolicyType>::Optimize(
i += effectiveBatchSize;
currentFunction += effectiveBatchSize;
overallObjective += currentObjective;
currentObjective /= effectiveBatchSize;
// Is this iteration the start of a sequence?
if ((currentFunction % numFunctions) == 0)
@@ -52,7 +52,8 @@ class SPALeRAStepsize
const double adaptRate = 3.10e-8) :
alpha(alpha),
epsilon(epsilon),
adaptRate(adaptRate)
adaptRate(adaptRate),
lambda(0)
{
/* Nothing to do here. */
}
+9 -17
View File
@@ -50,7 +50,6 @@ class SWATSUpdate
epsilon(epsilon),
beta1(beta1),
beta2(beta2),
iteration(0),
phaseSGD(false),
sgdRate(0),
sgdLambda(0)
@@ -73,11 +72,6 @@ class SWATSUpdate
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
//! Get the current iteration number.
size_t Iteration() const { return iteration; }
//! Modify the current iteration number.
size_t& Iteration() { return iteration; }
//! Get whether the current phase is SGD.
bool PhaseSGD() const { return phaseSGD; }
//! Modify whether the current phase is SGD.
@@ -111,7 +105,8 @@ class SWATSUpdate
* @param cols Number of columns in the gradient matrix.
*/
Policy(SWATSUpdate& parent, const size_t rows, const size_t cols) :
parent(parent)
parent(parent),
iteration(0)
{
m.zeros(rows, cols);
v.zeros(rows, cols);
@@ -131,7 +126,7 @@ class SWATSUpdate
const GradType& gradient)
{
// Increment the iteration counter variable.
++parent.iteration;
++iteration;
if (parent.phaseSGD)
{
@@ -150,10 +145,8 @@ class SWATSUpdate
v *= parent.beta2;
v += (1 - parent.beta2) * (gradient % gradient);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1,
parent.iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2,
parent.iteration);
const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
GradType delta = stepSize * m / biasCorrection1 /
(arma::sqrt(v / biasCorrection2) + parent.epsilon);
@@ -167,8 +160,7 @@ class SWATSUpdate
(1 - parent.beta2) * rate;
parent.sgdRate = parent.sgdLambda / biasCorrection2;
if (std::abs(parent.sgdRate - rate) < parent.epsilon &&
parent.iteration > 1)
if (std::abs(parent.sgdRate - rate) < parent.epsilon && iteration > 1)
{
parent.phaseSGD = true;
v.zeros();
@@ -188,6 +180,9 @@ class SWATSUpdate
//! The exponential moving average of squared gradient values (SGD).
GradType sgdV;
//! The number of iterations.
size_t iteration;
};
private:
@@ -200,9 +195,6 @@ class SWATSUpdate
//! The second moment coefficient.
double beta2;
//! The number of iterations.
size_t iteration;
//! Wether to use the SGD or Adam update rule.
bool phaseSGD;
@@ -0,0 +1,92 @@
/**
* @file epsilon.hpp
* @author Rahul Ganesh Prabhu
* @author Nanubala Gnana Sai
*
* Epsilon indicator
* A binary quality indicator that is capable of detecting whether one
* approximation set is better than another.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_INDICATORS_EPSILON_HPP
#define ENSMALLEN_INDICATORS_EPSILON_HPP
namespace ens {
/**
* The epsilon indicator is one of the binary quality indicators that was proposed by
* Zitzler et. al.. The indicator originally calculates a weak dominance relation
* between two approximation sets. It returns "epsilon" which is the factor by which
* the given approximation set is worse than the reference front with respect to
* all the objectives.
*
* \f[ I_{\epsilon}(A,B) = \max_{z^2 \in B} \
* \min_{z^1 \in A} \
* \max_{1 \leq i \leq n} \ \frac{z^1_i}{z^2_i}\
* \f]
*
* For more information, please see:
*
* @code
* @article{1197687,
* author = {E. Zitzler and L. Thiele and M. Laumanns and C. M. Fonseca and
* V. G. da Fonseca},
* title = {Performance assessment of multiobjective optimizers: an
* analysis and review},
* journal = {IEEE Transactions on Evolutionary Computation},
* year = {2003},
* }
* @endcode
*/
class Epsilon
{
public:
/**
* Default constructor does nothing, but is required to satisfy the Indicator
* policy.
*/
Epsilon() { }
/**
* Find the epsilon value of the front with respect to the given reference
* front.
*
* @tparam CubeType The cube data type of front.
* @param front The given approximation front.
* @param referenceFront The given reference front.
* @return The epsilon value of the front.
*/
template<typename CubeType>
static typename CubeType::elem_type Evaluate(const CubeType& front,
const CubeType& referenceFront)
{
// Convenience typedefs.
typedef typename CubeType::elem_type ElemType;
ElemType eps = 0;
for (size_t i = 0; i < referenceFront.n_slices; i++)
{
ElemType epsjMin = std::numeric_limits<ElemType>::max();
for (size_t j = 0; j < front.n_slices; j++)
{
arma::Mat<ElemType> frontRatio = front.slice(j) / referenceFront.slice(i);
frontRatio.replace(arma::datum::inf, -1.); // Handle zero division case.
ElemType epsj = frontRatio.max();
if (epsj < epsjMin)
epsjMin = epsj;
}
if (epsjMin > eps)
eps = epsjMin;
}
return eps;
}
};
} // namespace ens
#endif
@@ -0,0 +1,94 @@
/**
* @file igd_plus.hpp
* @author Rahul Ganesh Prabhu
* @author Nanubala Gnana Sai
*
* Inverse Generational Distance Plus (IGD+) indicator.
* The average distance from each reference point to its nearest solution.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_INDICATORS_IGD_PLUS_HPP
#define ENSMALLEN_INDICATORS_IGD_PLUS_HPP
namespace ens {
/**
* The IGD indicator returns the average distance from each point in the reference
* front to the nearest point to it's solution. IGD+ is an improvement upon
* the IGD indicator, which fixes misleading results given by IGD in certain
* cases via a different distance metric:
*
* \f[ d^{+}(z,a) = \sqrt{\sum_{i = 1}^{n}( \max\{a_i - z_i, 0\})^2 \ } \
* \f]
*
* For more information see:
*
* @code
* @article{10.1007/978-3-319-15892-1_8,
* author = {Ishibuchi, Hisao and Masuda, Hiroyuki and Tanigaki, Yuki
* and Nojima, Yusuke},
* title = {Modified Distance Calculation in Generational Distance
* and Inverted Generational Distance},
* book = {Evolutionary Multi-Criterion Optimization}
* year = {2015}
* }
* @endcode
*/
class IGDPlus
{
public:
/**
* Default constructor does nothing, but is required to satisfy the Indicator
* policy.
*/
IGDPlus() { }
/**
* Find the IGD+ value of the front with respect to the given reference
* front.
*
* @tparam CubeType The cube data type of front.
* @param front The given approximation front.
* @param referenceFront The given reference front.
* @return The IGD value of the front.
*/
template<typename CubeType>
static typename CubeType::elem_type Evaluate(const CubeType& front,
const CubeType& referenceFront)
{
// Convenience typedefs.
typedef typename CubeType::elem_type ElemType;
ElemType igd = 0;
for (size_t i = 0; i < referenceFront.n_slices; i++)
{
ElemType min = std::numeric_limits<ElemType>::max();
for (size_t j = 0; j < front.n_slices; j++)
{
ElemType dist = 0;
for (size_t k = 0; k < front.slice(j).n_rows; k++)
{
ElemType z = referenceFront(k, 0, i);
ElemType a = front(k, 0, j);
// Assuming minimization of all objectives.
dist += std::pow(std::max<ElemType>(a - z, 0), 2);
}
dist = std::sqrt(dist);
if (dist < min)
min = dist;
}
igd += min;
}
igd /= referenceFront.n_slices;
return igd;
}
};
} // namespace ens
#endif
+189
View File
@@ -0,0 +1,189 @@
/**
* @file yogi.hpp
* @author Marcus Edel
*
* Class wrapper for the Yogi update Policy. Yogi is based on Adam with more
* fine grained effective learning rate control.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_YOGI_YOGI_HPP
#define ENSMALLEN_YOGI_YOGI_HPP
#include <ensmallen_bits/sgd/sgd.hpp>
#include "yogi_update.hpp"
namespace ens {
/**
* Yogi is an variation of Adam with more fine grained effective learning rate
* control.
*
* For more information, see the following.
*
* @code
* @inproceedings{Zaheer2018,
* author = {Zaheer, Manzil and Reddi, Sashank J. and Sachan, Devendra
* and Kale, Satyen and Kumar, Sanjiv},
* title = {Adaptive Methods for Nonconvex Optimization},
* year = {2018},
* publisher = {Curran Associates Inc.},
* booktitle = {Proceedings of the 32nd International Conference on Neural
* Information Processing Systems},
* pages = {98159825},
* series = {NIPS'18}
* }
* @endcode
*
* Yogi can optimize differentiable separable functions. For more details,
* see the documentation on function types included with this distribution or
* on the ensmallen website.
*/
class Yogi
{
public:
/**
* Construct the Yogi optimizer with the given function and parameters.
* Yogi is sensitive to its paramters and hence a good hyper paramater
* selection is necessary as its default may not fit every case.
*
* The maximum number of iterations refers to the maximum number of
* points that are processed (i.e., one iteration equals one point; one
* iteration does not equal one pass over the dataset).
*
* @param stepSize Step size for each iteration.
* @param batchSize Number of points to process in a single step.
* @param beta1 Exponential decay rate for the first moment estimates.
* @param beta2 Exponential decay rate for the weighted infinity norm
* estimates.
* @param epsilon Value used to initialise the mean squared gradient
* parameter.
* @param maxIterations Maximum number of iterations allowed (0 means no
* limit).
* @param tolerance Maximum absolute tolerance to terminate algorithm.
* @param shuffle If true, the function order is shuffled; otherwise, each
* function is visited in linear order.
* @param resetPolicy If true, parameters are reset before every Optimize
* call; otherwise, their values are retained.
* @param exactObjective Calculate the exact objective (Default: estimate the
* final objective obtained on the last pass over the data).
*/
Yogi(const double stepSize = 0.001,
const size_t batchSize = 32,
const double beta1 = 0.9,
const double beta2 = 0.999,
const double epsilon = 1e-8,
const size_t maxIterations = 100000,
const double tolerance = 1e-5,
const bool shuffle = true,
const bool resetPolicy = true,
const bool exactObjective = false);
/**
* Optimize the given function using Yogi. The given starting point will be
* modified to store the finishing point of the algorithm, and the final
* objective value is returned.
*
* @tparam SeparableFunctionType Type of the function to optimize.
* @tparam MatType Type of matrix to optimize with.
* @tparam GradType Type of matrix to use to represent function gradients.
* @tparam CallbackTypes Types of callback functions.
* @param function Function to optimize.
* @param iterate Starting point (will be modified).
* @param callbacks Callback functions.
* @return Objective value of the final point.
*/
template<typename SeparableFunctionType,
typename MatType,
typename GradType,
typename... CallbackTypes>
typename std::enable_if<IsArmaType<GradType>::value,
typename MatType::elem_type>::type
Optimize(SeparableFunctionType& function,
MatType& iterate,
CallbackTypes&&... callbacks)
{
return optimizer.Optimize<SeparableFunctionType, MatType, GradType,
CallbackTypes...>(function, iterate,
std::forward<CallbackTypes>(callbacks)...);
}
//! Forward the MatType as GradType.
template<typename SeparableFunctionType,
typename MatType,
typename... CallbackTypes>
typename MatType::elem_type Optimize(SeparableFunctionType& function,
MatType& iterate,
CallbackTypes&&... callbacks)
{
return Optimize<SeparableFunctionType, MatType, MatType,
CallbackTypes...>(function, iterate,
std::forward<CallbackTypes>(callbacks)...);
}
//! Get the step size.
double StepSize() const { return optimizer.StepSize(); }
//! Modify the step size.
double& StepSize() { return optimizer.StepSize(); }
//! Get the batch size.
size_t BatchSize() const { return optimizer.BatchSize(); }
//! Modify the batch size.
size_t& BatchSize() { return optimizer.BatchSize(); }
//! Get the smoothing parameter.
double Beta1() const { return optimizer.UpdatePolicy().Beta1(); }
//! Modify the smoothing parameter.
double& Beta1() { return optimizer.UpdatePolicy().Beta1(); }
//! Get the second moment coefficient.
double Beta2() const { return optimizer.UpdatePolicy().Beta2(); }
//! Modify the second moment coefficient.
double& Beta2() { return optimizer.UpdatePolicy().Beta2(); }
//! Get the value used to initialise the mean squared gradient parameter.
double Epsilon() const { return optimizer.UpdatePolicy().Epsilon(); }
//! Modify the value used to initialise the mean squared gradient parameter.
double& Epsilon() { return optimizer.UpdatePolicy().Epsilon(); }
//! Get the maximum number of iterations (0 indicates no limit).
size_t MaxIterations() const { return optimizer.MaxIterations(); }
//! Modify the maximum number of iterations (0 indicates no limit).
size_t& MaxIterations() { return optimizer.MaxIterations(); }
//! Get the tolerance for termination.
double Tolerance() const { return optimizer.Tolerance(); }
//! Modify the tolerance for termination.
double& Tolerance() { return optimizer.Tolerance(); }
//! Get whether or not the individual functions are shuffled.
bool Shuffle() const { return optimizer.Shuffle(); }
//! Modify whether or not the individual functions are shuffled.
bool& Shuffle() { return optimizer.Shuffle(); }
//! Get whether or not the actual objective is calculated.
bool ExactObjective() const { return optimizer.ExactObjective(); }
//! Modify whether or not the actual objective is calculated.
bool& ExactObjective() { return optimizer.ExactObjective(); }
//! Get whether or not the update policy parameters are reset before
//! Optimize call.
bool ResetPolicy() const { return optimizer.ResetPolicy(); }
//! Modify whether or not the update policy parameters
//! are reset before Optimize call.
bool& ResetPolicy() { return optimizer.ResetPolicy(); }
private:
//! The Stochastic Gradient Descent object with Yogi policy.
SGD<YogiUpdate> optimizer;
};
} // namespace ens
// Include implementation.
#include "yogi_impl.hpp"
#endif
+44
View File
@@ -0,0 +1,44 @@
/**
* @file yogi_impl.hpp
* @author Marcus Edel
*
* Implementation of Yogi class wrapper.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_YOGI_YOGI_IMPL_HPP
#define ENSMALLEN_YOGI_YOGI_IMPL_HPP
// In case it hasn't been included yet.
#include "yogi.hpp"
namespace ens {
inline Yogi::Yogi(
const double stepSize,
const size_t batchSize,
const double beta1,
const double beta2,
const double epsilon,
const size_t maxIterations,
const double tolerance,
const bool shuffle,
const bool resetPolicy,
const bool exactObjective) :
optimizer(stepSize,
batchSize,
maxIterations,
tolerance,
shuffle,
YogiUpdate(epsilon, beta1, beta2),
NoDecay(),
resetPolicy,
exactObjective)
{ /* Nothing to do. */ }
} // namespace ens
#endif
+146
View File
@@ -0,0 +1,146 @@
/**
* @file yogi_update.hpp
* @author Marcus Edel
*
* Implements the Yogi Optimizer. Yogi is a variant of Adam with more fine
* grained effective learning rate control.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef ENSMALLEN_YOGI_YOGI_UPDATE_HPP
#define ENSMALLEN_YOGI_YOGI_UPDATE_HPP
namespace ens {
/**
* Yogi builds upon the Adam update strategy but provides more fine grained
* effective learning rate control.
*
* For more information, see the following.
*
* @code
* @inproceedings{Zaheer2018,
* author = {Zaheer, Manzil and Reddi, Sashank J. and Sachan, Devendra
* and Kale, Satyen and Kumar, Sanjiv},
* title = {Adaptive Methods for Nonconvex Optimization},
* year = {2018},
* publisher = {Curran Associates Inc.},
* booktitle = {Proceedings of the 32nd International Conference on Neural
* Information Processing Systems},
* pages = {98159825},
* series = {NIPS'18}
* }
* @endcode
*/
class YogiUpdate
{
public:
/**
* Construct the Yogi update policy with the given parameters.
*
* @param epsilon The epsilon value used to initialise the squared gradient
* parameter.
* @param beta1 The smoothing parameter.
* @param beta2 The second moment coefficient.
* @param v1 The first quasi-hyperbolic term.
* @param v1 The second quasi-hyperbolic term.
*/
YogiUpdate(const double epsilon = 1e-8,
const double beta1 = 0.9,
const double beta2 = 0.999) :
epsilon(epsilon),
beta1(beta1),
beta2(beta2)
{
// Nothing to do.
}
//! Get the value used to initialise the squared gradient parameter.
double Epsilon() const { return epsilon; }
//! Modify the value used to initialise the squared gradient parameter.
double& Epsilon() { return epsilon; }
//! Get the smoothing parameter.
double Beta1() const { return beta1; }
//! Modify the smoothing parameter.
double& Beta1() { return beta1; }
//! Get the second moment coefficient.
double Beta2() const { return beta2; }
//! Modify the second moment coefficient.
double& Beta2() { return beta2; }
/**
* The UpdatePolicyType policy classes must contain an internal 'Policy'
* template class with two template arguments: MatType and GradType. This is
* instantiated at the start of the optimization, and holds parameters
* specific to an individual optimization.
*/
template<typename MatType, typename GradType>
class Policy
{
public:
/**
* This constructor is called by the SGD Optimize() method before the start
* of the iteration update process.
*
* @param parent YogiUpdate object.
* @param rows Number of rows in the gradient matrix.
* @param cols Number of columns in the gradient matrix.
*/
Policy(YogiUpdate& parent, const size_t rows, const size_t cols) :
parent(parent)
{
m.zeros(rows, cols);
v.zeros(rows, cols);
}
/**
* Update step for Yogi.
*
* @param iterate Parameters that minimize the function.
* @param stepSize Step size to be used for the given iteration.
* @param gradient The gradient matrix.
*/
void Update(MatType& iterate,
const double stepSize,
const GradType& gradient)
{
m *= parent.beta1;
m += (1 - parent.beta1) * gradient;
const MatType gSquared = arma::square(gradient);
v -= (1 - parent.beta2) * arma::sign(v - gSquared) % gSquared;
// Now update the iterate.
iterate -= stepSize * m / (arma::sqrt(v) + parent.epsilon);
}
private:
//! Instantiated parent object.
YogiUpdate& parent;
//! The exponential moving average of gradient values.
GradType m;
// The exponential moving average of squared gradient values.
GradType v;
};
private:
// The epsilon value used to initialise the squared gradient parameter.
double epsilon;
// The smoothing parameter.
double beta1;
// The second moment coefficient.
double beta2;
};
} // namespace ens
#endif
+8 -2
View File
@@ -1,9 +1,11 @@
# The tests that need to be compiled.
set(ENSMALLEN_TESTS_SOURCES
main.cpp
ada_belief_test.cpp
ada_bound_test.cpp
ada_delta_test.cpp
ada_grad_test.cpp
ada_sqrt_test.cpp
adam_test.cpp
aug_lagrangian_test.cpp
bigbatch_sgd_test.cpp
@@ -11,6 +13,8 @@ set(ENSMALLEN_TESTS_SOURCES
cmaes_test.cpp
cne_test.cpp
de_test.cpp
demon_adam_test.cpp
demon_sgd_test.cpp
eve_test.cpp
frankwolfe_test.cpp
ftml_test.cpp
@@ -23,6 +27,7 @@ set(ENSMALLEN_TESTS_SOURCES
line_search_test.cpp
lookahead_test.cpp
lrsdp_test.cpp
moead_test.cpp
momentum_sgd_test.cpp
nesterov_momentum_sgd_test.cpp
nsga2_test.cpp
@@ -44,10 +49,11 @@ set(ENSMALLEN_TESTS_SOURCES
svrg_test.cpp
swats_test.cpp
wn_grad_test.cpp
yogi_test.cpp
)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
add_executable(ensmallen_tests ${ENSMALLEN_TESTS_SOURCES})
add_executable(ensmallen_tests EXCLUDE_FROM_ALL ${ENSMALLEN_TESTS_SOURCES})
target_link_libraries(ensmallen_tests PRIVATE ensmallen)
# Copy test data into place.
@@ -59,4 +65,4 @@ add_custom_command(TARGET ensmallen_tests
enable_testing()
add_test(NAME ensmallen_tests COMMAND ensmallen_tests
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
+71
View File
@@ -0,0 +1,71 @@
/**
* @file ada_belief_test.cpp
* @author Marcus Edel
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <ensmallen.hpp>
#include "catch.hpp"
#include "test_function_tools.hpp"
using namespace ens;
using namespace ens::test;
/**
* Test the AdaBelief optimizer on the Sphere function.
*/
TEST_CASE("AdaBeliefSphereFunctionTest", "[AdaBeliefTest]")
{
AdaBelief optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false);
FunctionTest<SphereFunction>(optimizer, 0.5, 0.1);
}
/**
* Test the AdaBelief optimizer on the Sphere function with arma::fmat.
*/
TEST_CASE("AdaBeliefSphereFunctionTestFMat", "[AdaBeliefTest]")
{
AdaBelief optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false);
FunctionTest<SphereFunction, arma::fmat>(optimizer, 0.5, 0.1);
}
/**
* Test the AdaBelief optimizer on the McCormick function.
*/
TEST_CASE("AdaBeliefMcCormickFunctionTest", "[AdaBeliefTest]")
{
AdaBelief optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false);
FunctionTest<McCormickFunction>(optimizer, 0.5, 0.1);
}
/**
* Run AdaBelief on logistic regression and make sure the results are
* acceptable.
*/
TEST_CASE("AdaBeliefLogisticRegressionTest", "[AdaBeliefTest]")
{
AdaBelief optimizer;
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006);
}
/**
* Run AdaBelief on logistic regression and make sure the results are
* acceptable, using arma::fmat.
*/
TEST_CASE("AdaBeliefLogisticRegressionFMatTest", "[AdaBeliefTest]")
{
arma::fmat data, testData, shuffledData;
arma::Row<size_t> responses, testResponses, shuffledResponses;
LogisticRegressionTestData(data, testData, shuffledData,
responses, testResponses, shuffledResponses);
LogisticRegression<arma::fmat> lr(shuffledData, shuffledResponses, 0.5);
AdaBelief optimizer;
LogisticRegressionFunctionTest<arma::fmat>(optimizer, 0.003, 0.006);
}
+34
View File
@@ -0,0 +1,34 @@
/**
* @file ada_sqrt_test.cpp
* @author Marcus Edel
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <ensmallen.hpp>
#include "catch.hpp"
#include "test_function_tools.hpp"
using namespace ens;
using namespace ens::test;
/**
* Run AdaSqrt on logistic regression and make sure the results are acceptable.
*/
TEST_CASE("AdaSqrtLogisticRegressionTest", "[AdaSqrtTest]")
{
AdaSqrt optimizer(0.01, 32, 1e-8, 5000000, 1e-9, true);
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006);
}
/**
* Run AdaSqrt on logistic regression and make sure the results are acceptable.
*/
TEST_CASE("AdaSqrtLogisticRegressionTestFMat", "[AdaSqrtTest]")
{
AdaSqrt optimizer(0.01, 32, 1e-8, 5000000, 1e-9, true);
LogisticRegressionFunctionTest<arma::fmat>(optimizer, 0.003, 0.006);
}
+22
View File
@@ -322,3 +322,25 @@ TEST_CASE("AdamThreeHumpCamelFunctionTest", "[AdamTest]")
Adam optimizer(0.001, 2, 0.7, 0.999, 1e-8, 500000, 1e-9, false);
FunctionTest<ThreeHumpCamelFunction>(optimizer, 0.1, 0.01);
}
/**
* Test that multiple runs of the Adam optimizer result in the exact same
* result. This specifically tests that the update policy is successfully
* reset at the start of each optimization.
*/
TEST_CASE("AdamResetPolicyTest", "[AdamTest]")
{
Adam optimizer(0.5, 2, 0.7, 0.999, 1e-8, 5, 1e-3, false);
optimizer.ResetPolicy() = true;
SphereFunction f(2);
arma::mat coordinatesA = f.GetInitialPoint();
optimizer.Optimize(f, coordinatesA);
// A second run should produce the exact same results.
arma::mat coordinatesB = f.GetInitialPoint();
optimizer.Optimize(f, coordinatesB);
CheckMatrices(coordinatesA, coordinatesB);
}
+104 -3
View File
@@ -33,7 +33,8 @@ class CompleteCallbackTestFunction
calledEndOptimization(false),
calledEvaluateConstraint(false),
calledGradientConstraint(false),
calledStepTaken(false)
calledStepTaken(false),
calledGenerationalStepTaken(false)
{ }
template<typename OptimizerType, typename FunctionType, typename MatType>
@@ -106,6 +107,18 @@ class CompleteCallbackTestFunction
MatType& /* coordinates */)
{ calledStepTaken = true; }
template<typename OptimizerType,
typename FunctionType,
typename MatType,
typename ObjectivesVecType,
typename IndicesType>
void GenerationalStepTaken(OptimizerType& /* optimizer */,
FunctionType& /* function */,
MatType& /* coordinates */,
ObjectivesVecType& /* objectives */,
IndicesType& /* frontIndices */)
{ calledGenerationalStepTaken = true; }
bool calledEvaluate;
bool calledGradient;
bool calledBeginEpoch;
@@ -115,6 +128,7 @@ class CompleteCallbackTestFunction
bool calledEvaluateConstraint;
bool calledGradientConstraint;
bool calledStepTaken;
bool calledGenerationalStepTaken;
};
template<typename OptimizerType>
@@ -162,7 +176,8 @@ void CallbacksFullMultiobjectiveFunctionTest(OptimizerType& optimizer,
bool calledEndOptimization,
bool calledEvaluateConstraint,
bool calledGradientConstraint,
bool calledStepTaken)
bool calledStepTaken,
bool calledGenerationalStepTaken)
{
SchafferFunctionN1<arma::mat> SCH;
@@ -185,6 +200,7 @@ void CallbacksFullMultiobjectiveFunctionTest(OptimizerType& optimizer,
REQUIRE(cb.calledEvaluateConstraint == calledEvaluateConstraint);
REQUIRE(cb.calledGradientConstraint == calledGradientConstraint);
REQUIRE(cb.calledStepTaken == calledStepTaken);
REQUIRE(cb.calledGenerationalStepTaken == calledGenerationalStepTaken);
}
template<typename OptimizerType>
@@ -380,7 +396,19 @@ TEST_CASE("NSGA2CallbacksFullFunctionTest", "[CallbackTest]")
arma::vec upperBound = {1000};
NSGA2 optimizer(20, 5000, 0.5, 0.5, 1e-3, 1e-6, lowerBound, upperBound);
CallbacksFullMultiobjectiveFunctionTest(optimizer, false, false, false, false,
true, true, false, false, true);
true, true, false, false, false, true);
}
/**
* Make sure we invoke all callbacks (MOEA/D-DE).
*/
TEST_CASE("MOEADCallbacksFullFunctionTest", "[CallbackTest]")
{
arma::vec lowerBound = {-1000};
arma::vec upperBound = {1000};
DefaultMOEAD optimizer(150, 300, 1.0, 0.9, 20, 20, 0.5, 2, 1E-10, lowerBound, upperBound);
CallbacksFullMultiobjectiveFunctionTest(optimizer, false, false, false, false,
true, true, false, false, false, true);
}
/**
@@ -755,3 +783,76 @@ TEST_CASE("ReportCallbackTest", "[CallbacksTest]")
aug.Optimize(f3, coordinates, Report(0.1, stream));
REQUIRE(stream.str().length() > 0);
}
/**
* Make sure the GradClipByNorm callback will clip the gradient.
*/
TEST_CASE("GradClipByNormCallbackTest", "[CallbacksTest]")
{
SGDTestFunction f;
arma::mat coordinates = f.GetInitialPoint();
StandardSGD s(0.0003, 1, 10, 1e-9, true);
std::stringstream stream;
s.Optimize(f, coordinates, GradClipByNorm(0.5), Report(0.1, stream));
// We don't store the gradient during the optimization process, so we use the
// output of the Report callback function to check if the gradient is
// clipped.
std::string line;
bool gradientInfo = false;
double gradient = 1;
while (std::getline(stream, line, '\n'))
{
if (gradientInfo)
{
size_t iter;
double loss, lossChange, stepSize, totalTime;
std::stringstream stream(line);
stream >> iter >> loss >> lossChange >> gradient >> stepSize >> totalTime;
break;
}
gradientInfo = line.find("|gradient|") != std::string::npos;
}
REQUIRE(gradient == 0.5);
}
/**
* Make sure the GradClipByValue callback will clip the gradient.
*/
TEST_CASE("GradClipByValueCallbackTest", "[CallbacksTest]")
{
SGDTestFunction f;
arma::mat coordinates = f.GetInitialPoint();
StandardSGD s(0.0003, 1, 10, 1e-9, true);
std::stringstream stream;
s.Optimize(f, coordinates, GradClipByValue(0, 0), Report(0.1, stream));
// We don't store the gradient during the optimization process, so we use the
// output of the Report callback function to check if the gradient is
// clipped.
std::string line;
bool gradientInfo = false;
double gradient = 1;
while (std::getline(stream, line, '\n'))
{
if (gradientInfo)
{
size_t iter;
double loss, lossChange, stepSize, totalTime;
std::stringstream stream(line);
stream >> iter >> loss >> lossChange >> gradient >> stepSize >> totalTime;
break;
}
gradientInfo = line.find("|gradient|") != std::string::npos;
}
REQUIRE(gradient == 0);
}
+313 -229
View File
@@ -1,9 +1,9 @@
/*
* Catch v2.13.4
* Generated: 2020-12-29 14:48:00.116107
* Catch v2.13.8
* Generated: 2022-01-03 21:20:09.589503
* ----------------------------------------------------------
* This file has been merged from multiple headers. Please don't edit it directly
* Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved.
* Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved.
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -15,7 +15,7 @@
#define CATCH_VERSION_MAJOR 2
#define CATCH_VERSION_MINOR 13
#define CATCH_VERSION_PATCH 4
#define CATCH_VERSION_PATCH 8
#ifdef __clang__
# pragma clang system_header
@@ -66,13 +66,16 @@
#if !defined(CATCH_CONFIG_IMPL_ONLY)
// start catch_platform.h
// See e.g.:
// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html
#ifdef __APPLE__
# include <TargetConditionals.h>
# if TARGET_OS_OSX == 1
# define CATCH_PLATFORM_MAC
# elif TARGET_OS_IPHONE == 1
# define CATCH_PLATFORM_IPHONE
# endif
# include <TargetConditionals.h>
# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
(defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
# define CATCH_PLATFORM_MAC
# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
# define CATCH_PLATFORM_IPHONE
# endif
#elif defined(linux) || defined(__linux) || defined(__linux__)
# define CATCH_PLATFORM_LINUX
@@ -132,9 +135,9 @@ namespace Catch {
#endif
// We have to avoid both ICC and Clang, because they try to mask themselves
// as gcc, and we want only GCC in this block
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__)
// Only GCC compiler should be used in this block, so other compilers trying to
// mask themselves as GCC should be ignored.
#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__)
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
@@ -237,9 +240,6 @@ namespace Catch {
// Visual C++
#if defined(_MSC_VER)
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) )
// Universal Windows platform does not support SEH
// Or console colours (or console at all...)
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
@@ -248,13 +248,18 @@ namespace Catch {
# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
# endif
# if !defined(__clang__) // Handle Clang masquerading for msvc
// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
# if !defined(__clang__) // Handle Clang masquerading for msvc
# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
# endif // MSVC_TRADITIONAL
// Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop`
# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) )
# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) )
# endif // __clang__
#endif // _MSC_VER
@@ -323,7 +328,7 @@ namespace Catch {
// Check if byte is available and usable
# if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
# include <cstddef>
# if __cpp_lib_byte > 0
# if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0)
# define CATCH_INTERNAL_CONFIG_CPP17_BYTE
# endif
# endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
@@ -1007,34 +1012,34 @@ struct AutoReg : NonCopyable {
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ )
INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
#endif
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ )
INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) )
#endif
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
#endif
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
#endif
#endif
@@ -1047,7 +1052,7 @@ struct AutoReg : NonCopyable {
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
static void TestName()
#define INTERNAL_CATCH_TESTCASE( ... ) \
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
@@ -1069,7 +1074,7 @@ struct AutoReg : NonCopyable {
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
void TestName::test()
#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), ClassName, __VA_ARGS__ )
///////////////////////////////////////////////////////////////////////////////
#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
@@ -1110,18 +1115,18 @@ struct AutoReg : NonCopyable {
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ )
INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
#endif
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ )
INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) )
#endif
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \
@@ -1159,18 +1164,18 @@ struct AutoReg : NonCopyable {
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T,__VA_ARGS__)
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T,__VA_ARGS__)
#else
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T, __VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T, __VA_ARGS__ ) )
#endif
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__)
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__)
#else
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) )
#endif
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\
@@ -1201,7 +1206,7 @@ struct AutoReg : NonCopyable {
static void TestFunc()
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \
INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, TmplList )
INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, TmplList )
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
@@ -1234,18 +1239,18 @@ struct AutoReg : NonCopyable {
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
#endif
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
#endif
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
@@ -1286,18 +1291,18 @@ struct AutoReg : NonCopyable {
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T, __VA_ARGS__ )
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) )
#endif
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature, __VA_ARGS__ )
INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature, __VA_ARGS__ )
#else
#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
#endif
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
@@ -1331,7 +1336,7 @@ struct AutoReg : NonCopyable {
void TestName<TestType>::test()
#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, TmplList )
INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, TmplList )
// end catch_test_registry.h
// start catch_capture.hpp
@@ -3088,7 +3093,7 @@ namespace Detail {
Approx operator-() const;
template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx operator()( T const& value ) {
Approx operator()( T const& value ) const {
Approx approx( static_cast<double>(value) );
approx.m_epsilon = m_epsilon;
approx.m_margin = m_margin;
@@ -4160,7 +4165,7 @@ namespace Generators {
if (!m_predicate(m_generator.get())) {
// It might happen that there are no values that pass the
// filter. In that case we throw an exception.
auto has_initial_value = next();
auto has_initial_value = nextImpl();
if (!has_initial_value) {
Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
}
@@ -4172,6 +4177,11 @@ namespace Generators {
}
bool next() override {
return nextImpl();
}
private:
bool nextImpl() {
bool success = m_generator.next();
if (!success) {
return false;
@@ -5455,6 +5465,8 @@ namespace Catch {
} // namespace Catch
// end catch_outlier_classification.hpp
#include <iterator>
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
#include <string>
@@ -6339,9 +6351,10 @@ namespace Catch {
void writeTestCase(TestCaseNode const& testCaseNode);
void writeSection(std::string const& className,
std::string const& rootName,
SectionNode const& sectionNode);
void writeSection( std::string const& className,
std::string const& rootName,
SectionNode const& sectionNode,
bool testOkToFail );
void writeAssertions(SectionNode const& sectionNode);
void writeAssertion(AssertionStats const& stats);
@@ -6876,7 +6889,7 @@ namespace Catch {
}
iters *= 2;
}
throw optimized_away_error{};
Catch::throw_exception(optimized_away_error{});
}
} // namespace Detail
} // namespace Benchmark
@@ -6884,6 +6897,7 @@ namespace Catch {
// end catch_run_for_at_least.hpp
#include <algorithm>
#include <iterator>
namespace Catch {
namespace Benchmark {
@@ -7054,8 +7068,8 @@ namespace Catch {
double b2 = bias - z1;
double a1 = a(b1);
double a2 = a(b2);
auto lo = std::max(cumn(a1), 0);
auto hi = std::min(cumn(a2), n - 1);
auto lo = (std::max)(cumn(a1), 0);
auto hi = (std::min)(cumn(a2), n - 1);
return { point, resample[lo], resample[hi], confidence_level };
}
@@ -7124,7 +7138,9 @@ namespace Catch {
}
template <typename Clock>
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit));
auto time_limit = (std::min)(
resolution * clock_cost_estimation_tick_limit,
FloatDuration<Clock>(clock_cost_estimation_time_limit));
auto time_clock = [](int k) {
return Detail::measure<Clock>([k] {
for (int i = 0; i < k; ++i) {
@@ -7771,7 +7787,7 @@ namespace Catch {
double sb = stddev.point;
double mn = mean.point / n;
double mg_min = mn / 2.;
double sg = std::min(mg_min / 4., sb / std::sqrt(n));
double sg = (std::min)(mg_min / 4., sb / std::sqrt(n));
double sg2 = sg * sg;
double sb2 = sb * sb;
@@ -7790,7 +7806,7 @@ namespace Catch {
return (nc / n) * (sb2 - nc * sg2);
};
return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2;
return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2;
}
bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
@@ -7980,86 +7996,58 @@ namespace Catch {
// start catch_fatal_condition.h
// start catch_windows_h_proxy.h
#if defined(CATCH_PLATFORM_WINDOWS)
#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
# define CATCH_DEFINED_NOMINMAX
# define NOMINMAX
#endif
#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#ifdef __AFXDLL
#include <AfxWin.h>
#else
#include <windows.h>
#endif
#ifdef CATCH_DEFINED_NOMINMAX
# undef NOMINMAX
#endif
#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# undef WIN32_LEAN_AND_MEAN
#endif
#endif // defined(CATCH_PLATFORM_WINDOWS)
// end catch_windows_h_proxy.h
#if defined( CATCH_CONFIG_WINDOWS_SEH )
#include <cassert>
namespace Catch {
struct FatalConditionHandler {
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
FatalConditionHandler();
static void reset();
~FatalConditionHandler();
private:
static bool isSet;
static ULONG guaranteeSize;
static PVOID exceptionHandlerHandle;
};
} // namespace Catch
#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
#include <signal.h>
namespace Catch {
struct FatalConditionHandler {
static bool isSet;
static struct sigaction oldSigActions[];
static stack_t oldSigStack;
static char altStackMem[];
static void handleSignal( int sig );
// Wrapper for platform-specific fatal error (signals/SEH) handlers
//
// Tries to be cooperative with other handlers, and not step over
// other handlers. This means that unknown structured exceptions
// are passed on, previous signal handlers are called, and so on.
//
// Can only be instantiated once, and assumes that once a signal
// is caught, the binary will end up terminating. Thus, there
class FatalConditionHandler {
bool m_started = false;
// Install/disengage implementation for specific platform.
// Should be if-defed to work on current platform, can assume
// engage-disengage 1:1 pairing.
void engage_platform();
void disengage_platform();
public:
// Should also have platform-specific implementations as needed
FatalConditionHandler();
~FatalConditionHandler();
static void reset();
void engage() {
assert(!m_started && "Handler cannot be installed twice.");
m_started = true;
engage_platform();
}
void disengage() {
assert(m_started && "Handler cannot be uninstalled without being installed first");
m_started = false;
disengage_platform();
}
};
} // namespace Catch
#else
namespace Catch {
struct FatalConditionHandler {
void reset();
//! Simple RAII guard for (dis)engaging the FatalConditionHandler
class FatalConditionHandlerGuard {
FatalConditionHandler* m_handler;
public:
FatalConditionHandlerGuard(FatalConditionHandler* handler):
m_handler(handler) {
m_handler->engage();
}
~FatalConditionHandlerGuard() {
m_handler->disengage();
}
};
}
#endif
} // end namespace Catch
// end catch_fatal_condition.h
#include <string>
@@ -8185,6 +8173,7 @@ namespace Catch {
std::vector<SectionEndInfo> m_unfinishedSections;
std::vector<ITracker*> m_activeSections;
TrackerContext m_trackerContext;
FatalConditionHandler m_fatalConditionhandler;
bool m_lastAssertionPassed = false;
bool m_shouldReportUnexpected = true;
bool m_includeSuccessfulResults;
@@ -10057,6 +10046,36 @@ namespace Catch {
}
// end catch_errno_guard.h
// start catch_windows_h_proxy.h
#if defined(CATCH_PLATFORM_WINDOWS)
#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
# define CATCH_DEFINED_NOMINMAX
# define NOMINMAX
#endif
#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#ifdef __AFXDLL
#include <AfxWin.h>
#else
#include <windows.h>
#endif
#ifdef CATCH_DEFINED_NOMINMAX
# undef NOMINMAX
#endif
#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
# undef WIN32_LEAN_AND_MEAN
#endif
#endif // defined(CATCH_PLATFORM_WINDOWS)
// end catch_windows_h_proxy.h
#include <sstream>
namespace Catch {
@@ -10573,7 +10592,7 @@ namespace Catch {
// Extracts the actual name part of an enum instance
// In other words, it returns the Blue part of Bikeshed::Colour::Blue
StringRef extractInstanceName(StringRef enumInstance) {
// Find last occurence of ":"
// Find last occurrence of ":"
size_t name_start = enumInstance.size();
while (name_start > 0 && enumInstance[name_start - 1] != ':') {
--name_start;
@@ -10735,25 +10754,47 @@ namespace Catch {
// end catch_exception_translator_registry.cpp
// start catch_fatal_condition.cpp
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
#include <algorithm>
#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace Catch {
// If neither SEH nor signal handling is required, the handler impls
// do not have to do anything, and can be empty.
void FatalConditionHandler::engage_platform() {}
void FatalConditionHandler::disengage_platform() {}
FatalConditionHandler::FatalConditionHandler() = default;
FatalConditionHandler::~FatalConditionHandler() = default;
} // end namespace Catch
#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
namespace {
// Report the error condition
//! Signals fatal error message to the run context
void reportFatal( char const * const message ) {
Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
}
}
#endif // signals/SEH handling
//! Minimal size Catch2 needs for its own fatal error handling.
//! Picked anecdotally, so it might not be sufficient on all
//! platforms, and for all configurations.
constexpr std::size_t minStackSizeForErrors = 32 * 1024;
} // end unnamed namespace
#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
#if defined( CATCH_CONFIG_WINDOWS_SEH )
namespace Catch {
struct SignalDefs { DWORD id; const char* name; };
// There is no 1-1 mapping between signals and windows exceptions.
@@ -10766,7 +10807,7 @@ namespace Catch {
{ static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" },
};
LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
for (auto const& def : signalDefs) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
reportFatal(def.name);
@@ -10777,38 +10818,50 @@ namespace Catch {
return EXCEPTION_CONTINUE_SEARCH;
}
FatalConditionHandler::FatalConditionHandler() {
isSet = true;
// 32k seems enough for Catch to handle stack overflow,
// but the value was found experimentally, so there is no strong guarantee
guaranteeSize = 32 * 1024;
exceptionHandlerHandle = nullptr;
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
// Pass in guarantee size to be filled
SetThreadStackGuarantee(&guaranteeSize);
}
// Since we do not support multiple instantiations, we put these
// into global variables and rely on cleaning them up in outlined
// constructors/destructors
static PVOID exceptionHandlerHandle = nullptr;
void FatalConditionHandler::reset() {
if (isSet) {
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
SetThreadStackGuarantee(&guaranteeSize);
exceptionHandlerHandle = nullptr;
isSet = false;
// For MSVC, we reserve part of the stack memory for handling
// memory overflow structured exception.
FatalConditionHandler::FatalConditionHandler() {
ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
if (!SetThreadStackGuarantee(&guaranteeSize)) {
// We do not want to fully error out, because needing
// the stack reserve should be rare enough anyway.
Catch::cerr()
<< "Failed to reserve piece of stack."
<< " Stack overflows will not be reported successfully.";
}
}
FatalConditionHandler::~FatalConditionHandler() {
reset();
// We do not attempt to unset the stack guarantee, because
// Windows does not support lowering the stack size guarantee.
FatalConditionHandler::~FatalConditionHandler() = default;
void FatalConditionHandler::engage_platform() {
// Register as first handler in current chain
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
if (!exceptionHandlerHandle) {
CATCH_RUNTIME_ERROR("Could not register vectored exception handler");
}
}
bool FatalConditionHandler::isSet = false;
ULONG FatalConditionHandler::guaranteeSize = 0;
PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
void FatalConditionHandler::disengage_platform() {
if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) {
CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler");
}
exceptionHandlerHandle = nullptr;
}
} // namespace Catch
} // end namespace Catch
#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
#endif // CATCH_CONFIG_WINDOWS_SEH
#if defined( CATCH_CONFIG_POSIX_SIGNALS )
#include <signal.h>
namespace Catch {
@@ -10817,10 +10870,6 @@ namespace Catch {
const char* name;
};
// 32kb for the alternate stack seems to be sufficient. However, this value
// is experimentally determined, so that's not guaranteed.
static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
static SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
{ SIGILL, "SIGILL - Illegal instruction signal" },
@@ -10830,7 +10879,32 @@ namespace Catch {
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
};
void FatalConditionHandler::handleSignal( int sig ) {
// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
// which is zero initialization, but not explicit. We want to avoid
// that.
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
static char* altStackMem = nullptr;
static std::size_t altStackSize = 0;
static stack_t oldSigStack{};
static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
static void restorePreviousSignalHandlers() {
// We set signal handlers back to the previous ones. Hopefully
// nobody overwrote them in the meantime, and doesn't expect
// their signal handlers to live past ours given that they
// installed them after ours..
for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
}
// Return the old stack
sigaltstack(&oldSigStack, nullptr);
}
static void handleSignal( int sig ) {
char const * name = "<unknown signal>";
for (auto const& def : signalDefs) {
if (sig == def.id) {
@@ -10838,16 +10912,33 @@ namespace Catch {
break;
}
}
reset();
reportFatal(name);
// We need to restore previous signal handlers and let them do
// their thing, so that the users can have the debugger break
// when a signal is raised, and so on.
restorePreviousSignalHandlers();
reportFatal( name );
raise( sig );
}
FatalConditionHandler::FatalConditionHandler() {
isSet = true;
assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
if (altStackSize == 0) {
altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
}
altStackMem = new char[altStackSize]();
}
FatalConditionHandler::~FatalConditionHandler() {
delete[] altStackMem;
// We signal that another instance can be constructed by zeroing
// out the pointer.
altStackMem = nullptr;
}
void FatalConditionHandler::engage_platform() {
stack_t sigStack;
sigStack.ss_sp = altStackMem;
sigStack.ss_size = sigStackSize;
sigStack.ss_size = altStackSize;
sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = { };
@@ -10859,40 +10950,17 @@ namespace Catch {
}
}
FatalConditionHandler::~FatalConditionHandler() {
reset();
}
void FatalConditionHandler::reset() {
if( isSet ) {
// Set signals back to previous values -- hopefully nobody overwrote them in the meantime
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
}
// Return the old stack
sigaltstack(&oldSigStack, nullptr);
isSet = false;
}
}
bool FatalConditionHandler::isSet = false;
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
stack_t FatalConditionHandler::oldSigStack = {};
char FatalConditionHandler::altStackMem[sigStackSize] = {};
} // namespace Catch
#else
namespace Catch {
void FatalConditionHandler::reset() {}
}
#endif // signals/SEH handling
#if defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
void FatalConditionHandler::disengage_platform() {
restorePreviousSignalHandlers();
}
} // end namespace Catch
#endif // CATCH_CONFIG_POSIX_SIGNALS
// end catch_fatal_condition.cpp
// start catch_generators.cpp
@@ -11447,7 +11515,8 @@ namespace {
return lhs == rhs;
}
auto ulpDiff = std::abs(lc - rc);
// static cast as a workaround for IBM XLC
auto ulpDiff = std::abs(static_cast<FP>(lc - rc));
return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff;
}
@@ -11621,7 +11690,6 @@ Floating::WithinRelMatcher WithinRel(float target) {
} // namespace Matchers
} // namespace Catch
// end catch_matchers_floating.cpp
// start catch_matchers_generic.cpp
@@ -12955,9 +13023,8 @@ namespace Catch {
}
void RunContext::invokeActiveTestCase() {
FatalConditionHandler fatalConditionHandler; // Handle signals
FatalConditionHandlerGuard _(&m_fatalConditionhandler);
m_activeTestCase->invoke();
fatalConditionHandler.reset();
}
void RunContext::handleUnfinishedSections() {
@@ -15320,7 +15387,7 @@ namespace Catch {
}
Version const& libraryVersion() {
static Version version( 2, 13, 4, "", 0 );
static Version version( 2, 13, 8, "", 0 );
return version;
}
@@ -16733,6 +16800,7 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter)
#include <sstream>
#include <ctime>
#include <algorithm>
#include <iomanip>
namespace Catch {
@@ -16760,7 +16828,7 @@ namespace Catch {
#else
std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
#endif
return std::string(timeStamp);
return std::string(timeStamp, timeStampSize-1);
}
std::string fileNameTag(const std::vector<std::string> &tags) {
@@ -16771,6 +16839,17 @@ namespace Catch {
return it->substr(1);
return std::string();
}
// Formats the duration in seconds to 3 decimal places.
// This is done because some genius defined Maven Surefire schema
// in a way that only accepts 3 decimal places, and tools like
// Jenkins use that schema for validation JUnit reporter output.
std::string formatDuration( double seconds ) {
ReusableStringStream rss;
rss << std::fixed << std::setprecision( 3 ) << seconds;
return rss.str();
}
} // anonymous namespace
JunitReporter::JunitReporter( ReporterConfig const& _config )
@@ -16840,7 +16919,7 @@ namespace Catch {
if( m_config->showDurations() == ShowDurations::Never )
xml.writeAttribute( "time", "" );
else
xml.writeAttribute( "time", suiteTime );
xml.writeAttribute( "time", formatDuration( suiteTime ) );
xml.writeAttribute( "timestamp", getCurrentTimestamp() );
// Write properties if there are any
@@ -16885,12 +16964,13 @@ namespace Catch {
if ( !m_config->name().empty() )
className = m_config->name() + "." + className;
writeSection( className, "", rootSection );
writeSection( className, "", rootSection, stats.testInfo.okToFail() );
}
void JunitReporter::writeSection( std::string const& className,
std::string const& rootName,
SectionNode const& sectionNode ) {
void JunitReporter::writeSection( std::string const& className,
std::string const& rootName,
SectionNode const& sectionNode,
bool testOkToFail) {
std::string name = trim( sectionNode.stats.sectionInfo.name );
if( !rootName.empty() )
name = rootName + '/' + name;
@@ -16907,13 +16987,18 @@ namespace Catch {
xml.writeAttribute( "classname", className );
xml.writeAttribute( "name", name );
}
xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) );
xml.writeAttribute( "time", formatDuration( sectionNode.stats.durationInSeconds ) );
// This is not ideal, but it should be enough to mimic gtest's
// junit output.
// Ideally the JUnit reporter would also handle `skipTest`
// events and write those out appropriately.
xml.writeAttribute( "status", "run" );
if (sectionNode.stats.assertions.failedButOk) {
xml.scopedElement("skipped")
.writeAttribute("message", "TEST_CASE tagged with !mayfail");
}
writeAssertions( sectionNode );
if( !sectionNode.stdOut.empty() )
@@ -16923,9 +17008,9 @@ namespace Catch {
}
for( auto const& childNode : sectionNode.childSections )
if( className.empty() )
writeSection( name, "", *childNode );
writeSection( name, "", *childNode, testOkToFail );
else
writeSection( className, name, *childNode );
writeSection( className, name, *childNode, testOkToFail );
}
void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {
@@ -17570,9 +17655,9 @@ int main (int argc, char * const argv[]) {
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
#define CATCH_BENCHMARK(...) \
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
#define CATCH_BENCHMARK_ADVANCED(name) \
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name)
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
@@ -17674,9 +17759,9 @@ int main (int argc, char * const argv[]) {
#if defined(CATCH_CONFIG_ENABLE_BENCHMARKING)
#define BENCHMARK(...) \
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
#define BENCHMARK_ADVANCED(name) \
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name)
INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name)
#endif // CATCH_CONFIG_ENABLE_BENCHMARKING
using Catch::Detail::Approx;
@@ -17723,8 +17808,8 @@ using Catch::Detail::Approx;
#define CATCH_WARN( msg ) (void)(0)
#define CATCH_CAPTURE( msg ) (void)(0)
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
#define CATCH_METHOD_AS_TEST_CASE( method, ... )
#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
#define CATCH_SECTION( ... )
@@ -17733,7 +17818,7 @@ using Catch::Detail::Approx;
#define CATCH_FAIL_CHECK( ... ) (void)(0)
#define CATCH_SUCCEED( ... ) (void)(0)
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
@@ -17756,8 +17841,8 @@ using Catch::Detail::Approx;
#endif
// "BDD-style" convenience wrappers
#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className )
#define CATCH_GIVEN( desc )
#define CATCH_AND_GIVEN( desc )
#define CATCH_WHEN( desc )
@@ -17807,8 +17892,8 @@ using Catch::Detail::Approx;
#define WARN( msg ) (void)(0)
#define CAPTURE( msg ) (void)(0)
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
#define METHOD_AS_TEST_CASE( method, ... )
#define REGISTER_TEST_CASE( Function, ... ) (void)(0)
#define SECTION( ... )
@@ -17816,7 +17901,7 @@ using Catch::Detail::Approx;
#define FAIL( ... ) (void)(0)
#define FAIL_CHECK( ... ) (void)(0)
#define SUCCEED( ... ) (void)(0)
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ))
#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
@@ -17846,8 +17931,8 @@ using Catch::Detail::Approx;
#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
// "BDD-style" convenience wrappers
#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) )
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ) )
#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className )
#define GIVEN( desc )
#define AND_GIVEN( desc )
@@ -17878,4 +17963,3 @@ using Catch::Detail::Approx;
// end catch_reenable_warnings.h
// end catch.hpp
#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+1 -1
View File
@@ -94,7 +94,7 @@ TEST_CASE("CNELevyFunctionN13Test", "[CNETest]")
TEST_CASE("CNEHimmelblauFunctionTest", "[CNETest]")
{
HimmelblauFunction f;
CNE optimizer(450, 1500, 0.3, 0.3, 0.3, 1e-7);
CNE optimizer(650, 3000, 0.3, 0.3, 0.3, 1e-7);
arma::mat coordinates = arma::mat("2; 1");
optimizer.Optimize(f, coordinates);
+75
View File
@@ -0,0 +1,75 @@
/**
* @file demon_adam_test.cpp
* @author Marcus Edel
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <ensmallen.hpp>
#include "catch.hpp"
#include "test_function_tools.hpp"
using namespace ens;
using namespace ens::test;
/**
* Run DemonAdam on logistic regression and make sure the results are
* acceptable.
*/
TEST_CASE("DemonAdamLogisticRegressionTest", "[DemonAdamTest]")
{
DemonAdam optimizer(0.2, 32, 0.9, 0.9, 0.999, 1e-8,
10000, 1e-9, true, true, true);
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006, 6);
}
/**
* Test the Adam optimizer on the Sphere function.
*/
TEST_CASE("DemonAdamSphereFunctionTest", "[DemonAdamTest]")
{
SphereFunction f(2);
DemonAdam optimizer(0.5, 2, 0.9);
FunctionTest<SphereFunction, arma::mat>(optimizer, 1.0, 0.1);
}
/**
* Test the DemonAdam optimizer on the Matyas function.
*/
TEST_CASE("DemonAdamMatyasFunctionTest", "[DemonAdamTest]")
{
DemonAdam optimizer(0.5, 1, 0.9);
FunctionTest<MatyasFunction, arma::mat>(optimizer, 0.1, 0.01);
}
/**
* Test the Adam optimizer on the Sphere function.
*/
TEST_CASE("DemonAdamSphereFunctionTestFloat", "[DemonAdamTest]")
{
DemonAdam optimizer(0.5, 2, 0.9);
FunctionTest<SphereFunction, arma::sp_mat>(optimizer, 1.0, 0.1);
}
/**
* Test the DemonAdam optimizer on the Matyas function.
*/
TEST_CASE("DemonAdamMatyasFunctionTestFloat", "[DemonAdamTest]")
{
DemonAdam optimizer(0.5, 1, 0.9);
FunctionTest<MatyasFunction, arma::fmat>(optimizer, 0.1, 0.01);
}
/**
* Run DemonAdam (AdaMax update) on logistic regression and make sure the
* results are acceptable.
*/
TEST_CASE("DemonAdaMaxLogisticRegressionTest", "[DemonAdamTest]")
{
DemonAdamType<AdaMaxUpdate> optimizer(0.5, 10, 0.9, 0.9, 0.999, 1e-8,
10000, 1e-9, true, true, true);
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006, 3);
}
+43
View File
@@ -0,0 +1,43 @@
/**
* @file demon_sgd_test.cpp
* @author Marcus Edel
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <ensmallen.hpp>
#include "catch.hpp"
#include "test_function_tools.hpp"
using namespace ens;
using namespace ens::test;
/**
* Run DemonSGD on logistic regression and make sure the results are
* acceptable.
*/
TEST_CASE("DemonSGDLogisticRegressionTest", "[DemonSGDTest]")
{
DemonSGD optimizer(0.1, 32, 0.9, 1000000, 1e-9, true, true, true);
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006, 6);
}
/**
* Tests the DemonSGD optimizer using a simple test function.
*/
TEST_CASE("DemonSGDSimpleTestFunctionFloat", "[DemonSGDTest]")
{
SGDTestFunction f;
DemonSGD optimizer(1e-2, 1, 0.9, 400000);
arma::fmat coordinates = f.GetInitialPoint<arma::fmat>();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.1));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.1));
REQUIRE(coordinates(2) == Approx(0.0).margin(0.1));
}
+97
View File
@@ -0,0 +1,97 @@
/**
* @file indicators_test.cpp
* @author Nanubala Gnana Sai
*
* Test file for all the indicators: Epsilon, IGD+.
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <ensmallen.hpp>
#include "catch.hpp"
using namespace ens;
using namespace ens::test;
/**
* Calculates the Epsilon metric for the pair of fronts.
* Tests for data of type double.
* The reference numerical results have been taken from hand calculated values.
* Refer the IPynb notebook in https://github.com/mlpack/ensmallen/pull/285
* for more.
*/
TEST_CASE("EpsilonDoubleTest", "[IndicatorsTest]")
{
arma::cube referenceFront(2, 1, 3);
double tol = 1e-10;
referenceFront.slice(0) = arma::vec{0.01010101, 0.89949622};
referenceFront.slice(1) = arma::vec{0.02020202, 0.85786619};
referenceFront.slice(2) = arma::vec{0.03030303, 0.82592234};
arma::cube front = referenceFront * 1.1;
double eps = Epsilon::Evaluate(front, referenceFront);
REQUIRE(eps == Approx(1.1).margin(tol));
}
/**
* Calculates the Epsilon metric for the pair of fronts.
* Tests for data of type float.
* The reference numerical results have been taken from hand calculated values.
* Refer the IPynb notebook in https://github.com/mlpack/ensmallen/pull/285
* for more.
*/
TEST_CASE("EpsilonFloatTest", "[IndicatorsTest]")
{
arma::fcube referenceFront(2, 1, 3);
float tol = 1e-10;
referenceFront.slice(0) = arma::fvec{0.01010101f, 0.89949622f};
referenceFront.slice(1) = arma::fvec{0.02020202f, 0.85786619f};
referenceFront.slice(2) = arma::fvec{0.03030303f, 0.82592234f};
arma::fcube front = referenceFront * 1.1;
double eps = Epsilon::Evaluate(front, referenceFront);
REQUIRE(eps == Approx(1.1).margin(tol));
}
/**
* Calculates the IGD+ metric for the pair of fronts.
* Tests for data of type double.
* The reference numerical results have been taken from hand calculated values.
* Refer the IPynb notebook in https://github.com/mlpack/ensmallen/pull/285
* for more.
*/
TEST_CASE("IGDPlusDoubleTest", "[IndicatorsTest]")
{
arma::cube referenceFront(2, 1, 3);
double tol = 1e-10;
referenceFront.slice(0) = arma::vec{0.01010101, 0.89949622};
referenceFront.slice(1) = arma::vec{0.02020202, 0.85786619};
referenceFront.slice(2) = arma::vec{0.03030303, 0.82592234};
arma::cube front = referenceFront * 1.1;
double igdPlus = IGDPlus::Evaluate(front, referenceFront);
REQUIRE(igdPlus == Approx(0.05329735411078149).margin(tol));
}
/**
* Calculates the IGD+ metric for the pair of fronts.
* Tests for data of type float.
* The reference numerical results have been taken from hand calculated values.
* Refer the IPynb notebook in https://github.com/mlpack/ensmallen/pull/285
* for more.
*/
TEST_CASE("IGDPlusFloatTest", "[IndicatorsTest]")
{
arma::fcube referenceFront(2, 1, 3);
float tol = 1e-10;
referenceFront.slice(0) = arma::fvec{0.01010101f, 0.89949622f};
referenceFront.slice(1) = arma::fvec{0.02020202f, 0.85786619f};
referenceFront.slice(2) = arma::fvec{0.03030303f, 0.82592234f};
arma::fcube front = referenceFront * 1.1;
float igdPlus = IGDPlus::Evaluate(front, referenceFront);
REQUIRE(igdPlus == Approx(0.05329735411078149).margin(tol));
}
+15 -10
View File
@@ -17,18 +17,23 @@
int main(int argc, char** argv)
{
/**
* Uncomment these three lines if you want to test with different random seeds
* each run. This is good for ensuring that a test's tolerance is sufficient
* across many different runs.
*/
//size_t seed = std::time(NULL);
//srand((unsigned int) seed);
//arma::arma_rng::set_seed(seed);
Catch::Session session;
const int returnCode = session.applyCommandLine(argc, argv);
// Check for a command line error.
if (returnCode != 0)
return returnCode;
std::cout << "ensmallen version: " << ens::version::as_string() << std::endl;
std::cout << "armadillo version: " << arma::arma_version::as_string() << std::endl;
return Catch::Session().run(argc, argv);
// Use Catch2 command-line to set the random seed.
// -rng-seed <'time'|number>
// If a number is provided this is used directly as the seed. Alternatively
// if the keyword 'time' is provided then the result of calling std::time(0)
// is used.
const size_t seed = session.config().rngSeed();
srand((unsigned int) seed);
arma::arma_rng::set_seed(seed);
return session.run();
}
+630
View File
@@ -0,0 +1,630 @@
/**
* @file moead_test.cpp
* @author Nanubala Gnana Sai
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <ensmallen.hpp>
#include "catch.hpp"
#include "test_function_tools.hpp"
using namespace ens;
using namespace ens::test;
using namespace std;
/**
* Checks if low <= value <= high. Used by MOEADFonsecaFlemingTest.
*
* @param value The value being checked.
* @param low The lower bound.
* @param high The upper bound.
* @param roundoff To round off precision.
* @tparam The type of elements in the population set.
* @return true if value lies in the range [low, high].
* @return false if value does not lie in the range [low, high].
*/
template<typename ElemType>
bool IsInBounds(const ElemType& value,
const ElemType& low,
const ElemType& high,
const ElemType& roundoff)
{
return !(value < (low - roundoff)) && !((high + roundoff) < value);
}
/**
* Optimize for the Schaffer N.1 function using NSGA-II optimizer.
* Tests for data of type double.
*/
TEST_CASE("MOEADSchafferN1DoubleTest", "[MOEADTest]")
{
SchafferFunctionN1<arma::mat> SCH;
const double lowerBound = -1000;
const double upperBound = 1000;
const double expectedLowerBound = 0.0;
const double expectedUpperBound = 2.0;
DefaultMOEAD opt(
300, // Population size.
300, // Max generations.
1.0, // Crossover probability.
0.9, // Probability of sampling from neighbor.
20, // Neighborhood size.
20, // Perturbation index.
0.5, // Differential weight.
2, // Max childrens to replace parents.
1E-10, // epsilon.
lowerBound, // Lower bound.
upperBound // Upper bound.
);
typedef decltype(SCH.objectiveA) ObjectiveTypeA;
typedef decltype(SCH.objectiveB) ObjectiveTypeB;
// We allow a few trials in case of poor convergence.
bool success = false;
for (size_t trial = 0; trial < 5; ++trial)
{
arma::mat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
opt.Optimize(objectives, coords);
arma::cube paretoSet= opt.ParetoSet();
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
double val = arma::as_scalar(paretoSet.slice(solutionIdx));
if (!IsInBounds<double>(val, expectedLowerBound, expectedUpperBound, 0.1))
{
allInRange = false;
break;
}
}
if (allInRange)
{
success = true;
break;
}
}
REQUIRE(success == true);
}
/**
* Optimize for the Schaffer N.1 function using NSGA-II optimizer.
* Tests for data of type double.
*/
TEST_CASE("MOEADSchafferN1TestVectorDoubleBounds", "[MOEADTest]")
{
// This test can be a little flaky, so we try it a few times.
SchafferFunctionN1<arma::mat> SCH;
const arma::vec lowerBound = {-1000};
const arma::vec upperBound = {1000};
const double expectedLowerBound = 0.0;
const double expectedUpperBound = 2.0;
DefaultMOEAD opt(
300, // Population size.
300, // Max generations.
1.0, // Crossover probability.
0.9, // Probability of sampling from neighbor.
20, // Neighborhood size.
20, // Perturbation index.
0.5, // Differential weight.
2, // Max childrens to replace parents.
1E-10, // epsilon.
lowerBound, // Lower bound.
upperBound // Upper bound.
);
typedef decltype(SCH.objectiveA) ObjectiveTypeA;
typedef decltype(SCH.objectiveB) ObjectiveTypeB;
bool success = false;
for (size_t trial = 0; trial < 3; ++trial)
{
arma::mat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
opt.Optimize(objectives, coords);
arma::cube paretoSet = opt.ParetoSet();
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
double val = arma::as_scalar(paretoSet.slice(solutionIdx));
if (!IsInBounds<double>(val, expectedLowerBound, expectedUpperBound, 0.1))
{
allInRange = false;
break;
}
}
if (allInRange)
{
success = true;
break;
}
}
REQUIRE(success == true);
}
/**
* Optimize for the Fonseca Fleming function using NSGA-II optimizer.
* Tests for data of type double.
*/
TEST_CASE("MOEADFonsecaFlemingDoubleTest", "[MOEADTest]")
{
FonsecaFlemingFunction<arma::mat> FON;
const double lowerBound = -4;
const double upperBound = 4;
const double expectedLowerBound = -1.0 / sqrt(3);
const double expectedUpperBound = 1.0 / sqrt(3);
DefaultMOEAD opt(
300, // Max generations.
300, // Max generations.
1.0, // Crossover probability.
0.9, // Probability of sampling from neighbor.
20, // Neighborhood size.
20, // Perturbation index.
0.5, // Differential weight.
2, // Max childrens to replace parents.
1E-10, // epsilon.
lowerBound, // Lower bound.
upperBound // Upper bound.
);
typedef decltype(FON.objectiveA) ObjectiveTypeA;
typedef decltype(FON.objectiveB) ObjectiveTypeB;
arma::mat coords = FON.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = FON.GetObjectives();
opt.Optimize(objectives, coords);
arma::cube paretoSet = opt.ParetoSet();
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
const arma::mat solution = paretoSet.slice(solutionIdx);
double valX = arma::as_scalar(solution(0));
double valY = arma::as_scalar(solution(1));
double valZ = arma::as_scalar(solution(2));
if (!IsInBounds<double>(valX, expectedLowerBound, expectedUpperBound, 0.1) ||
!IsInBounds<double>(valY, expectedLowerBound, expectedUpperBound, 0.1) ||
!IsInBounds<double>(valZ, expectedLowerBound, expectedUpperBound, 0.1))
{
allInRange = false;
break;
}
}
REQUIRE(allInRange);
}
/**
* Optimize for the Fonseca Fleming function using NSGA-II optimizer.
* Tests for data of type double.
*/
TEST_CASE("MOEADFonsecaFlemingTestVectorDoubleBounds", "[MOEADTest]")
{
FonsecaFlemingFunction<arma::mat> FON;
const arma::vec lowerBound = {-4, -4, -4};
const arma::vec upperBound = {4, 4, 4};
const double expectedLowerBound = -1.0 / sqrt(3);
const double expectedUpperBound = 1.0 / sqrt(3);
DefaultMOEAD opt(
300, // Max generations.
300, // Max generations.
1.0, // Crossover probability.
0.9, // Probability of sampling from neighbor.
20, // Neighborhood size.
20, // Perturbation index.
0.5, // Differential weight.
2, // Max childrens to replace parents.
1E-10, // epsilon.
lowerBound, // Lower bound.
upperBound // Upper bound.
);
typedef decltype(FON.objectiveA) ObjectiveTypeA;
typedef decltype(FON.objectiveB) ObjectiveTypeB;
arma::mat coords = FON.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = FON.GetObjectives();
opt.Optimize(objectives, coords);
arma::cube paretoSet = opt.ParetoSet();
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
const arma::mat solution = paretoSet.slice(solutionIdx);
double valX = arma::as_scalar(solution(0));
double valY = arma::as_scalar(solution(1));
double valZ = arma::as_scalar(solution(2));
if (!IsInBounds<double>(valX, expectedLowerBound, expectedUpperBound, 0.1) ||
!IsInBounds<double>(valY, expectedLowerBound, expectedUpperBound, 0.1) ||
!IsInBounds<double>(valZ, expectedLowerBound, expectedUpperBound, 0.1))
{
allInRange = false;
break;
}
}
REQUIRE(allInRange);
}
/**
* Optimize for the Schaffer N.1 function using NSGA-II optimizer.
* Tests for data of type float.
*/
TEST_CASE("MOEADSchafferN1FloatTest", "[MOEADTest]")
{
SchafferFunctionN1<arma::fmat> SCH;
const double lowerBound = -1000;
const double upperBound = 1000;
const double expectedLowerBound = 0.0;
const double expectedUpperBound = 2.0;
DefaultMOEAD opt(
300, // Population size.
300, // Max generations.
1.0, // Crossover probability.
0.9, // Probability of sampling from neighbor.
20, // Neighborhood size.
20, // Perturbation index.
0.5, // Differential weight.
2, // Max childrens to replace parents.
1E-10, // epsilon.
lowerBound, // Lower bound.
upperBound // Upper bound.
);
typedef decltype(SCH.objectiveA) ObjectiveTypeA;
typedef decltype(SCH.objectiveB) ObjectiveTypeB;
// We allow a few trials in case of poor convergence.
bool success = false;
for (size_t trial = 0; trial < 3; ++trial)
{
arma::fmat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
opt.Optimize(objectives, coords);
arma::fcube paretoSet = arma::conv_to<arma::fcube>::from(opt.ParetoSet());
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
float val = arma::as_scalar(paretoSet.slice(solutionIdx));
if (!IsInBounds<float>(val, expectedLowerBound, expectedUpperBound, 0.1))
{
allInRange = false;
break;
}
}
if (allInRange)
{
success = true;
break;
}
}
REQUIRE(success == true);
}
/**
* Optimize for the Schaffer N.1 function using NSGA-II optimizer.
* Tests for data of type float.
*/
TEST_CASE("MOEADSchafferN1TestVectorFloatBounds", "[MOEADTest]")
{
// This test can be a little flaky, so we try it a few times.
SchafferFunctionN1<arma::fmat> SCH;
const arma::vec lowerBound = {-1000};
const arma::vec upperBound = {1000};
const double expectedLowerBound = 0.0;
const double expectedUpperBound = 2.0;
DefaultMOEAD opt(
300, // Population size.
300, // Max generations.
1.0, // Crossover probability.
0.9, // Probability of sampling from neighbor.
20, // Neighborhood size.
20, // Perturbation index.
0.5, // Differential weight.
2, // Max childrens to replace parents.
1E-10, // epsilon.
lowerBound, // Lower bound.
upperBound // Upper bound.
);
typedef decltype(SCH.objectiveA) ObjectiveTypeA;
typedef decltype(SCH.objectiveB) ObjectiveTypeB;
bool success = false;
for (size_t trial = 0; trial < 3; ++trial)
{
arma::fmat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
opt.Optimize(objectives, coords);
arma::fcube paretoSet = arma::conv_to<arma::fcube>::from(opt.ParetoSet());
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
float val = arma::as_scalar(paretoSet.slice(solutionIdx));
if (!IsInBounds<float>(val, expectedLowerBound, expectedUpperBound, 0.1))
{
allInRange = false;
break;
}
}
if (allInRange)
{
success = true;
break;
}
}
REQUIRE(success == true);
}
/**
* Optimize for the Fonseca Fleming function using NSGA-II optimizer.
* Tests for data of type float.
*/
TEST_CASE("MOEADFonsecaFlemingFloatTest", "[MOEADTest]")
{
FonsecaFlemingFunction<arma::fmat> FON;
const double lowerBound = -4;
const double upperBound = 4;
const float expectedLowerBound = -1.0 / sqrt(3);
const float expectedUpperBound = 1.0 / sqrt(3);
DefaultMOEAD opt(
300, // Max generations.
300, // Max generations.
1.0, // Crossover probability.
0.9, // Probability of sampling from neighbor.
20, // Neighborhood size.
20, // Perturbation index.
0.5, // Differential weight.
2, // Max childrens to replace parents.
1E-10, // epsilon.
lowerBound, // Lower bound.
upperBound // Upper bound.
);
typedef decltype(FON.objectiveA) ObjectiveTypeA;
typedef decltype(FON.objectiveB) ObjectiveTypeB;
arma::fmat coords = FON.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = FON.GetObjectives();
opt.Optimize(objectives, coords);
arma::fcube paretoSet = arma::conv_to<arma::fcube>::from(opt.ParetoSet());
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
const arma::fmat solution = paretoSet.slice(solutionIdx);
float valX = arma::as_scalar(solution(0));
float valY = arma::as_scalar(solution(1));
float valZ = arma::as_scalar(solution(2));
if (!IsInBounds<float>(valX, expectedLowerBound, expectedUpperBound, 0.1) ||
!IsInBounds<float>(valY, expectedLowerBound, expectedUpperBound, 0.1) ||
!IsInBounds<float>(valZ, expectedLowerBound, expectedUpperBound, 0.1))
{
allInRange = false;
break;
}
}
REQUIRE(allInRange);
}
/**
* Optimize for the Fonseca Fleming function using NSGA-II optimizer.
* Tests for data of type float.
*/
TEST_CASE("MOEADFonsecaFlemingTestVectorFloatBounds", "[MOEADTest]")
{
FonsecaFlemingFunction<arma::fmat> FON;
const arma::vec lowerBound = {-4, -4, -4};
const arma::vec upperBound = {4, 4, 4};
const float expectedLowerBound = -1.0 / sqrt(3);
const float expectedUpperBound = 1.0 / sqrt(3);
DefaultMOEAD opt(
300, // Max generations.
300, // Max generations.
1.0, // Crossover probability.
0.9, // Probability of sampling from neighbor.
20, // Neighborhood size.
20, // Perturbation index.
0.5, // Differential weight.
2, // Max childrens to replace parents.
1E-10, // epsilon.
lowerBound, // Lower bound.
upperBound // Upper bound.
);
typedef decltype(FON.objectiveA) ObjectiveTypeA;
typedef decltype(FON.objectiveB) ObjectiveTypeB;
arma::fmat coords = FON.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = FON.GetObjectives();
opt.Optimize(objectives, coords);
arma::fcube paretoSet = arma::conv_to<arma::fcube>::from(opt.ParetoSet());
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
const arma::fmat solution = paretoSet.slice(solutionIdx);
float valX = arma::as_scalar(solution(0));
float valY = arma::as_scalar(solution(1));
float valZ = arma::as_scalar(solution(2));
if (!IsInBounds<float>(valX, expectedLowerBound, expectedUpperBound, 0.1) ||
!IsInBounds<float>(valY, expectedLowerBound, expectedUpperBound, 0.1) ||
!IsInBounds<float>(valZ, expectedLowerBound, expectedUpperBound, 0.1))
{
allInRange = false;
break;
}
}
REQUIRE(allInRange);
}
/**
* Test against the first problem of ZDT Test Suite. ZDT-1 is a 30
* variable-2 objective problem with a convex Pareto Front.
*
* NOTE: For the sake of runtime, only ZDT-1 is tested against the
* algorithm. Others have been tested separately.
*
* We run the test multiple times, since it sometimes fails, in order to get the
* probability of failure down.
*/
TEST_CASE("MOEADZDTONETest", "[MOEADTest]")
{
//! Parameters taken from original ZDT Paper.
ZDT1<> ZDT_ONE(100);
const double lowerBound = 0;
const double upperBound = 1;
DefaultMOEAD opt(
300, // Population size.
150, // Max generations.
1.0, // Crossover probability.
0.9, // Probability of sampling from neighbor.
20, // Neighborhood size.
20, // Perturbation index.
0.5, // Differential weight.
2, // Max childrens to replace parents.
1E-10, // epsilon.
lowerBound, // Lower bound.
upperBound // Upper bound.
);
typedef decltype(ZDT_ONE.objectiveF1) ObjectiveTypeA;
typedef decltype(ZDT_ONE.objectiveF2) ObjectiveTypeB;
const size_t trials = 8;
for (size_t trial = 0; trial < trials; ++trial)
{
arma::mat coords = ZDT_ONE.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives =
ZDT_ONE.GetObjectives();
opt.Optimize(objectives, coords);
//! Refer the ZDT_ONE implementation for g objective implementation.
//! The optimal g value is taken from the docs of ZDT_ONE.
size_t numVariables = coords.size();
double sum = arma::accu(coords(arma::span(1, numVariables - 1), 0));
const double g = 1.0 + 9.0 * sum / (static_cast<double>(numVariables - 1));
if (trial < trials - 1 && g != Approx(1.0).margin(0.99))
continue;
REQUIRE(g == Approx(1.0).margin(0.99));
break;
}
}
/**
* Check if the final population lies in the optimal region in variable space.
*
* @param paretoSet The final population in variable space.
*/
bool VariableBoundsCheck(const arma::cube& paretoSet)
{
bool inBounds = true;
const arma::mat regions{
{0.0, 0.182228780, 0.4093136748,
0.6183967944, 0.8233317983},
{0.0830015349, 0.2577623634, 0.4538821041,
0.6525117038, 0.8518328654}
};
for (size_t pointIdx = 0; pointIdx < paretoSet.n_slices; ++pointIdx)
{
const arma::mat& point = paretoSet.slice(pointIdx);
const double firstVariable = point(0, 0);
const bool notInRegion0 = !IsInBounds<double>(firstVariable, regions(0, 0), regions(1, 0), 1e-2);
const bool notInRegion1 = !IsInBounds<double>(firstVariable, regions(0, 1), regions(1, 1), 1e-2);
const bool notInRegion2 = !IsInBounds<double>(firstVariable, regions(0, 2), regions(1, 2), 1e-2);
const bool notInRegion3 = !IsInBounds<double>(firstVariable, regions(0, 3), regions(1, 3), 1e-2);
const bool notInRegion4 = !IsInBounds<double>(firstVariable, regions(0, 4), regions(1, 4), 1e-2);
if (notInRegion0 && notInRegion1 && notInRegion2 && notInRegion3 && notInRegion4)
{
inBounds = false;
break;
}
}
return inBounds;
}
/**
* Test DirichletMOEAD against the third problem of ZDT Test Suite. ZDT-3 is a 30
* variable-2 objective problem with disconnected Pareto Fronts.
*/
TEST_CASE("MOEADDIRICHLETZDT3Test", "[MOEADTest]")
{
//! Parameters taken from original ZDT Paper.
ZDT3<> ZDT_THREE(300);
const double lowerBound = 0;
const double upperBound = 1;
DirichletMOEAD opt(
300, // Population size.
300, // Max generations.
1.0, // Crossover probability.
0.9, // Probability of sampling from neighbor.
20, // Neighborhood size.
20, // Perturbation index.
0.5, // Differential weight.
2, // Max childrens to replace parents.
1E-10, // epsilon.
lowerBound, // Lower bound.
upperBound // Upper bound.
);
typedef decltype(ZDT_THREE.objectiveF1) ObjectiveTypeA;
typedef decltype(ZDT_THREE.objectiveF2) ObjectiveTypeB;
arma::mat coords = ZDT_THREE.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = ZDT_THREE.GetObjectives();
opt.Optimize(objectives, coords);
const arma::cube& finalPopulation = opt.ParetoSet();
REQUIRE(VariableBoundsCheck(finalPopulation));
}
+304 -32
View File
@@ -1,6 +1,7 @@
/**
* @file nsga2_test.cpp
* @author Sayan Goswami
* @author Nanubala Gnana Sai
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
@@ -22,24 +23,30 @@ using namespace std;
* @param value The value being checked.
* @param low The lower bound.
* @param high The upper bound.
* @tparam The type of elements in the population set.
* @return true if value lies in the range [low, high].
* @return false if value does not lie in the range [low, high].
*/
bool IsInBounds(const double& value, const double& low, const double& high)
template<typename ElemType>
bool IsInBounds(const ElemType& value, const ElemType& low, const ElemType& high)
{
return !(value < low) && !(high < value);
ElemType roundoff = 0.1;
return !(value < (low - roundoff)) && !((high + roundoff) < value);
}
/**
* Optimize for the Schaffer N.1 function using NSGA-II optimizer.
* Tests for data of type double.
*/
TEST_CASE("NSGA2SchafferN1Test", "[NSGA2Test]")
TEST_CASE("NSGA2SchafferN1DoubleTest", "[NSGA2Test]")
{
SchafferFunctionN1<arma::mat> SCH;
const double lowerBound = -1000;
const double upperBound = 1000;
const double expectedLowerBound = 0.0;
const double expectedUpperBound = 2.0;
NSGA2 opt(20, 5000, 0.5, 0.5, 1e-3, 1e-6, lowerBound, upperBound);
NSGA2 opt(20, 300, 0.5, 0.5, 1e-3, 1e-6, lowerBound, upperBound);
typedef decltype(SCH.objectiveA) ObjectiveTypeA;
typedef decltype(SCH.objectiveB) ObjectiveTypeB;
@@ -52,15 +59,14 @@ TEST_CASE("NSGA2SchafferN1Test", "[NSGA2Test]")
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
opt.Optimize(objectives, coords);
std::vector<arma::mat> bestFront = opt.Front();
arma::cube paretoSet = opt.ParetoSet();
bool allInRange = true;
for (arma::mat solution: bestFront)
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
double val = arma::as_scalar(solution);
if (val < 0.0 || val > 2.0)
double val = arma::as_scalar(paretoSet.slice(solutionIdx));
if (!IsInBounds<double>(val, expectedLowerBound, expectedUpperBound))
{
allInRange = false;
break;
@@ -79,15 +85,18 @@ TEST_CASE("NSGA2SchafferN1Test", "[NSGA2Test]")
/**
* Optimize for the Schaffer N.1 function using NSGA-II optimizer.
* Tests for data of type double.
*/
TEST_CASE("NSGA2SchafferN1TestVectorBounds", "[NSGA2Test]")
TEST_CASE("NSGA2SchafferN1TestVectorDoubleBounds", "[NSGA2Test]")
{
// This test can be a little flaky, so we try it a few times.
SchafferFunctionN1<arma::mat> SCH;
const arma::vec lowerBound = {-1000};
const arma::vec upperBound = {1000};
const double expectedLowerBound = 0.0;
const double expectedUpperBound = 2.0;
NSGA2 opt(20, 5000, 0.5, 0.5, 1e-3, 1e-6, lowerBound, upperBound);
NSGA2 opt(20, 300, 0.5, 0.5, 1e-3, 1e-6, lowerBound, upperBound);
typedef decltype(SCH.objectiveA) ObjectiveTypeA;
typedef decltype(SCH.objectiveB) ObjectiveTypeB;
@@ -99,15 +108,14 @@ TEST_CASE("NSGA2SchafferN1TestVectorBounds", "[NSGA2Test]")
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
opt.Optimize(objectives, coords);
std::vector<arma::mat> bestFront = opt.Front();
arma::cube paretoSet = opt.ParetoSet();
bool allInRange = true;
for (arma::mat solution: bestFront)
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
double val = arma::as_scalar(solution);
if (val < 0.0 || val > 2.0)
double val = arma::as_scalar(paretoSet.slice(solutionIdx));
if (!IsInBounds<double>(val, expectedLowerBound, expectedUpperBound))
{
allInRange = false;
break;
@@ -126,8 +134,9 @@ TEST_CASE("NSGA2SchafferN1TestVectorBounds", "[NSGA2Test]")
/**
* Optimize for the Fonseca Fleming function using NSGA-II optimizer.
* Tests for data of type double.
*/
TEST_CASE("NSGA2FonsecaFlemingTest", "[NSGA2Test]")
TEST_CASE("NSGA2FonsecaFlemingDoubleTest", "[NSGA2Test]")
{
FonsecaFlemingFunction<arma::mat> FON;
const double lowerBound = -4;
@@ -137,7 +146,7 @@ TEST_CASE("NSGA2FonsecaFlemingTest", "[NSGA2Test]")
const double expectedLowerBound = -1.0 / sqrt(3);
const double expectedUpperBound = 1.0 / sqrt(3);
NSGA2 opt(20, 4000, 0.6, 0.3, strength, tolerance, lowerBound, upperBound);
NSGA2 opt(20, 300, 0.6, 0.3, strength, tolerance, lowerBound, upperBound);
typedef decltype(FON.objectiveA) ObjectiveTypeA;
typedef decltype(FON.objectiveB) ObjectiveTypeB;
@@ -146,32 +155,34 @@ TEST_CASE("NSGA2FonsecaFlemingTest", "[NSGA2Test]")
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = FON.GetObjectives();
opt.Optimize(objectives, coords);
std::vector<arma::mat> bestFront = opt.Front();
arma::cube paretoSet = opt.ParetoSet();
bool allInRange = true;
for (size_t i = 0; i < bestFront.size(); i++)
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
const arma::mat solution = bestFront[i];
const arma::mat solution = paretoSet.slice(solutionIdx);
double valX = arma::as_scalar(solution(0));
double valY = arma::as_scalar(solution(1));
double valZ = arma::as_scalar(solution(2));
if (!IsInBounds(valX, expectedLowerBound, expectedUpperBound) ||
!IsInBounds(valY, expectedLowerBound, expectedUpperBound) ||
!IsInBounds(valZ, expectedLowerBound, expectedUpperBound))
if (!IsInBounds<double>(valX, expectedLowerBound, expectedUpperBound) ||
!IsInBounds<double>(valY, expectedLowerBound, expectedUpperBound) ||
!IsInBounds<double>(valZ, expectedLowerBound, expectedUpperBound))
{
allInRange = false;
break;
}
}
REQUIRE(allInRange);
}
/**
* Optimize for the Fonseca Fleming function using NSGA-II optimizer.
* Tests for data of type double.
*/
TEST_CASE("NSGA2FonsecaFlemingTestVectorBounds", "[NSGA2Test]")
TEST_CASE("NSGA2FonsecaFlemingTestVectorDoubleBounds", "[NSGA2Test]")
{
FonsecaFlemingFunction<arma::mat> FON;
const arma::vec lowerBound = {-4, -4, -4};
@@ -181,7 +192,7 @@ TEST_CASE("NSGA2FonsecaFlemingTestVectorBounds", "[NSGA2Test]")
const double expectedLowerBound = -1.0 / sqrt(3);
const double expectedUpperBound = 1.0 / sqrt(3);
NSGA2 opt(20, 4000, 0.6, 0.3, strength, tolerance, lowerBound, upperBound);
NSGA2 opt(20, 300, 0.6, 0.3, strength, tolerance, lowerBound, upperBound);
typedef decltype(FON.objectiveA) ObjectiveTypeA;
typedef decltype(FON.objectiveB) ObjectiveTypeB;
@@ -190,24 +201,285 @@ TEST_CASE("NSGA2FonsecaFlemingTestVectorBounds", "[NSGA2Test]")
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = FON.GetObjectives();
opt.Optimize(objectives, coords);
std::vector<arma::mat> bestFront = opt.Front();
arma::cube paretoSet = opt.ParetoSet();
bool allInRange = true;
for (size_t i = 0; i < bestFront.size(); i++)
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
const arma::mat solution = bestFront[i];
const arma::mat solution = paretoSet.slice(solutionIdx);
double valX = arma::as_scalar(solution(0));
double valY = arma::as_scalar(solution(1));
double valZ = arma::as_scalar(solution(2));
if (!IsInBounds(valX, expectedLowerBound, expectedUpperBound) ||
!IsInBounds(valY, expectedLowerBound, expectedUpperBound) ||
!IsInBounds(valZ, expectedLowerBound, expectedUpperBound))
if (!IsInBounds<double>(valX, expectedLowerBound, expectedUpperBound) ||
!IsInBounds<double>(valY, expectedLowerBound, expectedUpperBound) ||
!IsInBounds<double>(valZ, expectedLowerBound, expectedUpperBound))
{
allInRange = false;
break;
}
}
REQUIRE(allInRange);
}
/**
* Optimize for the Schaffer N.1 function using NSGA-II optimizer.
* Tests for data of type float.
*/
TEST_CASE("NSGA2SchafferN1FloatTest", "[NSGA2Test]")
{
SchafferFunctionN1<arma::fmat> SCH;
const double lowerBound = -1000;
const double upperBound = 1000;
const double expectedLowerBound = 0.0;
const double expectedUpperBound = 2.0;
NSGA2 opt(20, 300, 0.5, 0.5, 1e-3, 1e-6, lowerBound, upperBound);
typedef decltype(SCH.objectiveA) ObjectiveTypeA;
typedef decltype(SCH.objectiveB) ObjectiveTypeB;
// We allow a few trials in case of poor convergence.
bool success = false;
for (size_t trial = 0; trial < 3; ++trial)
{
arma::fmat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
opt.Optimize(objectives, coords);
arma::fcube paretoSet = arma::conv_to<arma::fcube>::from(opt.ParetoSet());
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
float val = arma::as_scalar(paretoSet.slice(solutionIdx));
if (!IsInBounds<float>(val, expectedLowerBound, expectedUpperBound))
{
allInRange = false;
break;
}
}
if (allInRange)
{
success = true;
break;
}
}
REQUIRE(success == true);
}
/**
* Optimize for the Schaffer N.1 function using NSGA-II optimizer.
* Tests for data of type float.
*/
TEST_CASE("NSGA2SchafferN1TestVectorFloatBounds", "[NSGA2Test]")
{
// This test can be a little flaky, so we try it a few times.
SchafferFunctionN1<arma::fmat> SCH;
const arma::vec lowerBound = {-1000};
const arma::vec upperBound = {1000};
const double expectedLowerBound = 0.0;
const double expectedUpperBound = 2.0;
NSGA2 opt(20, 300, 0.5, 0.5, 1e-3, 1e-6, lowerBound, upperBound);
typedef decltype(SCH.objectiveA) ObjectiveTypeA;
typedef decltype(SCH.objectiveB) ObjectiveTypeB;
bool success = false;
for (size_t trial = 0; trial < 3; ++trial)
{
arma::fmat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
opt.Optimize(objectives, coords);
arma::fcube paretoSet = arma::conv_to<arma::fcube>::from(opt.ParetoSet());
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
float val = arma::as_scalar(paretoSet.slice(solutionIdx));
if (!IsInBounds<float>(val, expectedLowerBound, expectedUpperBound))
{
allInRange = false;
break;
}
}
if (allInRange)
{
success = true;
break;
}
}
REQUIRE(success == true);
}
/**
* Optimize for the Fonseca Fleming function using NSGA-II optimizer.
* Tests for data of type float.
*/
TEST_CASE("NSGA2FonsecaFlemingFloatTest", "[NSGA2Test]")
{
FonsecaFlemingFunction<arma::fmat> FON;
const double lowerBound = -4;
const double upperBound = 4;
const double tolerance = 1e-6;
const double strength = 1e-4;
const float expectedLowerBound = -1.0 / sqrt(3);
const float expectedUpperBound = 1.0 / sqrt(3);
NSGA2 opt(20, 300, 0.6, 0.3, strength, tolerance, lowerBound, upperBound);
typedef decltype(FON.objectiveA) ObjectiveTypeA;
typedef decltype(FON.objectiveB) ObjectiveTypeB;
arma::fmat coords = FON.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = FON.GetObjectives();
opt.Optimize(objectives, coords);
arma::fcube paretoSet = arma::conv_to<arma::fcube>::from(opt.ParetoSet());
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
const arma::fmat solution = paretoSet.slice(solutionIdx);
float valX = arma::as_scalar(solution(0));
float valY = arma::as_scalar(solution(1));
float valZ = arma::as_scalar(solution(2));
if (!IsInBounds<float>(valX, expectedLowerBound, expectedUpperBound) ||
!IsInBounds<float>(valY, expectedLowerBound, expectedUpperBound) ||
!IsInBounds<float>(valZ, expectedLowerBound, expectedUpperBound))
{
allInRange = false;
break;
}
}
REQUIRE(allInRange);
}
/**
* Optimize for the Fonseca Fleming function using NSGA-II optimizer.
* Tests for data of type float.
*/
TEST_CASE("NSGA2FonsecaFlemingTestVectorFloatBounds", "[NSGA2Test]")
{
FonsecaFlemingFunction<arma::fmat> FON;
const arma::vec lowerBound = {-4, -4, -4};
const arma::vec upperBound = {4, 4, 4};
const double tolerance = 1e-6;
const double strength = 1e-4;
const float expectedLowerBound = -1.0 / sqrt(3);
const float expectedUpperBound = 1.0 / sqrt(3);
NSGA2 opt(20, 300, 0.6, 0.3, strength, tolerance, lowerBound, upperBound);
typedef decltype(FON.objectiveA) ObjectiveTypeA;
typedef decltype(FON.objectiveB) ObjectiveTypeB;
arma::fmat coords = FON.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = FON.GetObjectives();
opt.Optimize(objectives, coords);
arma::fcube paretoSet = arma::conv_to<arma::fcube>::from(opt.ParetoSet());
bool allInRange = true;
for (size_t solutionIdx = 0; solutionIdx < paretoSet.n_slices; ++solutionIdx)
{
const arma::fmat solution = paretoSet.slice(solutionIdx);
float valX = arma::as_scalar(solution(0));
float valY = arma::as_scalar(solution(1));
float valZ = arma::as_scalar(solution(2));
if (!IsInBounds<float>(valX, expectedLowerBound, expectedUpperBound) ||
!IsInBounds<float>(valY, expectedLowerBound, expectedUpperBound) ||
!IsInBounds<float>(valZ, expectedLowerBound, expectedUpperBound))
{
allInRange = false;
break;
}
}
REQUIRE(allInRange);
}
/**
* Test against the first problem of ZDT Test Suite. ZDT-1 is a 30
* variable-2 objective problem with a convex Pareto Front.
*
* NOTE: For the sake of runtime, only ZDT-1 is tested against the
* algorithm. Others have been tested separately.
*/
TEST_CASE("NSGA2ZDTONETest", "[NSGA2Test]")
{
//! Parameters taken from original ZDT Paper.
ZDT1<> ZDT_ONE(100);
const double lowerBound = 0;
const double upperBound = 1;
const double tolerance = 1e-6;
const double mutationRate = 1e-2;
const double crossoverRate = 0.8;
const double strength = 1e-4;
NSGA2 opt(100, 250, crossoverRate, mutationRate, strength,
tolerance, lowerBound, upperBound);
typedef decltype(ZDT_ONE.objectiveF1) ObjectiveTypeA;
typedef decltype(ZDT_ONE.objectiveF2) ObjectiveTypeB;
arma::mat coords = ZDT_ONE.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = ZDT_ONE.GetObjectives();
opt.Optimize(objectives, coords);
//! Refer the ZDT_ONE implementation for g objective implementation.
//! The optimal g value is taken from the docs of ZDT_ONE.
size_t numVariables = coords.size();
double sum = arma::accu(coords(arma::span(1, numVariables - 1), 0));
double g = 1. + 9. * sum / (static_cast<double>(numVariables - 1));
REQUIRE(g == Approx(1.0).margin(0.99));
}
/**
* Ensure that the reverse-compatible Front() function works.
*
* This test can be removed when Front() is removed, in ensmallen 3.x.
*/
TEST_CASE("NSGA2FrontTest", "[NSGA2Test]")
{
SchafferFunctionN1<arma::mat> SCH;
const double lowerBound = -1000;
const double upperBound = 1000;
NSGA2 opt(20, 300, 0.5, 0.5, 1e-3, 1e-6, lowerBound, upperBound);
typedef decltype(SCH.objectiveA) ObjectiveTypeA;
typedef decltype(SCH.objectiveB) ObjectiveTypeB;
arma::mat coords = SCH.GetInitialPoint();
std::tuple<ObjectiveTypeA, ObjectiveTypeB> objectives = SCH.GetObjectives();
opt.Optimize(objectives, coords);
arma::cube paretoFront = opt.ParetoFront();
std::vector<arma::mat> rcFront = opt.Front();
REQUIRE(paretoFront.n_slices == rcFront.size());
for (size_t i = 0; i < paretoFront.n_slices; ++i)
{
arma::mat paretoM = paretoFront.slice(i);
CheckMatrices(paretoM, rcFront[i]);
}
}
+1 -1
View File
@@ -196,7 +196,7 @@ TEST_CASE("SoftmaxRegressionFunctionPartialGradientTest", "[SCDTest]")
// Create random class labels.
arma::Row<size_t> labels = arma::randi<arma::Row<size_t> >(
points, arma::distr_param(0, numClasses));
points, arma::distr_param(0, numClasses - 1));
// 2 objects for 2 terms in the cost function. Each term contributes towards
// the gradient and thus need to be checked independently.
+1
View File
@@ -70,6 +70,7 @@ TEST_CASE("GeneralizedRosenbrockTestFloat", "[SGDTest]")
REQUIRE(result == Approx(0.0).margin(1e-5));
for (size_t j = 0; j < i; ++j)
REQUIRE(coordinates(j) == Approx(1.0).epsilon(1e-3));
break;
}
}
}
+74
View File
@@ -0,0 +1,74 @@
/**
* @file yogi_test.cpp
* @author Marcus Edel
*
* ensmallen is free software; you may redistribute it and/or modify it under
* the terms of the 3-clause BSD license. You should have received a copy of
* the 3-clause BSD license along with ensmallen. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <ensmallen.hpp>
#include "catch.hpp"
#include "test_function_tools.hpp"
using namespace ens;
using namespace ens::test;
/**
* Test the Yogi optimizer on the Sphere function.
*/
TEST_CASE("YogiSphereFunctionTest", "[YogiTest]")
{
SphereFunction f(2);
Yogi optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false);
arma::mat coordinates = f.GetInitialPoint();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.1));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.1));
}
/**
* Test the Yogi optimizer on the Sphere function with arma::fmat.
*/
TEST_CASE("YogiSphereFunctionTestFMat", "[YogiTest]")
{
SphereFunction f(2);
Yogi optimizer(0.5, 2, 0.7, 0.999, 1e-8, 500000, 1e-3, false);
arma::fmat coordinates = f.GetInitialPoint<arma::fmat>();
optimizer.Optimize(f, coordinates);
REQUIRE(coordinates(0) == Approx(0.0).margin(0.1));
REQUIRE(coordinates(1) == Approx(0.0).margin(0.1));
}
/**
* Test the Yogi optimizer on the McCormick function.
*/
TEST_CASE("YogiMcCormickFunctionTest", "[YogiTest]")
{
Yogi optimizer(0.5, 1, 0.7, 0.999, 1e-8, 500000, 1e-5, false);
FunctionTest<McCormickFunction>(optimizer, 0.5, 0.1);
}
/**
* Run Yogi on logistic regression and make sure the results are acceptable.
*/
TEST_CASE("YogiLogisticRegressionTest", "[YogiTest]")
{
Yogi optimizer;
LogisticRegressionFunctionTest(optimizer, 0.003, 0.006);
}
/**
* Run Yogi on logistic regression and make sure the results are acceptable,
* using arma::fmat.
*/
TEST_CASE("YogiLogisticRegressionFMatTest", "[YogiTest]")
{
Yogi optimizer;
LogisticRegressionFunctionTest<arma::fmat>(optimizer, 0.003, 0.006);
}